1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-28 13:13:07 +01:00

1 Commits

Author SHA1 Message Date
c5e346f4eb First design experiments for barograph 2024-12-21 10:25:53 +01:00
173 changed files with 34944 additions and 20819 deletions

View File

@@ -68,12 +68,12 @@ Initial Flash
__Browser__
If you run a system with a modern Chrome or Edge Browser you can directly flash your device from within the browser.
Just go to the [Flash Page](https://wellenvogel.de/software/esp32/install.html) and select the "Initial" flash for your Hardware. This will install the most current software to your device. If you are using a forked project (like OBP60) refer to the documentation of the fork. You can just install any flash binary from your local computer with the browser based installation using the "upload" button.<br>
Just go to the [Flash Page](https://wellenvogel.github.io/esp32-nmea2000/install.html) and select the "Initial" flash for your Hardware. This will install the most current software to your device.
If you are on Windows you will need to have the correct driver installed before (see below at [windows users](#windows) - only install the driver, not the flashtool).
You can also install an update from the flash page but normally it is easier to do this from the Web Gui of the device (see [below](#update)).
The [Flash Page](https://wellenvogel.de/software/esp32/install.html) will also allow you to open a console window to your ESP32.
The [Flash Page](https://wellenvogel.github.io/esp32-nmea2000/install.html) will also allow you to open a console window to your ESP32.
__Tool based__
@@ -170,12 +170,6 @@ For details refer to the [example description](lib/exampletask/Readme.md).
Changelog
---------
[20250305](../../releases/tag/20250305)
*********
* better handling for reconnect to a raspberry pi after reset [#102](../../issues/102)
* introduce _custom_config_, _custom_js_, _custom_css_, refer to [extending the core](lib/exampletask/Readme.md) [#100](../../pull/100)
* create VWR [#103](../../issues/103)
[20241128](../../releases/tag/20241128)
*********
* additional correction for: USB connection on S3 stops [#81](../../issues/81)

View File

@@ -1,56 +0,0 @@
{
"build": {
"arduino":{
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_ESP32S3_DEV",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_CDC_ON_BOOT=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0x1A86",
"0x7523"
]
],
"mcu": "esp32s3",
"variant": "obp40s3"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": [
"esp-builtin"
],
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "OBP40 ESP32-S3-N8R8 (8 MB QD, 8 MB PSRAM)",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 460800
},
"url": "https://open-boat-projects.org/en/diy-multifunktionsdisplay-obp-60/",
"vendor": "Open Boat Projects"
}

Binary file not shown.

Binary file not shown.

View File

@@ -10,7 +10,7 @@ from datetime import datetime
import re
import pprint
from platformio.project.config import ProjectConfig
from platformio.project.exception import InvalidProjectConfError
Import("env")
#print(env.Dump())
@@ -104,17 +104,7 @@ def writeFileIfChanged(fileName,data):
return True
def mergeConfig(base,other):
try:
customconfig = env.GetProjectOption("custom_config")
except InvalidProjectConfError:
customconfig = None
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")
if os.path.exists(cname):
print("merge config %s"%cname)
@@ -284,9 +274,9 @@ class Grove:
def _ss(self,z=False):
if z:
return self.name
return self.name if self.name != 'Z' else ''
return self.name if self.name is not 'Z' else ''
def _suffix(self):
return '_'+self.name if self.name != 'Z' else ''
return '_'+self.name if self.name is not 'Z' else ''
def replace(self,line):
if line is None:
return line

View File

@@ -1,538 +0,0 @@
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
from platformio.project.exception import InvalidProjectConfError
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):
try:
customconfig = env.GetProjectOption("custom_config")
except InvalidProjectConfError:
customconfig = None
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")
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 != 'Z' else ''
def _suffix(self):
return '_'+self.name if self.name != '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"])))
epdtype = "unknown"
pcbvers = "unknown"
for x in env["BUILD_FLAGS"]:
if x.startswith("-D HARDWARE_"):
pcbvers = x.split('_')[1]
if x.startswith("-D DISPLAY_"):
epdtype = x.split('_')[1]
env.Append(
LINKFLAGS=[ "-u", "custom_app_desc" ],
CPPDEFINES=[(board,"1"), ("BOARD", env["BOARD"]), ("EPDTYPE", epdtype),
("PCBVERS", pcbvers)]
)
#script does not run on clean yet - maybe in the future
env.AddPostAction("clean",cleangenerated)

View File

@@ -1,518 +0,0 @@
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)

View File

@@ -493,11 +493,6 @@ double formatKnots(double cv)
return cv * 3600.0 / 1852.0;
}
double formatKmh(double cv)
{
return cv *3600.0 / 1000.0;
}
uint32_t mtr2nm(uint32_t m)
{
return m / 1852;
@@ -528,4 +523,4 @@ public:
};
static XWriter xwriter;
ARDUINOJSON_NAMESPACE::TextFormatter<XWriter> testWriter(xwriter);
#endif
#endif

View File

@@ -129,7 +129,6 @@ double formatCourse(double cv);
double formatDegToRad(double deg);
double formatWind(double cv);
double formatKnots(double cv);
double formatKmh(double cv);
uint32_t mtr2nm(uint32_t m);
double mtr2nm(double m);
@@ -252,4 +251,4 @@ class GwBoatData{
};
#endif
#endif

View File

@@ -27,19 +27,18 @@ class DummyConfig : public GwConfigInterface{
};
DummyConfig dummyConfig;
void GwConfigHandler::logConfig(int level) const
{
if (!logger->isActive(level))
return;
for (int i = 0; i < getNumConfig(); i++)
{
String v=configs[i]->asString();
bool isChanged=v != configs[i]->getDefault();
logger->logDebug(level, "Config[%s]%s='%s'", configs[i]->getName().c_str(),isChanged?"*":"", configs[i]->isSecret() ? "***" : configs[i]->asString().c_str());
if ((i%20) == 19) logger->flush();
String GwConfigHandler::toString() const{
String rt;
rt+="Config: ";
for (int i=0;i<getNumConfig();i++){
rt+=configs[i]->getName();
rt+="=";
rt+=configs[i]->asString();
rt+=", ";
}
return rt;
}
logger->flush();
}
String GwConfigHandler::toJson() const{
String rt;
int num=getNumConfig();
@@ -81,9 +80,6 @@ GwConfigHandler::~GwConfigHandler(){
bool GwConfigHandler::loadConfig(){
prefs->begin(PREF_NAME,true);
for (int i=0;i<getNumConfig();i++){
if (!prefs->isKey(configs[i]->getName().c_str())) {
continue;
}
String v=prefs->getString(configs[i]->getName().c_str(),configs[i]->getDefault());
configs[i]->value=v;
}

View File

@@ -22,7 +22,7 @@ class GwConfigHandler: public GwConfigDefinitions{
void stopChanges();
bool updateValue(String name, String value);
bool reset();
void logConfig(int level) const;
String toString() const;
String toJson() const;
String getString(const String name,const String defaultv="") const;
bool getBool(const String name,bool defaultv=false) const ;

View File

@@ -14,7 +14,7 @@ Files
* [platformio.ini](platformio.ini)<br>
This file is completely optional.
You only need this if you want to
extend the base configuration - we add a dummy library here and define additional build environments (boards)
extend the base configuration - we add a dummy library here and define one additional build 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.<br>
This registration can be done statically using [DECLARE_USERTASK](https://github.com/wellenvogel/esp32-nmea2000/blob/9b955d135d74937a60f2926e8bfb9395585ff8cd/lib/api/GwApi.h#L202) in the header file. <br>
As an alternative we just only register an [initialization function](https://github.com/wellenvogel/esp32-nmea2000/blob/9b955d135d74937a60f2926e8bfb9395585ff8cd/lib/exampletask/GwExampleTask.h#L19) using DECLARE_INITFUNCTION and later on register the task function itself via the [API](https://github.com/wellenvogel/esp32-nmea2000/blob/9b955d135d74937a60f2926e8bfb9395585ff8cd/lib/exampletask/GwExampleTask.cpp#L32).<br>
@@ -28,13 +28,11 @@ Files
* [GwExampleTaks.cpp](GwExampleTask.cpp) includes the implementation of our task. This tasks runs in an own thread - see the comments in the code.
We can have as many cpp (and header files) as we need to structure our code.
* [config.json](exampleConfig.json)<br>
* [config.json](config.json)<br>
This file allows to add some config definitions that are needed for our task. For the possible options have a look at the global [config.json](../../web/config.json). Be careful not to overwrite config defitions from the global file. A good practice wood be to prefix the names of definitions with parts of the library name. Always put them in a separate category so that they do not interfere with the system ones.
The defined config items can later be accessed in the code (see the example in [GwExampleTask.cpp](GwExampleTask.cpp)).<br>
Starting from Version 20250305 you should normally not use this file name any more as those configs would be added for all build environments. Instead define a parameter _custom_config_ in your [platformio.ini](platformio.ini) for the environments you would like to add some configurations for. This parameter accepts a list of file names (relative to the project root, separated by ,).
The defined config items can later be accessed in the code (see the example in [GwExampleTask.cpp](GwExampleTask.cpp)).
* [index.js](example.js)<br>
* [index.js](index.js)<br>
You can add javascript code that will contribute to the UI of the system. The WebUI provides a small API that allows you to "hook" into some functions to include your own parts of the UI. This includes adding new tabs, modifying/replacing the data display items, modifying the status display or accessing the config items.
For the API refer to [../../web/index.js](../../web/index.js#L2001).
To start interacting just register for some events like api.EVENTS.init. You can check the capabilities you have defined to see if your task is active.
@@ -48,14 +46,10 @@ Files
tools/testServer.py nnn http://x.x.x.x/api
```
with nnn being the local port and x.x.x.x the address of a running system. Open `http://localhost:nnn` in your browser.<br>
After a change just start the compilation and reload the page.<br>
Starting from Version 20250305 you should normally not use this file name any more as those js code would be added for all build environments. Instead define a parameter _custom_js_ in your [platformio.ini](platformio.ini) for the environments you would like to add the js code for. This parameter accepts a list of file names (relative to the project root, separated by ,). This will also allow you to skip the check for capabilities in your code.
After a change just start the compilation and reload the page.
* [index.css](index.css)<br>
You can add own css to influence the styling of the display.<br>
Starting from Version 20250305 you should normally not use this file name any more as those styles would be added for all build environments. Instead define a parameter _custom_css_ in your [platformio.ini](platformio.ini) for the environments you would like to add some styles for. This parameter accepts a list of file names (relative to the project root, separated by , or as multi line entry)
You can add own css to influence the styling of the display.
Interfaces

View File

@@ -10,9 +10,5 @@ lib_deps =
build_flags=
-D BOARD_TEST
${env.build_flags}
custom_config=
lib/exampletask/exampleConfig.json
custom_js=lib/exampletask/example.js
custom_css=lib/exampletask/example.css
upload_port = /dev/esp32
upload_protocol = esptool

View File

@@ -85,7 +85,6 @@ bool GwWifi::connectInternal(){
if (wifiClient->asBoolean()){
clientIsConnected=false;
LOG_DEBUG(GwLog::LOG,"creating wifiClient ssid=%s",wifiSSID->asString().c_str());
WiFi.setAutoReconnect(false); //#102
wl_status_t rt=WiFi.begin(wifiSSID->asCString(),wifiPass->asCString());
LOG_DEBUG(GwLog::LOG,"wifiClient connect returns %d",(int)rt);
lastConnectStart=millis();
@@ -93,8 +92,7 @@ bool GwWifi::connectInternal(){
}
return false;
}
//#102: we should have a wifi connect retry being > 30s - with some headroom
#define RETRY_MILLIS 40000
#define RETRY_MILLIS 20000
void GwWifi::loop(){
if (wifiClient->asBoolean())
{

View File

@@ -351,8 +351,8 @@ private:
rmb.vmg
);
send(n2kMsg,msg.sourceId);
SetN2kRouteWPInfo(n2kMsg,sourceId,1,1,N2kdir_forward,"default");
AppendN2kRouteWPInfo(n2kMsg,destinationId,rmb.destID,rmb.latitude,rmb.longitude);
SetN2kPGN129285(n2kMsg,sourceId,1,1,true,true,"default");
AppendN2kPGN129285(n2kMsg,destinationId,rmb.destID,rmb.latitude,rmb.longitude);
send(n2kMsg,msg.sourceId);
}
}
@@ -638,8 +638,8 @@ private:
for (int i=0;i< 3;i++){
if (msg.FieldLen(0)>0){
Depth=atof(msg.Field(0));
char du=msg.Field(i+1)[0];
switch(du){
char dt=msg.Field(i+1)[0];
switch(dt){
case 'f':
Depth=Depth/mToFeet;
break;
@@ -662,9 +662,8 @@ private:
//we can only send if we have a valid depth beloww tranducer
//to compute the offset
if (! boatData->DBT->isValid()) return;
double dbt=boatData->DBT->getData();
double offset=Depth-dbt;
if (offset >= 0 && dt == DBK){
double offset=Depth-boatData->DBT->getData();
if (offset >= 0 && dt == DBT){
logger->logDebug(GwLog::DEBUG, "strange DBK - more depth then transducer %s", msg.line);
return;
}
@@ -676,8 +675,8 @@ private:
if (! boatData->DBS->update(Depth,msg.sourceId)) return;
}
tN2kMsg n2kMsg;
SetN2kWaterDepth(n2kMsg,1,dbt,offset); //on the N2K side we always have depth below transducer
send(n2kMsg,msg.sourceId,(n2kMsg.PGN)+String((offset >=0)?1:0));
SetN2kWaterDepth(n2kMsg,1,Depth,offset);
send(n2kMsg,msg.sourceId,(n2kMsg.PGN)+String((offset != N2kDoubleNA)?1:0));
}
}
}

View File

@@ -267,29 +267,21 @@ private:
double DepthBelowTransducer;
double Offset;
double Range;
double WaterDepth;
if (ParseN2kWaterDepth(N2kMsg, SID, DepthBelowTransducer, Offset, Range))
{
if (updateDouble(boatData->DBT, DepthBelowTransducer))
WaterDepth = DepthBelowTransducer + Offset;
updateDouble(boatData->DBS, WaterDepth);
updateDouble(boatData->DBT,DepthBelowTransducer);
tNMEA0183Msg NMEA0183Msg;
if (NMEA0183SetDPT(NMEA0183Msg, DepthBelowTransducer, Offset,talkerId))
{
tNMEA0183Msg NMEA0183Msg;
bool offsetValid=true;
if (N2kIsNA(Offset)) {
Offset=NMEA0183DoubleNA;
offsetValid=false;
}
if (NMEA0183SetDPT(NMEA0183Msg, DepthBelowTransducer, Offset, talkerId))
{
SendMessage(NMEA0183Msg);
}
if (offsetValid)
{
double WaterDepth = DepthBelowTransducer + Offset;
updateDouble(boatData->DBS, WaterDepth);
}
if (NMEA0183SetDBx(NMEA0183Msg, DepthBelowTransducer, Offset, talkerId))
{
SendMessage(NMEA0183Msg);
}
SendMessage(NMEA0183Msg);
}
if (NMEA0183SetDBx(NMEA0183Msg, DepthBelowTransducer, Offset,talkerId))
{
SendMessage(NMEA0183Msg);
}
}
}
@@ -536,31 +528,6 @@ private:
{
SendMessage(NMEA0183Msg);
}
if (shouldSend && NMEA0183Reference == NMEA0183Wind_Apparent)
{
double wa = formatCourse(WindAngle);
if (!NMEA0183Msg.Init("VWR", talkerId))
return;
if (!NMEA0183Msg.AddDoubleField(( wa > 180 ) ? 360-wa : wa))
return;
if (!NMEA0183Msg.AddStrField(( wa >= 0 && wa <= 180) ? 'R' : 'L'))
return;
if (!NMEA0183Msg.AddDoubleField(formatKnots(WindSpeed)))
return;
if (!NMEA0183Msg.AddStrField("N"))
return;
if (!NMEA0183Msg.AddDoubleField(WindSpeed))
return;
if (!NMEA0183Msg.AddStrField("M"))
return;
if (!NMEA0183Msg.AddDoubleField(formatKmh(WindSpeed)))
return;
if (!NMEA0183Msg.AddStrField("K"))
return;
SendMessage(NMEA0183Msg);
}
}
/* if (WindReference == N2kWind_Apparent && boatData->SOG->isValid())

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
/****************************************************
AMS 5600 class for Arduino platform

View File

@@ -1,192 +0,0 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "BoatDataCalibration.h"
#include <cmath>
#include <math.h>
#include <unordered_map>
CalibrationDataList calibrationData;
std::unordered_map<std::string, TypeCalibData> CalibrationDataList::calibMap; // list of calibration data instances
void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
// Initial load of calibration data into internal list
// This method is called once at init phase of <obp60task> to read the configuration values
{
std::string instance;
double offset;
double slope;
double smooth;
String calInstance = "";
String calOffset = "";
String calSlope = "";
String calSmooth = "";
// Load user format configuration values
String lengthFormat = config->getString(config->lengthFormat); // [m|ft]
String distanceFormat = config->getString(config->distanceFormat); // [m|km|nm]
String speedFormat = config->getString(config->speedFormat); // [m/s|km/h|kn]
String windspeedFormat = config->getString(config->windspeedFormat); // [m/s|km/h|kn|bft]
String tempFormat = config->getString(config->tempFormat); // [K|C|F]
// Read calibration settings for data instances
for (int i = 0; i < MAX_CALIBRATION_DATA; i++) {
calInstance = "calInstance" + String(i + 1);
calOffset = "calOffset" + String(i + 1);
calSlope = "calSlope" + String(i + 1);
calSmooth = "calSmooth" + String(i + 1);
instance = std::string(config->getString(calInstance, "---").c_str());
if (instance == "---") {
LOG_DEBUG(GwLog::LOG, "no calibration data for instance no. %d", i + 1);
continue;
}
calibMap[instance] = { 0.0f, 1.0f, 1.0f, 0.0f, false };
offset = (config->getString(calOffset, "")).toFloat();
slope = (config->getString(calSlope, "")).toFloat();
smooth = (config->getString(calSmooth, "")).toInt(); // user input is int; further math is done with double
// Convert calibration values to internal standard formats
if (instance == "AWS" || instance == "TWS") {
if (windspeedFormat == "m/s") {
// No conversion needed
} else if (windspeedFormat == "km/h") {
offset /= 3.6; // Convert km/h to m/s
} else if (windspeedFormat == "kn") {
offset /= 1.94384; // Convert kn to m/s
} else if (windspeedFormat == "bft") {
offset *= 2 + (offset / 2); // Convert Bft to m/s (approx) -> to be improved
}
} else if (instance == "AWA" || instance == "COG" || instance == "TWA" || instance == "TWD" || instance == "HDM" || instance == "PRPOS" || instance == "RPOS") {
offset *= M_PI / 180; // Convert deg to rad
} else if (instance == "DBT") {
if (lengthFormat == "m") {
// No conversion needed
} else if (lengthFormat == "ft") {
offset /= 3.28084; // Convert ft to m
}
} else if (instance == "SOG" || instance == "STW") {
if (speedFormat == "m/s") {
// No conversion needed
} else if (speedFormat == "km/h") {
offset /= 3.6; // Convert km/h to m/s
} else if (speedFormat == "kn") {
offset /= 1.94384; // Convert kn to m/s
}
} else if (instance == "WTemp") {
if (tempFormat == "K" || tempFormat == "C") {
// No conversion needed
} else if (tempFormat == "F") {
offset *= 9.0 / 5.0; // Convert °F to K
slope *= 9.0 / 5.0; // Convert °F to K
}
}
// transform smoothing factor from {0.01..10} to {0.3..0.95} and invert for exponential smoothing formula
if (smooth <= 0) {
smooth = 0;
} else {
if (smooth > 10) {
smooth = 10;
}
smooth = 0.3 + ((smooth - 0.01) * (0.95 - 0.3) / (10 - 0.01));
}
smooth = 1 - smooth;
calibMap[instance].offset = offset;
calibMap[instance].slope = slope;
calibMap[instance].smooth = smooth;
calibMap[instance].isCalibrated = false;
LOG_DEBUG(GwLog::LOG, "stored calibration data: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(),
calibMap[instance].offset, calibMap[instance].slope, calibMap[instance].smooth);
}
LOG_DEBUG(GwLog::LOG, "all calibration data read");
}
void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger)
// Method to calibrate the boat data value
{
std::string instance = boatDataValue->getName().c_str();
double offset = 0;
double slope = 1.0;
double dataValue = 0;
std::string format = "";
if (calibMap.find(instance) == calibMap.end()) {
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not found in calibration data list", instance.c_str());
return;
} else if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data
calibMap[instance].isCalibrated = false;
return;
} else {
offset = calibMap[instance].offset;
slope = calibMap[instance].slope;
dataValue = boatDataValue->value;
format = boatDataValue->getFormat().c_str();
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: value: %f, format: %s", instance.c_str(), dataValue, format.c_str());
if (format == "formatWind") { // instance is of type angle
dataValue = (dataValue * slope) + offset;
dataValue = fmod(dataValue, 2 * M_PI);
if (dataValue > (M_PI)) {
dataValue -= (2 * M_PI);
} else if (dataValue < (M_PI * -1)) {
dataValue += (2 * M_PI);
}
} else if (format == "formatCourse") { // instance is of type direction
dataValue = (dataValue * slope) + offset;
dataValue = fmod(dataValue, 2 * M_PI);
if (dataValue < 0) {
dataValue += (2 * M_PI);
}
} else if (format == "kelvinToC") { // instance is of type temperature
dataValue = ((dataValue - 273.15) * slope) + offset + 273.15;
} else {
dataValue = (dataValue * slope) + offset;
}
calibMap[instance].isCalibrated = true;
boatDataValue->value = dataValue;
calibrationData.smoothInstance(boatDataValue, logger); // smooth the boat data value
calibMap[instance].value = boatDataValue->value; // store the calibrated + smoothed value in the list
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Offset: %f, Slope: %f, Result: %f", instance.c_str(), offset, slope, calibMap[instance].value);
}
}
void CalibrationDataList::smoothInstance(GwApi::BoatValue* boatDataValue, GwLog* logger)
// Method to smoothen the boat data value
{
static std::unordered_map<std::string, double> lastValue; // array for last values of smoothed boat data values
std::string instance = boatDataValue->getName().c_str();
double oldValue = 0;
double dataValue = boatDataValue->value;
double smoothFactor = 0;
if (!boatDataValue->valid) { // no valid boat data value, so we don't want to smoothen value
return;
} else if (calibMap.find(instance) == calibMap.end()) {
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: smooth factor for %s not found in calibration data list", instance.c_str());
return;
} else {
smoothFactor = calibMap[instance].smooth;
if (lastValue.find(instance) != lastValue.end()) {
oldValue = lastValue[instance];
dataValue = oldValue + (smoothFactor * (dataValue - oldValue)); // exponential smoothing algorithm
}
lastValue[instance] = dataValue; // store the new value for next cycle; first time, store only the current value and return
boatDataValue->value = dataValue; // set the smoothed value to the boat data value
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Smoothing factor: %f, Smoothed value: %f", instance.c_str(), smoothFactor, dataValue);
}
}
#endif

View File

@@ -1,33 +0,0 @@
// Functions lib for data instance calibration
#ifndef _BOATDATACALIBRATION_H
#define _BOATDATACALIBRATION_H
#include "Pagedata.h"
#include <string>
#include <unordered_map>
#define MAX_CALIBRATION_DATA 3 // maximum number of calibration data instances
typedef struct {
double offset; // calibration offset
double slope; // calibration slope
double smooth; // smoothing factor
double value; // calibrated data value
bool isCalibrated; // is data instance value calibrated?
} TypeCalibData;
class CalibrationDataList {
public:
static std::unordered_map<std::string, TypeCalibData> calibMap; // list of calibration data instances
void readConfig(GwConfigHandler* config, GwLog* logger);
void calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger);
void smoothInstance(GwApi::BoatValue* boatDataValue, GwLog* logger);
private:
};
extern CalibrationDataList calibrationData; // this list holds all calibration data
#endif

View File

@@ -2,5 +2,5 @@ Craete new page for OBP60
1. Create page under /lib/obp60task/PageXXXX.cpp
2. Set page name in PageXXXX.cpp on file name
3. Register new page in /lib/obp60task/obp60task.cpp line 242 (registerAllPages)
4. Add new page in /lib/obp60task/config.json for each page type or add new page to gen_set.py and run it to auto-generate the relevant section of config.json
4. Add new page in /lib/obp60task/config.json for each page type or add new page to gen_set.pl and run it to auto-generate the relevant section of config.json

View File

@@ -4,6 +4,7 @@
#include "GwApi.h"
#include "OBP60Hardware.h"
class Color{
public:
uint8_t r;
@@ -32,7 +33,6 @@ static Color COLOR_BLACK=Color(0,0,0);
Color setBrightness(const Color &color,uint8_t brightness);
enum BacklightMode {OFF, ON, SUN, BUS, TIME, KEY};
class LedInterface {
private:
@@ -92,4 +92,5 @@ class LedTaskData{
//task function
void createSpiLedTask(LedTaskData *param);
#endif
#endif

View File

@@ -1,6 +1,9 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include <Arduino.h>
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include <PCF8574.h> // Driver for PCF8574 output modul from Horter
#include <Wire.h> // I2C
#include <RTClib.h> // Driver for DS1388 RTC
@@ -8,22 +11,19 @@
#include "Pagedata.h"
#include "OBP60Hardware.h"
#include "OBP60Extensions.h"
#include "imglib.h"
// Character sets
#include "fonts/DSEG7Classic-BoldItalic16pt7b.h"
#include "fonts/DSEG7Classic-BoldItalic20pt7b.h"
#include "fonts/DSEG7Classic-BoldItalic26pt7b.h"
#include "fonts/DSEG7Classic-BoldItalic30pt7b.h"
#include "fonts/DSEG7Classic-BoldItalic42pt7b.h"
#include "fonts/DSEG7Classic-BoldItalic60pt7b.h"
#include "fonts/Ubuntu_Bold8pt8b.h"
#include "fonts/Ubuntu_Bold10pt8b.h"
#include "fonts/Ubuntu_Bold12pt8b.h"
#include "fonts/Ubuntu_Bold16pt8b.h"
#include "fonts/Ubuntu_Bold20pt8b.h"
#include "fonts/Ubuntu_Bold32pt8b.h"
#include "fonts/Atari16px8b.h" // Key label font
#include "Ubuntu_Bold8pt7b.h"
#include "Ubuntu_Bold10pt7b.h"
#include "Ubuntu_Bold12pt7b.h"
#include "Ubuntu_Bold16pt7b.h"
#include "Ubuntu_Bold20pt7b.h"
#include "Ubuntu_Bold32pt7b.h"
#include "DSEG7Classic-BoldItalic16pt7b.h"
#include "DSEG7Classic-BoldItalic20pt7b.h"
#include "DSEG7Classic-BoldItalic30pt7b.h"
#include "DSEG7Classic-BoldItalic42pt7b.h"
#include "DSEG7Classic-BoldItalic60pt7b.h"
// E-Ink Display
#define GxEPD_WIDTH 400 // Display width
@@ -60,10 +60,6 @@ GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(){r
// Horter I2C moduls
PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter
// FRAM
Adafruit_FRAM_I2C fram;
bool hasFRAM = false;
// Global vars
bool blinkingLED = false; // Enable / disable blinking flash LED
bool statusLED = false; // Actual status of flash LED on/off
@@ -71,12 +67,9 @@ bool statusBacklightLED = false;// Actual status of flash LED on/off
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;
void hardwareInit(GwApi *api)
void hardwareInit()
{
Wire.begin();
// Init PCF8574 digital outputs
@@ -84,27 +77,12 @@ void hardwareInit(GwApi *api)
if(pcf8574_Out.begin()){ // Initialize PCF8574
pcf8574_Out.write8(255); // Clear all outputs
}
fram = Adafruit_FRAM_I2C();
if (esp_reset_reason() == ESP_RST_POWERON) {
// help initialize FRAM
api->getLogger()->logDebug(GwLog::LOG,"Delaying I2C init for 250ms due to cold boot");
delay(250);
}
// FRAM (e.g. MB85RC256V)
if (fram.begin(FRAM_I2C_ADDR)) {
hasFRAM = true;
uint16_t manufacturerID;
uint16_t productID;
fram.getDeviceID(&manufacturerID, &productID);
// Boot counter
uint8_t framcounter = fram.read(0x0000);
fram.write(0x0000, framcounter+1);
api->getLogger()->logDebug(GwLog::LOG,"FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter);
}
else {
hasFRAM = false;
api->getLogger()->logDebug(GwLog::LOG,"NO FRAM detected");
}
}
void startLedTask(GwApi *api){
ledTaskData=new LedTaskData(api);
createSpiLedTask(ledTaskData);
}
void setPortPin(uint pin, bool value){
@@ -117,66 +95,6 @@ void togglePortPin(uint pin){
digitalWrite(pin, !digitalRead(pin));
}
void startLedTask(GwApi *api){
ledTaskData=new LedTaskData(api);
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_Bold20pt8b);
getdisplay().setCursor(85, 150);
getdisplay().print("Sleep Mode");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
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_Bold20pt8b);
getdisplay().setCursor(85, 150);
getdisplay().print("Sleep Mode");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
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
Color colorMapping(const String &colorString){
Color color = COLOR_RED;
@@ -190,21 +108,6 @@ Color colorMapping(const String &colorString){
return color;
}
BacklightMode backlightMapping(const String &backlightString) {
static std::map<String, BacklightMode> const table = {
{"Off", BacklightMode::OFF},
{"Control by Bus", BacklightMode::BUS},
{"Control by Time", BacklightMode::TIME},
{"Control by Key", BacklightMode::KEY},
{"On", BacklightMode::ON},
};
auto it = table.find(backlightString);
if (it != table.end()) {
return it->second;
}
return BacklightMode::OFF;
}
// All defined colors see pixeltypes.h in FastLED lib
void setBacklightLED(uint brightness, const Color &color){
if (ledTaskData == nullptr) return;
@@ -276,30 +179,6 @@ String xdrDelete(String input){
return input;
}
Point rotatePoint(const Point& origin, const Point& p, double angle) {
// rotate poind around origin by degrees
Point rotated;
double phi = angle * M_PI / 180.0;
double dx = p.x - origin.x;
double dy = p.y - origin.y;
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
return rotated;
}
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
std::vector<Point> rotatedPoints;
for (const auto& p : pts) {
rotatedPoints.push_back(rotatePoint(origin, p, angle));
}
return rotatedPoints;
}
void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
}
// Draw centered text
void drawTextCenter(int16_t cx, int16_t cy, String text) {
int16_t x1, y1;
@@ -342,12 +221,20 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
static unsigned long tcpClTxOld = 0;
static unsigned long n2kRxOld = 0;
static unsigned long n2kTxOld = 0;
int textcolor = GxEPD_BLACK;
if(commonData.config->getBool(commonData.config->statusLine) == true){
if(commonData.config->getString(commonData.config->displaycolor) == "Normal"){
textcolor = GxEPD_BLACK;
}
else{
textcolor = GxEPD_WHITE;
}
// Show status info
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(0, 15);
if(commonData.status.wifiApOn){
getdisplay().print(" AP ");
@@ -381,172 +268,52 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
usbRxOld = commonData.status.usbRx;
usbTxOld = commonData.status.usbTx;
#ifdef HARDWARE_V21
// Display key lock status
if (commonData.keylock) {
getdisplay().drawXBitmap(170, 1, lock_bits, icon_width, icon_height, commonData.fgcolor);
} else {
getdisplay().drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor);
// Heartbeat as dot
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(205, 14);
if(heartbeat == true){
getdisplay().print(".");
}
#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
else{
getdisplay().print(" ");
}
#endif // LIPO_ACCU_1200
// Heartbeat as page number
if (heartbeat) {
getdisplay().setTextColor(commonData.bgcolor);
getdisplay().fillRect(201, 0, 23, 19, commonData.fgcolor);
} else {
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().drawRect(201, 0, 23, 19, commonData.fgcolor);
}
getdisplay().setFont(&Ubuntu_Bold8pt8b);
drawTextCenter(211, 9, String(commonData.data.actpage));
heartbeat = !heartbeat;
heartbeat = !heartbeat;
// Date and time
String fmttype = commonData.config->getString(commonData.config->dateFormat);
String timesource = commonData.config->getString(commonData.config->timeSource);
double tz = commonData.config->getString(commonData.config->timeZone).toDouble();
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(230, 15);
if (timesource == "RTC" or timesource == "iRTC") {
// TODO take DST into account
if (commonData.data.rtcValid) {
time_t tv = mktime(&commonData.data.rtcTime) + (int)(tz * 3600);
struct tm *local_tm = localtime(&tv);
getdisplay().print(formatTime('m', local_tm->tm_hour, local_tm->tm_min, 0));
getdisplay().print(" ");
getdisplay().print(formatDate(fmttype, local_tm->tm_year + 1900, local_tm->tm_mon + 1, local_tm->tm_mday));
getdisplay().print(" ");
getdisplay().print(tz == 0 ? "UTC" : "LOT");
} else {
drawTextRalign(396, 15, "RTC invalid");
}
}
else if (timesource == "GPS") {
// Show date and time if date present
if(date->valid == true){
String acttime = formatValue(time, commonData).svalue;
acttime = acttime.substring(0, 5);
String actdate = formatValue(date, commonData).svalue;
getdisplay().print(acttime);
getdisplay().print(" ");
getdisplay().print(actdate);
getdisplay().print(" ");
getdisplay().print(tz == 0 ? "UTC" : "LOT");
// Show date and time if date present
if(date->valid == true){
String acttime = formatValue(time, commonData).svalue;
acttime = acttime.substring(0, 5);
String actdate = formatValue(date, commonData).svalue;
getdisplay().print(acttime);
getdisplay().print(" ");
getdisplay().print(actdate);
getdisplay().print(" ");
if(commonData.config->getInt(commonData.config->timeZone) == 0){
getdisplay().print("UTC");
}
else{
if(commonData.config->getBool(commonData.config->useSimuData) == true){
getdisplay().print("12:00 01.01.2024 LOT");
}
else{
drawTextRalign(396, 15, "No GPS data");
}
}
} // timesource == "GPS"
else {
getdisplay().print("No time source");
}
}
}
void displayFooter(CommonData &commonData) {
getdisplay().setFont(&Atari16px);
getdisplay().setTextColor(commonData.fgcolor);
#ifdef HARDWARE_V21
// Frame around key icon area
if (! commonData.keylock) {
// horizontal elements
const uint16_t top = 280;
const uint16_t bottom = 299;
// horizontal stub lines
getdisplay().drawLine(commonData.keydata[0].x, top, commonData.keydata[0].x+10, top, commonData.fgcolor);
for (int i = 1; i <= 5; i++) {
getdisplay().drawLine(commonData.keydata[i].x-10, top, commonData.keydata[i].x+10, top, commonData.fgcolor);
}
getdisplay().drawLine(commonData.keydata[5].x + commonData.keydata[5].w - 10, top, commonData.keydata[5].x + commonData.keydata[5].w + 1, top, commonData.fgcolor);
// vertical key separators
for (int i = 0; i <= 4; i++) {
getdisplay().drawLine(commonData.keydata[i].x + commonData.keydata[i].w, top, commonData.keydata[i].x + commonData.keydata[i].w, bottom, commonData.fgcolor);
}
for (int i = 0; i < 6; i++) {
uint16_t x, y;
if (commonData.keydata[i].label.length() > 0) {
// check if icon is enabled
String icon_name = commonData.keydata[i].label.substring(1);
if (commonData.keydata[i].label[0] == '#') {
if (iconmap.find(icon_name) != iconmap.end()) {
x = commonData.keydata[i].x + (commonData.keydata[i].w - icon_width) / 2;
y = commonData.keydata[i].y + (commonData.keydata[i].h - icon_height) / 2;
getdisplay().drawXBitmap(x, y, iconmap[icon_name], icon_width, icon_height, commonData.fgcolor);
} else {
// icon is missing, use name instead
x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
drawTextCenter(x, y, icon_name);
}
} else {
x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
drawTextCenter(x, y, commonData.keydata[i].label);
}
getdisplay().print("LOT");
}
}
} else {
getdisplay().setCursor(65, 295);
getdisplay().print("Press 1 and 6 fast to unlock keys");
}
#endif
#ifdef BOARD_OBP40S3
// grapical page indicator
static const uint16_t r = 5;
static const uint16_t space = 4;
uint16_t w = commonData.data.maxpage * r * 2 + (commonData.data.maxpage - 1) * space;
uint16_t x0 = (GxEPD_WIDTH - w) / 2 + r * 2;
for (int i = 0; i < commonData.data.maxpage; i++) {
if (i == (commonData.data.actpage - 1)) {
getdisplay().fillCircle(x0 + i * (r * 2 + space), 290, r, commonData.fgcolor);
} else {
getdisplay().drawCircle(x0 + i * (r * 2 + space), 290, r, commonData.fgcolor);
else{
if(commonData.config->getBool(commonData.config->useSimuData) == true){
getdisplay().print("12:00 01.01.2024 LOT");
}
else{
getdisplay().print("No GPS data");
}
}
}
// key indicators
// left side = top key "menu"
getdisplay().drawLine(0, 280, 10, 280, commonData.fgcolor);
getdisplay().drawLine(55, 280, 65, 280, commonData.fgcolor);
getdisplay().drawLine(65, 280, 65, 299, commonData.fgcolor);
drawTextCenter(33, 291, commonData.keydata[0].label);
// right side = bottom key "exit"
getdisplay().drawLine(390, 280, 399, 280, commonData.fgcolor);
getdisplay().drawLine(335, 280, 345, 280, commonData.fgcolor);
getdisplay().drawLine(335, 280, 335, 399, commonData.fgcolor);
drawTextCenter(366, 291, commonData.keydata[1].label);
#endif
}
// Sunset und sunrise calculation
SunData calcSunsetSunrise(double time, double date, double latitude, double longitude, float timezone){
SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone){
GwLog *logger=api->getLogger();
SunData returnset;
SunRise sr;
int secPerHour = 3600;
@@ -560,7 +327,8 @@ SunData calcSunsetSunrise(double time, double date, double latitude, double long
if (!isnan(time) && !isnan(date) && !isnan(latitude) && !isnan(longitude) && !isnan(timezone)) {
// Calculate local epoch
t = (date * secPerYear) + time;
t = (date * secPerYear) + time;
// api->getLogger()->logDebug(GwLog::DEBUG,"... calcSun: Lat %f, Lon %f, at: %d ", latitude, longitude, t);
sr.calculate(latitude, longitude, t); // LAT, LON, EPOCH
// Sunrise
if (sr.hasRise) {
@@ -583,37 +351,6 @@ SunData calcSunsetSunrise(double time, double date, double latitude, double long
return returnset;
}
SunData calcSunsetSunriseRTC(struct tm *rtctime, double latitude, double longitude, float timezone) {
SunData returnset;
SunRise sr;
const int secPerHour = 3600;
const int secPerYear = 86400;
sr.hasRise = false;
sr.hasSet = false;
time_t t = mktime(rtctime) + timezone * 3600;;
time_t sunR = 0;
time_t sunS = 0;
sr.calculate(latitude, longitude, t); // LAT, LON, EPOCH
// Sunrise
if (sr.hasRise) {
sunR = (sr.riseTime + int(timezone * secPerHour) + 30) % secPerYear; // add 30 seconds: round to minutes
returnset.sunriseHour = int (sunR / secPerHour);
returnset.sunriseMinute = int((sunR - returnset.sunriseHour * secPerHour) / 60);
}
// Sunset
if (sr.hasSet) {
sunS = (sr.setTime + int(timezone * secPerHour) + 30) % secPerYear; // add 30 seconds: round to minutes
returnset.sunsetHour = int (sunS / secPerHour);
returnset.sunsetMinute = int((sunS - returnset.sunsetHour * secPerHour) / 60);
}
// Sun control (return value by sun on sky = false, sun down = true)
if ((t >= sr.riseTime) && (t <= sr.setTime))
returnset.sunDown = false;
else returnset.sunDown = true;
return returnset;
}
// Battery graphic with fill level
void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor){
// Show battery
@@ -680,50 +417,9 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
getdisplay().fillCircle(xb, yb, 41, bcolor);
// Insert G
getdisplay().setTextColor(pcolor);
getdisplay().setFont(&Ubuntu_Bold32pt8b);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(xb-22, yb+20);
getdisplay().print("G");
}
// Function to handle HTTP image request
// http://192.168.15.1/api/user/OBP60Task/screenshot
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request) {
GwLog *logger = api->getLogger();
String imgformat = api->getConfig()->getConfigItem(api->getConfig()->imageFormat,true)->asString();
imgformat.toLowerCase();
String filename = "Page" + String(*pageno) + "_" + pages[*pageno].description->pageName + "." + imgformat;
logger->logDebug(GwLog::LOG,"handle image request [%s]: %s", imgformat, filename);
uint8_t *fb = getdisplay().getBuffer(); // EPD framebuffer
std::vector<uint8_t> imageBuffer; // image in webserver transferbuffer
String mimetype;
if (imgformat == "gif") {
// GIF is commpressed with LZW, so small
mimetype = "image/gif";
if (!createGIF(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT)) {
logger->logDebug(GwLog::LOG,"GIF creation failed: Hashtable init error!");
return;
}
}
else if (imgformat == "bmp") {
// Microsoft BMP bitmap
mimetype = "image/bmp";
createBMP(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
}
else {
// PBM simple portable bitmap
mimetype = "image/x-portable-bitmap";
createPBM(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
}
AsyncWebServerResponse *response = request->beginResponse_P(200, mimetype, (const uint8_t*)imageBuffer.data(), imageBuffer.size());
response->addHeader("Content-Disposition", "inline; filename=" + filename);
request->send(response);
imageBuffer.clear();
}
#endif

View File

@@ -3,44 +3,26 @@
#include <Arduino.h>
#include "OBP60Hardware.h"
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include "LedSpiTask.h"
#include <GxEPD2_BW.h> // E-paper lib V2
#include <Adafruit_FRAM_I2C.h> // I2C FRAM
// FRAM address reservations 32kB: 0x0000 - 0x7FFF
// 0x0000 - 0x03ff: single variables
#define FRAM_PAGE_NO 0x0002
#define FRAM_SYSTEM_MODE 0x009
// Voltage page
#define FRAM_VOLTAGE_AVG 0x000A
#define FRAM_VOLTAGE_TREND 0x000B
#define FRAM_VOLTAGE_MODE 0x000C
#define FRAM_WIND_SIZE 0x000D
#define FRAM_WIND_SRC 0x000E
#define FRAM_WIND_MODE 0x000F
// Barograph history data
#define FRAM_BAROGRAPH_START 0x0400
#define FRAM_BAROGRAPH_END 0x13FF
extern Adafruit_FRAM_I2C fram;
extern bool hasFRAM;
// Fonts declarations for display (#includes see OBP60Extensions.cpp)
// Fonts declarations for display (#inclues see OBP60Extensions.cpp)
extern const GFXfont Ubuntu_Bold8pt7b;
extern const GFXfont Ubuntu_Bold10pt7b;
extern const GFXfont Ubuntu_Bold12pt7b;
extern const GFXfont Ubuntu_Bold16pt7b;
extern const GFXfont Ubuntu_Bold20pt7b;
extern const GFXfont Ubuntu_Bold32pt7b;
extern const GFXfont DSEG7Classic_BoldItalic16pt7b;
extern const GFXfont DSEG7Classic_BoldItalic20pt7b;
extern const GFXfont DSEG7Classic_BoldItalic26pt7b;
extern const GFXfont DSEG7Classic_BoldItalic30pt7b;
extern const GFXfont DSEG7Classic_BoldItalic42pt7b;
extern const GFXfont DSEG7Classic_BoldItalic60pt7b;
extern const GFXfont Ubuntu_Bold8pt8b;
extern const GFXfont Ubuntu_Bold10pt8b;
extern const GFXfont Ubuntu_Bold12pt8b;
extern const GFXfont Ubuntu_Bold16pt8b;
extern const GFXfont Ubuntu_Bold20pt8b;
extern const GFXfont Ubuntu_Bold32pt8b;
extern const GFXfont Atari16px;
// Global functions
// Gloabl functions
#ifdef DISPLAY_GDEW042T2
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay();
#endif
@@ -57,19 +39,7 @@ GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay();
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
#endif
struct Point {
double x;
double y;
};
Point rotatePoint(const Point& origin, const Point& p, 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 deepSleep(CommonData &common);
uint8_t getLastPage();
void hardwareInit(GwApi *api);
void hardwareInit();
void setPortPin(uint pin, bool value); // Set port pin for extension port
@@ -78,7 +48,6 @@ void togglePortPin(uint pin); // Toggle extension port pin
Color colorMapping(const String &colorString); // Color mapping string to CHSV colors
void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs
void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs
BacklightMode backlightMapping(const String &backlightString);// Configuration string to value
void setFlashLED(bool status); // Set flash LED
void blinkingFlashLED(); // Blinking function for flash LED
@@ -96,134 +65,12 @@ void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop); // Draw display header
void displayFooter(CommonData &commonData);
SunData calcSunsetSunrise(double time, double date, double latitude, double longitude, float timezone); // Calulate sunset and sunrise
SunData calcSunsetSunriseRTC(struct tm *rtctime, double latitude, double longitude, float timezone);
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 solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic
void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic with fill level
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level
void startLedTask(GwApi *api);
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
// Icons
#define icon_width 16
#define icon_height 16
static unsigned char left_bits[] PROGMEM = {
0x00, 0x00, 0xc0, 0x01, 0xe0, 0x01, 0xf0, 0x01, 0xf8, 0x01, 0xfc, 0x7f,
0xfe, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x01,
0xf0, 0x01, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0x00 };
static unsigned char right_bits[] PROGMEM = {
0x00, 0x00, 0x80, 0x03, 0x80, 0x07, 0x80, 0x0f, 0x80, 0x1f, 0xfe, 0x3f,
0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0x80, 0x1f,
0x80, 0x0f, 0x80, 0x07, 0x80, 0x03, 0x00, 0x00 };
static unsigned char lock_bits[] PROGMEM = {
0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f };
static unsigned char plus_bits[] PROGMEM = {
0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0xc4, 0x08, 0xc2, 0x10,
0xf2, 0x13, 0xf2, 0x13, 0xc2, 0x10, 0xc4, 0x08, 0x04, 0x0c, 0x18, 0x1e,
0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
static unsigned char minus_bits[] PROGMEM = {
0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0x04, 0x08, 0x02, 0x10,
0xf2, 0x13, 0xf2, 0x13, 0x02, 0x10, 0x04, 0x08, 0x04, 0x0c, 0x18, 0x1e,
0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
static unsigned char fram_bits[] PROGMEM = {
0xf8, 0x1f, 0xff, 0xff, 0x9f, 0xff, 0x98, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };
static unsigned char ap_bits[] = {
0xe0, 0x03, 0x18, 0x0c, 0x04, 0x10, 0xc2, 0x21, 0x30, 0x06, 0x08, 0x08,
0xc0, 0x01, 0x20, 0x02, 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xc0, 0x01,
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
static unsigned char dish_bits[] PROGMEM= {
0x3c, 0x00, 0x42, 0x18, 0xfa, 0x1b, 0x02, 0x04, 0x02, 0x0a, 0x02, 0x09,
0x82, 0x08, 0x06, 0x0a, 0x0e, 0x1b, 0x9c, 0x2b, 0x38, 0x2b, 0x74, 0x20,
0xec, 0x1f, 0x1c, 0x00, 0xf4, 0x00, 0xfe, 0x03 };
static std::map<String, unsigned char *> iconmap = {
{"LEFT", left_bits},
{"RIGHT", right_bits},
{"LOCK", lock_bits},
{"PLUS", plus_bits},
{"MINUS", minus_bits},
{"DISH", dish_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
#define swipe_width 24
#define swipe_height 16
static unsigned char swipe_bits[] PROGMEM = {
0x00, 0x06, 0x00, 0x24, 0x09, 0x24, 0x12, 0x09, 0x48, 0x7f, 0x09, 0xfe,
0x12, 0xb9, 0x48, 0x24, 0xc9, 0x25, 0x40, 0x49, 0x02, 0xa0, 0x49, 0x06,
0x20, 0x01, 0x0a, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08,
0x80, 0x00, 0x04, 0x00, 0x01, 0x04, 0x00, 0x02, 0x02, 0x00, 0xfc, 0x01 };
#define exclamation_width 32
#define exclamation_height 32
static unsigned char exclamation_bits[] PROGMEM = {
0x00, 0xc0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0xb0, 0x0d, 0x00,
0x00, 0xd8, 0x1b, 0x00, 0x00, 0xec, 0x37, 0x00, 0x00, 0xf6, 0x6f, 0x00,
0x00, 0x3b, 0xdc, 0x00, 0x80, 0x3d, 0xbc, 0x01, 0xc0, 0x3e, 0x7c, 0x03,
0x60, 0x3f, 0xfc, 0x06, 0xb0, 0x3f, 0xfc, 0x0d, 0xd8, 0x3f, 0xfc, 0x1b,
0xec, 0x3f, 0xfc, 0x37, 0xf6, 0x3f, 0xfc, 0x6f, 0xfb, 0x3f, 0xfc, 0xdf,
0xfd, 0x3f, 0xfc, 0xbf, 0xfd, 0x3f, 0xfc, 0xbf, 0xfb, 0x3f, 0xfc, 0xdf,
0xf6, 0x3f, 0xfc, 0x6f, 0xec, 0x3f, 0xfc, 0x37, 0xd8, 0xff, 0xff, 0x1b,
0xb0, 0xff, 0xff, 0x0d, 0x60, 0x3f, 0xfc, 0x06, 0xc0, 0x3e, 0x7c, 0x03,
0x80, 0x3d, 0xbc, 0x01, 0x00, 0x3b, 0xdc, 0x00, 0x00, 0xf6, 0x6f, 0x00,
0x00, 0xec, 0x37, 0x00, 0x00, 0xd8, 0x1b, 0x00, 0x00, 0xb0, 0x0d, 0x00,
0x00, 0x60, 0x06, 0x00, 0x00, 0xc0, 0x03, 0x00 };
#endif

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include <Arduino.h>
#include "GwApi.h"
@@ -8,35 +8,6 @@
// simulation data
// hold values by missing data
String formatDate(String fmttype, uint16_t year, uint8_t month, uint8_t day) {
char buffer[12];
if (fmttype == "GB") {
snprintf(buffer, 12, "%02d/%02d/%04d", day , month, year);
}
else if (fmttype == "US") {
snprintf(buffer, 12, "%02d/%02d/%04d", month, day, year);
}
else if (fmttype == "ISO") {
snprintf(buffer, 12, "%04d-%02d-%02d", year, month, day);
}
else {
snprintf(buffer, 12, "%02d.%02d.%04d", day, month, year);
}
return String(buffer);
}
String formatTime(char fmttype, uint8_t hour, uint8_t minute, uint8_t second) {
// fmttype: s: with seconds, m: only minutes
char buffer[10];
if (fmttype == 'm') {
snprintf(buffer, 10, "%02d:%02d", hour , minute);
}
else {
snprintf(buffer, 10, "%02d:%02d:%02d", hour, minute, second);
}
return String(buffer);
}
FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
GwLog *logger = commondata.logger;
FormatedData result;
@@ -346,7 +317,7 @@ FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
else{
latdir = "S";
}
latitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + latdir;
latitude = String(degree,0) + "\" " + String(minute,4) + "' " + latdir;
result.unit = "";
strcpy(buffer, latitude.c_str());
}
@@ -370,7 +341,7 @@ FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
else{
londir = "W";
}
longitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + londir;
longitude = String(degree,0) + "\" " + String(minute,4) + "' " + londir;
result.unit = "";
strcpy(buffer, longitude.c_str());
}
@@ -409,14 +380,8 @@ FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
}
//########################################################
else if (value->getFormat() == "formatXte"){
double xte = 0;
if (!usesimudata) {
xte = abs(value->value);
rawvalue = value->value;
} else {
rawvalue = 6.0 + float(random(0, 4));
xte = rawvalue;
}
double xte = abs(value->value);
rawvalue = value->value;
if (xte >= 100) {
snprintf(buffer,bsize,"%3.0f",value->value);
} else if (xte >= 10) {
@@ -442,7 +407,7 @@ FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
result.unit = "C";
}
else if(String(tempFormat) == "F"){
temp = (temp - 273.15) * 9 / 5 + 32;
temp = temp - 459.67;
result.unit = "F";
}
else{

View File

@@ -1,7 +1,6 @@
// General hardware definitions
// CAN and RS485 bus pin definitions see obp60task.h
#ifdef HARDWARE_V21
// Direction pin for RS485 NMEA0183
#define OBP_DIRECTION_PIN 18
// I2C
@@ -31,8 +30,6 @@
#define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// Horter modules
#define PCF8574_I2C_ADDR1 0x20 // First digital out module
// FRAM (e.g. MB85RC256V)
#define FRAM_I2C_ADDR 0x50
// SPI (E-Ink display, Extern Bus)
#define OBP_SPI_CS 39
#define OBP_SPI_DC 40
@@ -42,6 +39,11 @@
#define OBP_SPI_DIN 48
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
#define FONT1 "Ubuntu_Bold8pt7b"
#define FONT2 "Ubuntu_Bold24pt7b"
#define FONT3 "Ubuntu_Bold32pt7b"
#define FONT4 "DSEG7Classic_BoldItalic80pt7b"
// GPS (NEO-6M, NEO-M8N, ATGM336H)
#define OBP_GPS_RX 2
@@ -55,7 +57,7 @@
#define TONE3 3500 // 3500Hz
#define TONE4 4000 // 4000Hz
// Analog Input
#define OBP_ANALOG0 4 // Analog input for voltage power supply
#define OBP_ANALOG0 4 // Analog input for voltage power supplay
#define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep)
#define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
// Touch buttons
@@ -70,96 +72,9 @@
#define NUM_FLASH_LED 1 // Number of flash LED
#define OBP_FLASH_LED 7 // GPIO port
// Backlight LEDs (6x WS2812B)
#define NUM_BACKLIGHT_LED 6 // Number of Backlight LEDs
#define NUM_BACKLIGHT_LED 6 // Numebr of Backlight LEDs
#define OBP_BACKLIGHT_LED 15 // GPIO port
// Power Rail
#define OBP_POWER_50 5 // 5.0V power rail
#endif
// Hardware configuration for OBP40
#ifdef BOARD_OBP40S3
// Direction pin for RS485 NMEA0183
#define OBP_DIRECTION_PIN 8
// I2C
#define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
#define OBP_I2C_SDA 21
#define OBP_I2C_SCL 38
// DS1388 RTC
#define DS1388_I2C_ADDR 0x68 // Addr. 0x68
// BME280
#define BME280_I2C_ADDR 0x76 // Addr. 0x76 (0x77)
// BMP280
#define BMP280_I2C_ADDR 0x77 // Addr. 0x77 (0x76) Attention: Pull up resistor
// BMP085 / BMP180
#define BMP180_I2C_ADDR 0x77 // Addr. 0x77 (fix)
// SHT21 / HUT21
#define SHT21_I2C_ADDR 0x40 // Addr. 0x40 (fix)
// AS5600
#define AS5600_I2C_ADDR 0x36 // Addr. 0x36 (fix)
// INA219
#define SHUNT_VOLTAGE 0.075 // Shunt voltage in V by max. current (75mV)
#define INA219_I2C_ADDR1 0x40 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
#define INA219_I2C_ADDR2 0x41 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
#define INA219_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// INA226
#define INA226_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
#define INA226_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
#define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// Horter modules
#define PCF8574_I2C_ADDR1 0x20 // First digital out module
// FRAM (e.g. MB85RC256V)
#define FRAM_I2C_ADDR 0x50
// SPI (E-Ink display, Extern Bus)
#define OBP_SPI_CS 45
#define OBP_SPI_DC 46
#define OBP_SPI_RST 47
#define OBP_SPI_BUSY 48
#define OBP_SPI_CLK 12
#define OBP_SPI_DIN 11
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
// SPI SD-Card
#define SD_SPI_CS 10
#define SD_SPI_MOSI 40
#define SD_SPI_CLK 39
#define SD_SPI_MISO 13
// GPS (NEO-6M, NEO-M8N, ATGM336H)
#define OBP_GPS_RX 19
#define OBP_GPS_TX 20
// 1Wire (DS18B20)
#define OBP_1WIRE 17 // External 1Wire
// Buzzer
#define OBP_BUZZER 18
#define TONE1 1500 // 1500Hz
#define TONE2 2500 // 2500Hz
#define TONE3 3500 // 3500Hz
#define TONE4 4000 // 4000Hz
// Analog Input
#define OBP_ANALOG0 3 // Analog input for voltage power supply
#define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep)
#define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
// Buttons
#define UP 6 // Wheel up
#define DOWN 4 // Wheel down
#define CONF 5 // Wheel press
#define MENUE 2 // Button top
#define EXIT 1 // Button bottom
// Flash LED (1x WS2812B)
#define NUM_FLASH_LED 1 // Number of flash LED
#define OBP_FLASH_LED 41 // GPIO port (power LED)
// Backlight LEDs (6x WS2812B)
#define NUM_BACKLIGHT_LED 6 // Number of Backlight LEDs
#define OBP_BACKLIGHT_LED 41 // GPIO port (power LED)
// Power Rail
#define OBP_POWER_50 41 // Power LED
#define OBP_POWER_EPD 7 // ePaper power
#define OBP_POWER_SD 42 // SD card power
// Deep sleep wakeup
#define OBP_WAKEUP_LEVEL 0 // //1 = High, 0 = Low, depends on switch
#define OBP_WAKEWUP_PIN GPIO_NUM_5// Wakeup pin, same as CONF (wheel press)
// Must define as GPIO_NUM_X
#endif

View File

@@ -14,290 +14,167 @@ int keycode = 0; // Keycode of pressed key [0...8], 0 = nothing touched
int keycode2 = 0; // Keycode of very short pressed key [0...8], 0 = nothing touched
int keycodeold = 0; // Old keycode
int keycodeold2 = 0; // Old keycode for short pressed key
int keystatus = 0; // Status of key [0...11]
bool keyoff = false; // Disable all keys
int keydelay = 250; // Delay after key pressed in [ms]
bool keylock = false; // Key lock after pressed key is valid (repeat protection by conginous pressing)
long starttime = 0; // Start time point for pressed key
void initKeys(CommonData &commonData) {
// coordinates for virtual keyboard keys
static uint16_t top = 281;
static uint16_t width = 65;
static uint16_t height = 18;
int readKeypad(uint thSensitivity) {
// Touch sensor values
// 35000 - Not touched
// 50000 - Light toched with fingertip
// 70000 - Touched
// 170000 - Strong touched
uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
commonData.keydata[0].x = 0;
commonData.keydata[0].y = top;
commonData.keydata[0].w = width + 1;
commonData.keydata[0].h = height;
int keystatus = 0; // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
keycode = 0;
commonData.keydata[1].x = commonData.keydata[0].x + commonData.keydata[0].w + 1;
commonData.keydata[1].y = top;
commonData.keydata[1].w = width;
commonData.keydata[1].h = height;
// Read key code
if(touchRead(14) > touchthreshold){ // Touch pad 1
keypad[1] = 1;
}
else{
keypad[1] = 0;
}
if(touchRead(13) > touchthreshold){ // Touch pad 2
keypad[2] = 1;
}
else{
keypad[2] = 0;
}
if(touchRead(12) > touchthreshold){ // Touch pad 3
keypad[3] = 1;
}
else{
keypad[3] = 0;
}
if(touchRead(11) > touchthreshold){ // Touch pad 4
keypad[4] = 1;
}
else{
keypad[4] = 0;
}
if(touchRead(10) > touchthreshold){ // Touch pad 5
keypad[5] = 1;
}
else{
keypad[5] = 0;
}
if(touchRead(9) > touchthreshold){ // Touch pad 6
keypad[6] = 1;
}
else{
keypad[6] = 0;
}
// Nothing touched
if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 && keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
keypad[0] = 1;
}
else{
keypad[0] = 0;
}
commonData.keydata[2].x = commonData.keydata[1].x + commonData.keydata[1].w + 1;
commonData.keydata[2].y = top;
commonData.keydata[2].w = width;
commonData.keydata[2].h = height;
commonData.keydata[3].x = commonData.keydata[2].x + commonData.keydata[2].w + 1;
commonData.keydata[3].y = top;
commonData.keydata[3].w = width;
commonData.keydata[3].h = height;
commonData.keydata[4].x = commonData.keydata[3].x + commonData.keydata[3].w + 1;
commonData.keydata[4].y = top;
commonData.keydata[4].w = width;
commonData.keydata[4].h = height;
commonData.keydata[5].x = commonData.keydata[4].x + commonData.keydata[4].w + 1;
commonData.keydata[5].y = top;
commonData.keydata[5].w = width;
commonData.keydata[5].h = height;
}
#ifdef HARDWARE_V21
// Keypad functions for original OBP60 hardware
int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) {
// Touch sensor values
// 35000 - Not touched
// 50000 - Light toched with fingertip
// 70000 - Touched
// 170000 - Strong touched
uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
keystatus = 0; // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
keycode = 0;
// Read key code
if(touchRead(14) > touchthreshold){ // Touch pad 1
keypad[1] = 1;
}
else{
keypad[1] = 0;
}
if(touchRead(13) > touchthreshold){ // Touch pad 2
keypad[2] = 1;
}
else{
keypad[2] = 0;
}
if(touchRead(12) > touchthreshold){ // Touch pad 3
keypad[3] = 1;
}
else{
keypad[3] = 0;
}
if(touchRead(11) > touchthreshold){ // Touch pad 4
keypad[4] = 1;
}
else{
keypad[4] = 0;
}
if(touchRead(10) > touchthreshold){ // Touch pad 5
keypad[5] = 1;
}
else{
keypad[5] = 0;
}
if(touchRead(9) > touchthreshold){ // Touch pad 6
keypad[6] = 1;
}
else{
keypad[6] = 0;
}
// Nothing touched
/* if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 && keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
keypad[0] = 1;
}
else{
keypad[0] = 0;
} */
for (int i = 1; i <= 6; i++) {
if(i > 0){
// Convert keypad to keycode
if(keypad[i] == 1){
key = 1;
}
else{
key = 0;
}
keycode += key * i;
}
}
// Detect short keynumber
if (keycode > 0 ){
if(keylock == false){
starttime = millis();
keylock = true;
for (int i = 0; i < 9; i++) {
if(i > 0){
// Convert keypad to keycode
if(keypad[i] == 1){
key = 1;
}
else{
key = 0;
}
keycode += key * i;
}
if (keycode != keycodeold){
keylock = false;
}
// Detect a very short keynumber (10ms)
if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
logger->logDebug(GwLog::LOG,"Very short 20ms key touch: %d", keycode);
}
// Process only valid keys
if(keycode == 1 || keycode == 4 || keycode == 5 || keycode == 6){
keycode2 = keycode;
}
// Clear by invalid keys
else{
keycode2 = 0;
keycodeold2 = 0;
}
// Detect short keynumber
if (keycode > 0 ){
if(keylock == false){
starttime = millis();
keylock = true;
}
if (keycode != keycodeold){
keylock = false;
}
// Detect a very short keynumber (10ms)
if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
// Process only valid keys
if(keycode == 1 || keycode == 6){
keycode2 = keycode;
}
// Timeout for very short pressed key
if(millis() > starttime + 200){
keycode2 = 0;
}
// Detect a short keynumber (200ms)
if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
logger->logDebug(GwLog::LOG,"Short 200ms key touch: %d", keycode);
keystatus = keycode;
keycode = 0;
keycodeold = 0;
// Clear by unvalid keys
else{
keycode2 = 0;
keycodeold2 = 0;
buzzer(TONE4, 100);
keylock = false;
delay(keydelay);
}
}
// System page with key 5 and 4 in fast series
if (keycode2 == 5 && keycodeold2 == 4) {
logger->logDebug(GwLog::LOG,"Keycode for system page");
keycode = 0;
keycodeold = 0;
// Timeout for very short pressed key
if(millis() > starttime + 200){
keycode2 = 0;
keycodeold2 = 0;
keystatus = 12;
buzzer(TONE4, 50);
delay(30);
buzzer(TONE4, 50);
delay(30);
buzzer(TONE4, 50);
}
// Key lock with key 1 and 6 or 6 and 1 in fast series
if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
// Detect a short keynumber (200ms)
if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
keystatus = keycode;
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
buzzer(TONE4, 1000);
buzzer(TONE4, 100);
keylock = false;
delay(keydelay);
keyoff = !keyoff;
keystatus = 11;
}
// Detect swipe right
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 9;
buzzer(TONE3, 150);
buzzer(TONE4, 150);
}
// Detect swipe left
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 10;
buzzer(TONE4, 150);
buzzer(TONE3, 150);
}
// Reset keylock after release
if (keycode == 0){
keylock = false;
}
// Copy keycode
keycodeold = keycode;
keycodeold2 = keycode2;
return keystatus;
}
#endif
#ifdef BOARD_OBP40S3
int readSensorpads(){
// Read key code
if(digitalRead(UP) == LOW){
keycode = 10; // Left swipe
}
else if(digitalRead(DOWN) == LOW){
keycode = 9; // Right swipe
}
else if(digitalRead(CONF) == LOW){
keycode = 3; // Key 3
}
else if(digitalRead(MENUE) == LOW){
keycode = 1; // Key 1
}
else if(digitalRead(EXIT) == LOW){
keycode = 2; // Key 2
}
else{
keycode = 0; // No key activ
}
return keycode;
}
// Keypad functions for OBP60 clone (thSensitivity is inactiv)
int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) {
pinMode(UP, INPUT);
pinMode(DOWN, INPUT);
pinMode(CONF, INPUT);
pinMode(MENUE, INPUT);
pinMode(EXIT, INPUT);
// Read pad values
readSensorpads();
// Detect key
if (keycode > 0 ){
if(keycode != keycodeold){
starttime = millis(); // Start key pressed
keycodeold = keycode;
}
// If key pressed longer than 100ms
if(millis() > starttime + 100 && keycode == keycodeold) {
if (use_syspage and keycode == 3) {
keystatus = 12;
} else {
keystatus = keycode;
}
// Copy keycode
keycodeold = keycode;
while(readSensorpads() > 0){} // Wait for pad release
delay(keydelay);
}
}
else{
keycode = 0;
keycodeold = 0;
keystatus = 0;
}
return keystatus;
// Key lock with key 1 and 6 or 6 and 1 in fast series
if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
buzzer(TONE4, 1000);
keylock = false;
delay(keydelay);
keyoff = !keyoff;
keystatus = 11;
}
#endif
#endif
// Detect swipe right
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 9;
buzzer(TONE3, 150);
buzzer(TONE4, 150);
}
// Detect swipe left
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 10;
buzzer(TONE4, 150);
buzzer(TONE3, 150);
}
// Reset keylock after release
if (keycode == 0){
keylock = false;
}
// Copy keycode
keycodeold = keycode;
keycodeold2 = keycode2;
return keystatus;
}
#endif

View File

@@ -35,7 +35,7 @@ void qrWiFi(String ssid, String passwd, uint16_t fgcolor, uint16_t bgcolor){
box_y = box_y + box_s;
box_x = init_x;
}
getdisplay().setFont(&Ubuntu_Bold32pt8b);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setTextColor(fgcolor);
getdisplay().setCursor(140, 285);
getdisplay().print("WiFi");

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include <Adafruit_Sensor.h> // Adafruit Lib for sensors
#include <Adafruit_BME280.h> // Adafruit Lib for BME280
#include <Adafruit_BMP280.h> // Adafruit Lib for BMP280
@@ -17,11 +17,9 @@
#include "ObpNmea0183.h" // Check NMEA0183 sentence for uncorrect content
#include "OBP60Extensions.h" // Lib for hardware extensions
#include "movingAvg.h" // Lib for moving average building
#include "time.h" // For getting NTP time
#include <ESP32Time.h> // Internal ESP32 RTC clock
// Timer for hardware functions
Ticker Timer1(blinkingFlashLED, 500); // Start Timer1 for flash LED all 500ms
Ticker Timer1(blinkingFlashLED, 500); // Satrt Timer1 for flash LED all 500ms
// Initialization for all sensors (RS232, I2C, 1Wire, IOs)
//####################################################################################
@@ -90,16 +88,8 @@ void sensorTask(void *param){
double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat();
double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat();
if(String(powsensor1) == "off"){
#ifdef VOLTAGE_SENSOR
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.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
sensors.batteryCurrent = 0;
sensors.batteryPower = 0;
// Fill average arrays with start values
@@ -152,7 +142,6 @@ void sensorTask(void *param){
// ds1388.adjust(DateTime(__DATE__, __TIME__)); // Set date and time from PC file time
}
RTC_ready = true;
sensors.rtcValid = true;
}
}
@@ -369,28 +358,6 @@ void sensorTask(void *param){
GwApi::BoatValue *hdop=new GwApi::BoatValue(GwBoatData::_HDOP);
GwApi::BoatValue *valueList[]={gpsdays, gpsseconds, hdop};
// Internal RTC with NTP init
ESP32Time rtc(0);
if (api->getConfig()->getString(api->getConfig()->timeSource) == "iRTC") {
GwApi::Status status;
api->getStatus(status);
if (status.wifiClientConnected) {
const char *ntpServer = api->getConfig()->getCString(api->getConfig()->timeServer);
api->getLogger()->logDebug(GwLog::LOG,"Fetching date and time from NTP server '%s'.", ntpServer);
configTime(0, 0, ntpServer); // get time in UTC
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
api->getLogger()->logDebug(GwLog::LOG,"NTP time: %04d-%02d-%02d %02d:%02d:%02d UTC", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
rtc.setTimeStruct(timeinfo);
sensors.rtcValid = true;
} else {
api->getLogger()->logDebug(GwLog::LOG,"NTP time fetch failed!");
}
} else {
api->getLogger()->logDebug(GwLog::LOG,"Wifi client not connected, NTP not available.");
}
}
// Sensor task loop runs with 100ms
//####################################################################################
@@ -453,112 +420,58 @@ void sensorTask(void *param){
loopCounter++;
}
// Get current RTC date and time all 500ms
if (millis() > starttime12 + 500) {
// If GPS not ready or installed then send RTC time on bus all 500ms
if(millis() > starttime12 + 500){
starttime12 = millis();
if (rtcOn == "DS1388" && RTC_ready) {
DateTime dt = ds1388.now();
sensors.rtcTime.tm_year = dt.year() - 1900; // Save values in SensorData
sensors.rtcTime.tm_mon = dt.month() - 1;
sensors.rtcTime.tm_mday = dt.day();
sensors.rtcTime.tm_hour = dt.hour();
sensors.rtcTime.tm_min = dt.minute();
sensors.rtcTime.tm_sec = dt.second();
sensors.rtcTime.tm_isdst = 0; // Not considering daylight saving time
// If GPS not ready or installed then send RTC time on bus
// TODO If there are other time sources on the bus there should
// be a logic not to send or to send with lower frequency
// or something totally different
if ((GPS_ready == false) || (GPS_ready == true && hdop->valid == false)) {
// TODO implement daysAt1970 and sysTime as methods of DateTime
const short daysOfYear[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
uint16_t switchYear = ((dt.year()-1)-1968)/4 - ((dt.year()-1)-1900)/100 + ((dt.year()-1)-1600)/400;
long daysAt1970 = (dt.year()-1970)*365 + switchYear + daysOfYear[dt.month()-1] + dt.day()-1;
// If switch year then add one day
if ((dt.month() > 2) && (dt.year() % 4 == 0 && (dt.year() % 100 != 0 || dt.year() % 400 == 0))) {
daysAt1970 += 1;
}
// N2K sysTime is double in n2klib
double sysTime = (dt.hour() * 3600) + (dt.minute() * 60) + dt.second();
// WHY? isnan should always fail here
//if(!isnan(daysAt1970) && !isnan(sysTime)){
//api->getLogger()->logDebug(GwLog::LOG,"RTC time: %04d/%02d/%02d %02d:%02d:%02d",sensors.rtcTime.tm_year+1900,sensors.rtcTime.tm_mon, sensors.rtcTime.tm_mday, sensors.rtcTime.tm_hour, sensors.rtcTime.tm_min, sensors.rtcTime.tm_sec);
//api->getLogger()->logDebug(GwLog::LOG,"Send PGN126992: %10d %10d",daysAt1970, (uint16_t)sysTime);
SetN2kPGN126992(N2kMsg,0,daysAt1970,sysTime,N2ktimes_LocalCrystalClock);
api->sendN2kMessage(N2kMsg);
// }
if((rtcOn == "DS1388" && RTC_ready == true && GPS_ready == false) || (rtcOn == "DS1388" && RTC_ready == true && GPS_ready == true && hdop->valid == false)){
// Convert RTC time to Unix system time
// https://de.wikipedia.org/wiki/Unixzeit
const short daysOfYear[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
long unixtime = ds1388.now().get();
uint16_t year = ds1388.now().year();
uint8_t month = ds1388.now().month();
uint8_t hour = ds1388.now().hour();
uint8_t minute = ds1388.now().minute();
uint8_t second = ds1388.now().second();
uint8_t day = ds1388.now().day();
uint16_t switchYear = ((year-1)-1968)/4 - ((year-1)-1900)/100 + ((year-1)-1600)/400;
long daysAt1970 = (year-1970)*365 + switchYear + daysOfYear[month-1] + day-1;
// If switch year then add one day
if ( (month>2) && (year%4==0 && (year%100!=0 || year%400==0)) ){
daysAt1970 += 1;
}
double sysTime = (hour * 3600) + (minute * 60) + second;
if(!isnan(daysAt1970) && !isnan(sysTime)){
sensors.rtcYear = year; // Save values in SensorData
sensors.rtcMonth = month;
sensors.rtcDay = day;
sensors.rtcHour = hour;
sensors.rtcMinute = minute;
sensors.rtcSecond = second;
// api->getLogger()->logDebug(GwLog::LOG,"RTC time: %04d/%02d/%02d %02d:%02d:%02d",year, month, day, hour, minute, second);
// api->getLogger()->logDebug(GwLog::LOG,"Send PGN126992: %10d %10d",daysAt1970, (uint16_t)sysTime);
SetN2kPGN126992(N2kMsg,0,daysAt1970,sysTime,N2ktimes_LocalCrystalClock);
api->sendN2kMessage(N2kMsg);
}
} else if (sensors.rtcValid) {
// use internal rtc feature
sensors.rtcTime = rtc.getTimeStruct();
}
}
// Send supply voltage value all 1s
// Send supplay voltage value all 1s
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
starttime5 = millis();
float rawVoltage = 0;
#if defined(BOARD_OBP40S3) && defined(VOLTAGE_SENSOR)
rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
#endif
#ifdef BOARD_OBP60S3
rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
#endif
sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
// Save new data in average array
batV.reading(int(sensors.batteryVoltage * 100));
// Calculate the average values for different time lines from integer values
sensors.batteryVoltage10 = batV.getAvg(10) / 100.0;
sensors.batteryVoltage60 = batV.getAvg(60) / 100.0;
sensors.batteryVoltage300 = batV.getAvg(300) / 100.0;
#if BOARD_OBP40S3 && 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;
// Higher limits for lower voltages
if(sensors.batteryVoltage10 < 4.0){
if(deltaV > 0.045){
sensors.BatteryChargeStatus = 1; // Charging active
}
if(deltaV < -0.04){
sensors.BatteryChargeStatus = 0; // Discharging
}
}
// Lower limits for higher voltages
else{
if(deltaV > 0.03){
sensors.BatteryChargeStatus = 1; // Charging active
}
if(deltaV < -0.03){
sensors.BatteryChargeStatus = 0; // Discharging
}
}
// Charging stops by grater than 4,15V
if(sensors.batteryVoltage10 > 4.15){
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
if(!isnan(sensors.batteryVoltage)){
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 1);
api->sendN2kMessage(N2kMsg);
}
#endif
}
// Send data from environment sensor all 2s

View File

@@ -0,0 +1,192 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageApparentWind : public Page
{
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length
public:
PageApparentWind(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageApparentWind");
}
// Key functions
virtual int handleKey(int key){
// Reduce instrument size
if(key == 2){ // Code for reduce
lp = lp - 10;
if(lp < 10){
lp = 10;
}
return 0; // Commit the key
}
// Enlarge instrument size
if(key == 5){ // Code for enlarge
lp = lp + 10;
if(lp > 80){
lp = 80;
}
return 0; // Commit the key
}
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values for AWS
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
// bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values for AWD
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
String name2 = bvalue2->getName().c_str(); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
// bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageApparentWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor);
// Show values AWS
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 50);
if(holdvalues == false){
getdisplay().print(name1); // Value name
getdisplay().print(": ");
getdisplay().print(svalue1); // Value
getdisplay().print(" ");
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(name1); // Value name
getdisplay().print(": ");
getdisplay().print(svalue1old); // Value old
getdisplay().print(" ");
getdisplay().print(unit1old); // Unit old
}
// Show values AWD
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 260);
if(holdvalues == false){
getdisplay().print(name2); // Value name
getdisplay().print(": ");
getdisplay().print(svalue2); // Value
getdisplay().print(" ");
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(name2); // Value name
getdisplay().print(": ");
getdisplay().print(svalue2old); // Value old
getdisplay().print(" ");
getdisplay().print(unit2old); // Unit old
}
// Draw wind pointer
static int16_t x0 = 200; // Center point
static int16_t y0 = 145;
static int16_t x1 = x0; // Start point for pointer
static int16_t y1 = y0;
static int16_t x2 = x0; // End point for pointer
static int16_t y2 = y0;
//Draw instrument
getdisplay().fillCircle(x0, y0, lp + 5, commonData.fgcolor);
getdisplay().fillCircle(x0, y0, lp + 1, commonData.bgcolor);
// Calculation end point of pointer
value2 = value2 - 3.14 / 2;
x1 = x0 + cos(value2) * lp * 0.6;
y1 = y0 + sin(value2) * lp * 0.6;
x2 = x0 + cos(value2) * lp;
y2 = y0 + sin(value2) * lp;
getdisplay().drawLine(x1, y1, x2, y2, commonData.fgcolor);
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageApparentWind(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageApparentWind(
"ApparentWind", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"AWS","AWA"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,28 +1,28 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageBME280 : public Page
{
bool keylock = false; // Keylock
public:
PageBME280(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageBME280");
common.logger->logDebug(GwLog::LOG,"Show PageBME280");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
double value1 = 0;
double value2 = 0;
@@ -42,13 +42,13 @@ class PageBME280 : public Page
String name1 = "Temp"; // Value name
name1 = name1.substring(0, 6); // String length limit for value name
if(simulation == false){
value1 = commonData->data.airTemperature; // Value as double in SI unit
value1 = commonData.data.airTemperature; // Value as double in SI unit
}
else{
value1 = 23.0 + float(random(0, 10)) / 10.0;
}
// Display data when sensor activated
if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){
if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){
svalue1 = String(value1, 1); // Formatted value as string including unit conversion and switching decimal places
}
else{
@@ -60,13 +60,13 @@ class PageBME280 : public Page
String name2 = "Humid"; // Value name
name2 = name2.substring(0, 6); // String length limit for value name
if(simulation == false){
value2 = commonData->data.airHumidity; // Value as double in SI unit
value2 = commonData.data.airHumidity; // Value as double in SI unit
}
else{
value2 = 43 + float(random(0, 4));
}
// Display data when sensor activated
if(useenvsensor == "BME280"){
if(String(useenvsensor) == "BME280"){
svalue2 = String(value2, 0); // Formatted value as string including unit conversion and switching decimal places
}
else{
@@ -78,13 +78,13 @@ class PageBME280 : public Page
String name3 = "Press"; // Value name
name3 = name3.substring(0, 6); // String length limit for value name
if(simulation == false){
value3 = commonData->data.airPressure; // Value as double in SI unit
value3 = commonData.data.airPressure; // Value as double in SI unit
}
else{
value3 = 1006 + float(random(0, 5));
}
// Display data when sensor activated
if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){
if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){
svalue3 = String(value3 / 100, 1); // Formatted value as string including unit conversion and switching decimal places
}
else{
@@ -107,17 +107,17 @@ class PageBME280 : public Page
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// ############### Value 1 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
getdisplay().print(unit1); // Unit
@@ -131,17 +131,17 @@ class PageBME280 : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
// ############### Value 2 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
getdisplay().print(unit2); // Unit
@@ -155,17 +155,17 @@ class PageBME280 : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
// ############### Value 3 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 235);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 270);
getdisplay().print(unit3); // Unit
@@ -176,6 +176,23 @@ class PageBME280 : public Page
// Show bus data
getdisplay().print(svalue3); // Real value as formated string
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -0,0 +1,228 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageBarograph : public Page{
bool keylock = false;
bool has_fram = false;
String flashLED;
String useenvsensor;
char source = 'I'; // (I)nternal, e(X)ternal
const int series[5] = {75, 150, 300, 600, 900};
const int zoom[5] = {1, 2, 3, 6, 12};
int zoomindex = 4;
uint16_t data[336] = {0}; // current data to display
// y-axis
uint16_t vmin;
uint16_t vmax;
uint16_t scalemin = 1000;
uint16_t scalemax = 1020;
uint16_t scalestep = 5;
int hist1 = 0; // one hour trend
int hist3 = 0; // three hours trend
long refresh = 0; // millis
void loadData() {
// Transfer data from history to page buffer,
// set y-axis according to data
int i = zoom[zoomindex];
// get min and max values of measured data
vmin = data[0];
vmax = data[0];
for (int x = 0; x < 336; x++) {
if (data[x] != 0) {
if (data[x] < vmin) {
vmin = data[x];
} else if (data[x] > vmax) {
vmax = data[x];
}
}
}
// calculate y-axis scale
uint16_t diff = vmax - vmin;
if (diff < 20) {
scalestep = 5;
} else if (diff < 40) {
scalestep = 10;
} else {
scalestep = 15;
}
scalemin = vmin - (vmin % scalestep);
scalemax = vmax + scalestep - (vmax % scalestep);
// TODO implement history buffer
};
public:
PageBarograph(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Instantiate PageBarograph");
// Get config data
flashLED = common.config->getString(common.config->flashLED);
useenvsensor = common.config->getString(common.config->useEnvSensor);
// possible values for internal sensor
static std::vector<String> sensorList = {
"BME280", "BMP280", "BMP180", "BMP085", "HTU21", "SHT21"
};
if (std::find(sensorList.begin(), sensorList.end(), useenvsensor) != sensorList.end()) {
source = 'I';
} else {
// "off" means user external data if available
source = 'X';
}
//common.logger->logDebug(GwLog::LOG,"Source=%s (%s)", source, useenvsensor);
loadData(); // initial load
}
virtual int handleKey(int key) {
if (key == 1) {
// zoom in
if (zoomindex > 0) {
zoomindex -= 1;
}
return 0;
}
if (key == 2) {
// zoom out
if (zoomindex < sizeof(zoom)) {
zoomindex += 1;
}
return 0;
}
if (key == 11) {
keylock = !keylock;
return 0;
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwLog *logger=commonData.logger;
// Optical warning by limit violation (unused)
if (String(flashLED) == "Limit Violation") {
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageBarograph");
// Draw page
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Frames
getdisplay().fillRect(0, 75, 400, 2, commonData.fgcolor); // fillRect: x, y, w, h
getdisplay().fillRect(130, 20, 2, 55, commonData.fgcolor);
getdisplay().fillRect(270, 20, 2, 55, commonData.fgcolor);
getdisplay().fillRect(325, 20, 2, 55, commonData.fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if (source == 'I') {
drawTextCenter(360, 40, useenvsensor);
} else {
drawTextCenter(360, 40, "ext.");
}
// Trend
drawTextCenter(295, 62, "0.0");
// Alarm placeholder
drawTextCenter(70, 62, "Alarm Off");
// Zoom
int datastep = series[zoomindex];
String fmt;
if (datastep > 120) {
if (datastep % 60 == 0) {
fmt = String(datastep / 60.0, 0) + " min";
} else {
fmt = String(datastep / 60.0, 1) + " min";
}
} else {
fmt = String(datastep) + " s";
}
drawTextCenter(360, 62, fmt);
// Current measurement
getdisplay().setFont(&Ubuntu_Bold16pt7b);
drawTextCenter(200, 40, String(commonData.data.airPressure / 100, 1));
getdisplay().setFont(&Ubuntu_Bold8pt7b);
drawTextCenter(200, 62, "hPa"); // Unit
// Diagram
const int xstep = 48; // x-axis-grid
const int x0 = 350; // origin
const int y0 = 270;
const int w = 7 * 48;
const int h = 180;
// getdisplay().drawRect(x0 - w, y0 - h, w, h, commonData.fgcolor);
// x-axis are hours
for (int i = 1; i <= 6; i++) {
String label = String(-1 * zoom[zoomindex] * i);
getdisplay().drawLine(x0 - i * xstep, y0, x0 - i * xstep, y0 - h, commonData.fgcolor);
drawTextCenter(x0 - i * xstep, y0 - 10, label);
}
// y-axis
getdisplay().drawLine(x0 + 5, y0, x0 + 5, y0 - h, commonData.fgcolor); // drawLine: x1, y1, x2, y2
getdisplay().drawLine(x0 - w, y0, x0 - w, y0 - h, commonData.fgcolor);
getdisplay().drawLine(x0 - w - 5, y0, x0 - w - 5, y0 - h, commonData.fgcolor);
getdisplay().drawLine(x0, y0, x0, y0 - h, commonData.fgcolor);
int16_t dy = 9; // px for one hPa
int16_t y = y0;
int16_t ys = scalemin;
while (y >= y0 - h) {
if (y % scalestep == 0) {
// big step, show label and long line
getdisplay().setCursor(x0 + 10, y + 5);
getdisplay().print(String(ys));
getdisplay().drawLine(x0 + 5, y, x0 - w - 5, y, commonData.fgcolor);
} else {
// small step, only short lines left and right
getdisplay().drawLine(x0 + 5, y, x0, y, commonData.fgcolor);
getdisplay().drawLine(x0 - w - 5, y, x0 - w, y, commonData.fgcolor);
}
y -= dy;
ys += 1;
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page* createPage(CommonData &common){
return new PageBarograph(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageBarograph(
"Barograph", // Page name
createPage, // Action
0, // No bus values needed
true // Show display header on/off
);
#endif

View File

@@ -1,21 +1,16 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageBattery : public Page
{
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
public:
PageBattery(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery");
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "AVG";
common.logger->logDebug(GwLog::LOG,"Show PageBattery");
}
virtual int handleKey(int key){
@@ -28,15 +23,15 @@ class PageBattery : public Page
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
double value1 = 0;
@@ -63,19 +58,19 @@ class PageBattery : public Page
// Switch average values
switch (average) {
case 0:
value1 = commonData->data.batteryVoltage; // Live data
value1 = commonData.data.batteryVoltage; // Live data
break;
case 1:
value1 = commonData->data.batteryVoltage10; // Average 10s
value1 = commonData.data.batteryVoltage10; // Average 10s
break;
case 2:
value1 = commonData->data.batteryVoltage60; // Average 60s
value1 = commonData.data.batteryVoltage60; // Average 60s
break;
case 3:
value1 = commonData->data.batteryVoltage300; // Average 300s
value1 = commonData.data.batteryVoltage300; // Average 300s
break;
default:
value1 = commonData->data.batteryVoltage; // Default
value1 = commonData.data.batteryVoltage; // Default
break;
}
}
@@ -92,19 +87,19 @@ class PageBattery : public Page
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
switch (average) {
case 0:
value2 = commonData->data.batteryCurrent; // Live data
value2 = commonData.data.batteryCurrent; // Live data
break;
case 1:
value2 = commonData->data.batteryCurrent10; // Average 10s
value2 = commonData.data.batteryCurrent10; // Average 10s
break;
case 2:
value2 = commonData->data.batteryCurrent60; // Average 60s
value2 = commonData.data.batteryCurrent60; // Average 60s
break;
case 3:
value2 = commonData->data.batteryCurrent300; // Average 300s
value2 = commonData.data.batteryCurrent300; // Average 300s
break;
default:
value2 = commonData->data.batteryCurrent; // Default
value2 = commonData.data.batteryCurrent; // Default
break;
}
}
@@ -121,19 +116,19 @@ class PageBattery : public Page
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
switch (average) {
case 0:
value3 = commonData->data.batteryPower; // Live data
value3 = commonData.data.batteryPower; // Live data
break;
case 1:
value3 = commonData->data.batteryPower10; // Average 10s
value3 = commonData.data.batteryPower10; // Average 10s
break;
case 2:
value3 = commonData->data.batteryPower60; // Average 60s
value3 = commonData.data.batteryPower60; // Average 60s
break;
case 3:
value3 = commonData->data.batteryPower300; // Average 300s
value3 = commonData.data.batteryPower300; // Average 300s
break;
default:
value3 = commonData->data.batteryPower; // Default
value3 = commonData.data.batteryPower; // Default
break;
}
}
@@ -161,8 +156,8 @@ class PageBattery : public Page
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show average settings
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
switch (average) {
case 0:
getdisplay().setCursor(60, 90);
@@ -209,12 +204,12 @@ class PageBattery : public Page
// ############### Value 1 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Value name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
getdisplay().print(unit1); // Unit
@@ -233,17 +228,17 @@ class PageBattery : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
// ############### Value 2 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Value name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
getdisplay().print(unit2); // Unit
@@ -262,17 +257,17 @@ class PageBattery : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
// ############### Value 3 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 235);
getdisplay().print(name3); // Value name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 270);
getdisplay().print(unit3); // Unit
@@ -288,6 +283,26 @@ class PageBattery : public Page
getdisplay().print("---"); // No sensor data (sensor is off)
}
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
@@ -7,21 +7,15 @@
class PageBattery2 : public Page
{
bool init = false; // Marker for init done
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
bool trend = true; // Trend indicator [0|1], 0=off, 1=on
double raw = 0;
public:
PageBattery2(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery2");
common.logger->logDebug(GwLog::LOG,"Show PageBattery2");
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "AVG";
}
virtual int handleKey(int key){
// Change average
if(key == 1){
@@ -38,16 +32,16 @@ public:
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData)
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Polynominal coefficients second order for battery energy level calculation
// index 0 = Pb, 1 = Gel, 2 = AGM, 3 = LiFePo4
@@ -77,42 +71,42 @@ public:
// Create trend value
if(init == false){ // Load start values for first page run
valueTrend = commonData->data.batteryVoltage10;
valueTrend = commonData.data.batteryVoltage10;
init = true;
}
else{ // Reading trend value
valueTrend = commonData->data.batteryVoltage10;
valueTrend = commonData.data.batteryVoltage10;
}
// Get raw value for trend indicator
raw = commonData->data.batteryVoltage; // Live data
raw = commonData.data.batteryVoltage; // Live data
// Switch average values
switch (average) {
case 0:
value1 = commonData->data.batteryVoltage; // Live data
value2 = commonData->data.batteryCurrent;
value3 = commonData->data.batteryPower;
value1 = commonData.data.batteryVoltage; // Live data
value2 = commonData.data.batteryCurrent;
value3 = commonData.data.batteryPower;
break;
case 1:
value1 = commonData->data.batteryVoltage10; // Average 10s
value2 = commonData->data.batteryCurrent10;
value3 = commonData->data.batteryPower10;
value1 = commonData.data.batteryVoltage10; // Average 10s
value2 = commonData.data.batteryCurrent10;
value3 = commonData.data.batteryPower10;
break;
case 2:
value1 = commonData->data.batteryVoltage60; // Average 60s
value2 = commonData->data.batteryCurrent60;
value3 = commonData->data.batteryPower60;
value1 = commonData.data.batteryVoltage60; // Average 60s
value2 = commonData.data.batteryCurrent60;
value3 = commonData.data.batteryPower60;
break;
case 3:
value1 = commonData->data.batteryVoltage300; // Average 300s
value2 = commonData->data.batteryCurrent300;
value3 = commonData->data.batteryPower300;
value1 = commonData.data.batteryVoltage300; // Average 300s
value2 = commonData.data.batteryCurrent300;
value3 = commonData.data.batteryPower300;
break;
default:
value1 = commonData->data.batteryVoltage; // Default
value2 = commonData->data.batteryCurrent;
value3 = commonData->data.batteryPower;
value1 = commonData.data.batteryVoltage; // Default
value2 = commonData.data.batteryCurrent;
value3 = commonData.data.batteryPower;
break;
}
bool valid1 = true;
@@ -186,15 +180,15 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print("Bat.");
// Show battery type
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(90, 65);
getdisplay().print(batType);
@@ -205,7 +199,7 @@ public:
if(String(batVoltage) == "12V") bvoltage = 12;
else bvoltage = 24;
getdisplay().print(bvoltage);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show battery capacity
@@ -213,22 +207,22 @@ public:
getdisplay().setCursor(10, 200);
if(batCapacity <= 999) getdisplay().print(batCapacity, 0);
if(batCapacity > 999) getdisplay().print(float(batCapacity/1000.0), 1);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
if(batCapacity <= 999) getdisplay().print("Ah");
if(batCapacity > 999) getdisplay().print("kAh");
// Show info
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 235);
getdisplay().print("Installed");
getdisplay().setCursor(10, 255);
getdisplay().print("Battery Type");
// Show battery with fill level
batteryGraphic(150, 45, batPercentage, commonData->fgcolor, commonData->bgcolor);
batteryGraphic(150, 45, batPercentage, commonData.fgcolor, commonData.bgcolor);
// Show average settings
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(150, 145);
switch (average) {
case 0:
@@ -252,7 +246,7 @@ public:
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 200);
getdisplay().print(batPercentage);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("%");
// Show time to full discharge
@@ -263,12 +257,12 @@ public:
else getdisplay().print(batRange, 0);
}
else getdisplay().print("--");
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("h");
// Show sensor type info
String i2cAddr = "";
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(270, 60);
if(powerSensor == "off") getdisplay().print("Internal");
if(powerSensor == "INA219"){
@@ -307,7 +301,7 @@ public:
getdisplay().print("---"); // Missing bus data
}
}
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show actual current in A
@@ -319,7 +313,7 @@ public:
if(value2 > 99.9) getdisplay().print(value2, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("A");
// Show actual consumption in W
@@ -331,9 +325,26 @@ public:
if(value3 > 99.9) getdisplay().print(value3, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W");
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};

View File

@@ -1,82 +1,19 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
/*
* TODO mode: race timer: keys
* - prepare: set countdown to 5min
* reset: abort current countdown and start over with 5min preparation
* - 5min: key press
* - 4min: key press to sync
* - 1min: buzzer signal
* - start: buzzer signal for start
*
*/
class PageClock : public Page
{
bool simulation = false;
int simtime;
bool keylock = false;
char source = 'R'; // time source (R)TC | (G)PS | (N)TP
char mode = 'A'; // display mode (A)nalog | (D)igital | race (T)imer
char tz = 'L'; // time zone (L)ocal | (U)TC
double timezone = 0; // there are timezones with non int offsets, e.g. 5.5 or 5.75
double homelat;
double homelon;
bool homevalid = false; // homelat and homelon are valid
bool keylock = false; // Keylock
public:
public:
PageClock(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageClock");
simulation = common.config->getBool(common.config->useSimuData);
timezone = common.config->getString(common.config->timeZone).toDouble();
homelat = common.config->getString(common.config->homeLAT).toDouble();
homelon = common.config->getString(common.config->homeLON).toDouble();
homevalid = homelat >= -180.0 and homelat <= 180 and homelon >= -90.0 and homelon <= 90.0;
simtime = 38160; // time value 11:36
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "SRC";
commonData->keydata[1].label = "MODE";
commonData->keydata[4].label = "TZ";
common.logger->logDebug(GwLog::LOG,"Show PageClock");
}
// Key functions
virtual int handleKey(int key){
// Time source
if (key == 1) {
if (source == 'G') {
source = 'R';
} else {
source = 'G';
}
return 0;
}
if (key == 2) {
if (mode == 'A') {
mode = 'D';
} else if (mode == 'D') {
mode = 'T';
} else {
mode = 'A';
}
return 0;
}
// Time zone: Local / UTC
if (key == 5) {
if (tz == 'L') {
tz = 'U';
} else {
tz = 'L';
}
return 0;
}
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
@@ -85,10 +22,10 @@ bool homevalid = false; // homelat and homelon are valid
return key;
}
virtual void displayPage(PageData &pageData)
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
@@ -106,10 +43,12 @@ bool homevalid = false; // homelat and homelon are valid
// Get config data
String lengthformat = config->getString(config->lengthFormat);
String dateformat = config->getString(config->dateFormat);
bool simulation = config->getBool(config->useSimuData);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
String stimezone = config->getString(config->timeZone);
double timezone = stimezone.toDouble();
// Get boat values for GPS time
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
@@ -119,13 +58,13 @@ bool homevalid = false; // homelat and homelon are valid
value1 = bvalue1->value; // Value as double in SI unit
}
else{
value1 = simtime++; // Simulation data for time value 11:36 in seconds
value1 = 38160; // Simulation data for time value 11:36 in seconds
} // Other simulation data see OBP60Formater.cpp
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
if(valid1 == true){
svalue1old = svalue1; // Save old value
svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit
}
@@ -135,10 +74,10 @@ bool homevalid = false; // homelat and homelon are valid
name2 = name2.substring(0, 6); // String length limit for value name
value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
if(valid2 == true){
svalue2old = svalue2; // Save old value
svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit
}
@@ -148,17 +87,17 @@ bool homevalid = false; // homelat and homelon are valid
name3 = name3.substring(0, 6); // String length limit for value name
value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
if(valid3 == true){
svalue3old = svalue3; // Save old value
svalue3old = svalue3; // Save old value
unit3old = unit3; // Save old unit
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
setFlashLED(false);
}
// Logging boat values
@@ -171,109 +110,70 @@ bool homevalid = false; // homelat and homelon are valid
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
time_t tv = mktime(&commonData->data.rtcTime) + timezone * 3600;
struct tm *local_tm = localtime(&tv);
getdisplay().setTextColor(commonData.fgcolor);
// Show values GPS date
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 65);
if (holdvalues == false) {
if (source == 'G') {
// GPS value
getdisplay().print(svalue2);
} else if (commonData->data.rtcValid) {
// RTC value
if (tz == 'L') {
getdisplay().print(formatDate(dateformat, local_tm->tm_year + 1900, local_tm->tm_mon + 1, local_tm->tm_mday));
}
else {
getdisplay().print(formatDate(dateformat, commonData->data.rtcTime.tm_year + 1900, commonData->data.rtcTime.tm_mon + 1, commonData->data.rtcTime.tm_mday));
}
} else {
getdisplay().print("---");
}
} else {
getdisplay().print(svalue2old);
}
getdisplay().setFont(&Ubuntu_Bold12pt8b);
if(holdvalues == false) getdisplay().print(svalue2); // Value
else getdisplay().print(svalue2old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 95);
getdisplay().print("Date"); // Name
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
// Show values GPS time
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 250);
if (holdvalues == false) {
if (source == 'G') {
getdisplay().print(svalue1); // Value
}
else if (commonData->data.rtcValid) {
if (tz == 'L') {
getdisplay().print(formatTime('s', local_tm->tm_hour, local_tm->tm_min, local_tm->tm_sec));
}
else {
getdisplay().print(formatTime('s', commonData->data.rtcTime.tm_hour, commonData->data.rtcTime.tm_min, commonData->data.rtcTime.tm_sec));
}
} else {
getdisplay().print("---");
}
}
else {
getdisplay().print(svalue1old);
}
getdisplay().setFont(&Ubuntu_Bold12pt8b);
if(holdvalues == false) getdisplay().print(svalue1); // Value
else getdisplay().print(svalue1old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 220);
getdisplay().print("Time"); // Name
// Show values sunrise
String sunrise = "---";
if ((valid1 and valid2 and valid3 == true) or (homevalid and commonData->data.rtcValid)) {
sunrise = String(commonData->sundata.sunriseHour) + ":" + String(commonData->sundata.sunriseMinute + 100).substring(1);
if(valid1 == true && valid2 == true && valid3 == true){
sunrise = String(commonData.sundata.sunriseHour) + ":" + String(commonData.sundata.sunriseMinute + 100).substring(1);
svalue5old = sunrise;
} else if (simulation) {
sunrise = String("06:42");
}
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 65);
if(holdvalues == false) getdisplay().print(sunrise); // Value
else getdisplay().print(svalue5old);
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 95);
getdisplay().print("SunR"); // Name
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
// Show values sunset
String sunset = "---";
if ((valid1 and valid2 and valid3 == true) or (homevalid and commonData->data.rtcValid)) {
sunset = String(commonData->sundata.sunsetHour) + ":" + String(commonData->sundata.sunsetMinute + 100).substring(1);
if(valid1 == true && valid2 == true && valid3 == true){
sunset = String(commonData.sundata.sunsetHour) + ":" + String(commonData.sundata.sunsetMinute + 100).substring(1);
svalue6old = sunset;
} else if (simulation) {
sunset = String("21:03");
}
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 250);
if(holdvalues == false) getdisplay().print(sunset); // Value
else getdisplay().print(svalue6old);
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 220);
getdisplay().print("SunS"); // Name
//*******************************************************************************************
// Draw clock
int rInstrument = 110; // Radius of clock
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle
for(int i=0; i<360; i=i+1)
{
@@ -304,7 +204,7 @@ bool homevalid = false; // homelat and homelon are valid
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().print(ii);
}
@@ -314,7 +214,7 @@ bool homevalid = false; // homelat and homelon are valid
if(i % 6 == 0){
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
sinx=sin(i/180.0*pi);
cosx=cos(i/180.0*pi);
}
@@ -328,63 +228,38 @@ bool homevalid = false; // homelat and homelon are valid
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
}
}
// Print Unit in clock
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
if(holdvalues == false){
getdisplay().print(tz == 'L' ? "LOT" : "UTC");
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(unit2old); // date unit
}
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(185, 190);
if (source == 'G') {
getdisplay().print("GPS");
} else {
getdisplay().print("RTC");
getdisplay().print(unit2old); // Unit
}
// Clock values
double hour = 0;
double minute = 0;
if (source == 'R') {
if (tz == 'L') {
time_t tv = mktime(&commonData->data.rtcTime) + timezone * 3600;
struct tm *local_tm = localtime(&tv);
minute = local_tm->tm_min;
hour = local_tm->tm_hour;
} else {
minute = commonData->data.rtcTime.tm_min;
hour = commonData->data.rtcTime.tm_hour;
}
hour += minute / 60;
} else {
if (tz == 'L') {
value1 += timezone * 3600;
}
if (value1 > 86400) {value1 -= 86400;}
if (value1 < 0) {value1 += 86400;}
hour = (value1 / 3600.0);
// minute = (hour - int(hour)) * 3600.0 / 60.0; // Analog minute pointer smooth moving
minute = int((hour - int(hour)) * 3600.0 / 60.0); // Jumping minute pointer from minute to minute
}
if (hour > 12) {
hour -= 12.0;
}
value1 = value1 + int(timezone*3600);
if (value1 > 86400) {value1 = value1 - 86400;}
if (value1 < 0) {value1 = value1 + 86400;}
hour = (value1 / 3600.0);
if(hour > 12) hour = hour - 12.0;
// minute = (hour - int(hour)) * 3600.0 / 60.0; // Analog minute pointer smooth moving
minute = int((hour - int(hour)) * 3600.0 / 60.0); // Jumping minute pointer from minute to minute
LOG_DEBUG(GwLog::DEBUG,"... PageClock, value1: %f hour: %f minute:%f", value1, hour, minute);
// Draw hour pointer
float startwidth = 8; // Start width of pointer
if(valid1 == true || (source == 'R' && commonData->data.rtcValid) || holdvalues == true || simulation == true){
if(valid1 == true || holdvalues == true || simulation == true){
float sinx=sin(hour * 30.0 * pi / 180); // Hour
float cosx=cos(hour * 30.0 * pi / 180);
// Normal pointer
@@ -392,10 +267,10 @@ bool homevalid = false; // homelat and homelon are valid
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument * 0.5);
float yy2 = -(rInstrument * 0.5);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -405,12 +280,12 @@ bool homevalid = false; // homelat and homelon are valid
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
}
// Draw minute pointer
startwidth = 8; // Start width of pointer
if(valid1 == true || (source == 'R' && commonData->data.rtcValid) || holdvalues == true || simulation == true){
if(valid1 == true || holdvalues == true || simulation == true){
float sinx=sin(minute * 6.0 * pi / 180); // Minute
float cosx=cos(minute * 6.0 * pi / 180);
// Normal pointer
@@ -418,10 +293,10 @@ bool homevalid = false; // homelat and homelon are valid
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument - 15);
float yy2 = -(rInstrument - 15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -431,12 +306,28 @@ bool homevalid = false; // homelat and homelon are valid
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,261 +0,0 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
// these constants have to match the declaration below in :
// PageDescription registerPageCompass(
// {"COG","HDT", "HDM"}, // Bus values we need in the page
const int HowManyValues = 6;
const int AverageValues = 4;
const int ShowHDM = 0;
const int ShowHDT = 1;
const int ShowCOG = 2;
const int ShowSTW = 3;
const int ShowSOG = 4;
const int ShowDBS = 5;
const int Compass_X0 = 200; // center point of compass band
const int Compass_Y0 = 220; // position of compass lines
const int Compass_LineLength = 22; // length of compass lines
const float Compass_LineDelta = 8.0;// compass band: 1deg = 5 Pixels, 10deg = 50 Pixels
class PageCompass : public Page
{
int WhichDataCompass = ShowHDM;
int WhichDataDisplay = ShowHDM;
public:
PageCompass(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageCompass");
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "CMP";
commonData->keydata[1].label = "SRC";
}
virtual int handleKey(int key){
// Code for keylock
if ( key == 1 ) {
WhichDataCompass += 1;
if ( WhichDataCompass > ShowCOG)
WhichDataCompass = ShowHDM;
return 0;
}
if ( key == 2 ) {
WhichDataDisplay += 1;
if ( WhichDataDisplay > ShowDBS)
WhichDataDisplay = ShowHDM;
}
if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Old values for hold function
static String OldDataText[HowManyValues] = {"", "", "","", "", ""};
static String OldDataUnits[HowManyValues] = {"", "", "","", "", ""};
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
GwApi::BoatValue *bvalue;
String DataName[HowManyValues];
double DataValue[HowManyValues];
bool DataValid[HowManyValues];
String DataText[HowManyValues];
String DataUnits[HowManyValues];
String DataFormat[HowManyValues];
FormatedData TheFormattedData;
for (int i = 0; i < HowManyValues; i++){
bvalue = pageData.values[i];
TheFormattedData = formatValue(bvalue, *commonData);
DataName[i] = xdrDelete(bvalue->getName());
DataName[i] = DataName[i].substring(0, 6); // String length limit for value name
DataUnits[i] = formatValue(bvalue, *commonData).unit;
DataText[i] = TheFormattedData.svalue; // Formatted value as string including unit conversion and switching decimal places
DataValue[i] = TheFormattedData.value; // Value as double in SI unit
DataValid[i] = bvalue->valid;
DataFormat[i] = bvalue->getFormat(); // Unit of value
LOG_DEBUG(GwLog::LOG,"Drawing at PageCompass: %d %s %f %s %s", i, DataName[i], DataValue[i], DataFormat[i], DataText[i] );
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
if (bvalue == NULL) return;
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
// Horizontal line 2 pix top & bottom
// Print data on top half
getdisplay().fillRect(0, 130, 400, 2, commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setCursor(10, 70);
getdisplay().print(DataName[WhichDataDisplay]); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(10, 120);
getdisplay().print(DataUnits[WhichDataDisplay]);
getdisplay().setCursor(190, 120);
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
if(holdvalues == false){
getdisplay().print(DataText[WhichDataDisplay]); // Real value as formated string
}
else{
getdisplay().print(OldDataText[WhichDataDisplay]); // Old value as formated string
}
if(DataValid[WhichDataDisplay] == true){
OldDataText[WhichDataDisplay] = DataText[WhichDataDisplay]; // Save the old value
OldDataUnits[WhichDataDisplay] = DataUnits[WhichDataDisplay]; // Save the old unit
}
// Now draw compass band
// Get the data
double TheAngle = DataValue[WhichDataCompass];
static double AvgAngle = 0;
AvgAngle = ( AvgAngle * AverageValues + TheAngle ) / (AverageValues + 1 );
int TheTrend = round( ( TheAngle - AvgAngle) * 180.0 / M_PI );
static const int bsize = 30;
char buffer[bsize+1];
buffer[0]=0;
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setCursor(10, Compass_Y0-60);
getdisplay().print(DataName[WhichDataCompass]); // Page name
// Draw compass base line and pointer
getdisplay().fillRect(0, Compass_Y0, 400, 3, commonData->fgcolor);
getdisplay().fillTriangle(Compass_X0,Compass_Y0-40,Compass_X0-10,Compass_Y0-80,Compass_X0+10,Compass_Y0-80,commonData->fgcolor);
// Draw trendlines
for ( int i = 1; i < abs(TheTrend) / 2; i++){
int x1;
if ( TheTrend < 0 )
x1 = Compass_X0 + 20 * i;
else
x1 = Compass_X0 - 20 * ( i + 1 );
getdisplay().fillRect(x1, Compass_Y0 -55, 10, 6, commonData->fgcolor);
}
// Central line + satellite lines
double NextSector = round(TheAngle / ( M_PI / 9 )) * ( M_PI / 9 ); // Get the next 20degree value
double Offset = - ( NextSector - TheAngle); // Offest of the center line compared to TheAngle in Radian
int Delta_X = int ( Offset * 180.0 / M_PI * Compass_LineDelta );
for ( int i = 0; i <=4; i++ ){
int x0;
x0 = Compass_X0 + Delta_X + 2 * i * 5 * Compass_LineDelta;
getdisplay().fillRect(x0-2, Compass_Y0 - 2 * Compass_LineLength, 5, 2 * Compass_LineLength, commonData->fgcolor);
x0 = Compass_X0 + Delta_X + ( 2 * i + 1 ) * 5 * Compass_LineDelta;
getdisplay().fillRect(x0-1, Compass_Y0 - Compass_LineLength, 3, Compass_LineLength, commonData->fgcolor);
x0 = Compass_X0 + Delta_X - 2 * i * 5 * Compass_LineDelta;
getdisplay().fillRect(x0-2, Compass_Y0 - 2 * Compass_LineLength, 5, 2 * Compass_LineLength, commonData->fgcolor);
x0 = Compass_X0 + Delta_X - ( 2 * i + 1 ) * 5 * Compass_LineDelta;
getdisplay().fillRect(x0-1, Compass_Y0 - Compass_LineLength, 3, Compass_LineLength, commonData->fgcolor);
}
getdisplay().fillRect(0, Compass_Y0, 400, 3, commonData->fgcolor);
// Add the numbers to the compass band
int x0;
float AngleToDisplay = NextSector * 180.0 / M_PI;
x0 = Compass_X0 + Delta_X;
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
do {
getdisplay().setCursor(x0 - 40, Compass_Y0 + 40);
snprintf(buffer,bsize,"%03.0f", AngleToDisplay);
getdisplay().print(buffer);
AngleToDisplay += 20;
if ( AngleToDisplay >= 360.0 )
AngleToDisplay -= 360.0;
x0 -= 4 * 5 * Compass_LineDelta;
} while ( x0 >= 0 - 60 );
AngleToDisplay = NextSector * 180.0 / M_PI - 20;
if ( AngleToDisplay < 0 )
AngleToDisplay += 360.0;
x0 = Compass_X0 + Delta_X + 4 * 5 * Compass_LineDelta;
do {
getdisplay().setCursor(x0 - 40, Compass_Y0 + 40);
snprintf(buffer,bsize,"%03.0f", AngleToDisplay);
// Quick and dirty way to prevent wrapping text in next line
if ( ( x0 - 40 ) > 380 )
buffer[0] = 0;
else if ( ( x0 - 40 ) > 355 )
buffer[1] = 0;
else if ( ( x0 - 40 ) > 325 )
buffer[2] = 0;
getdisplay().print(buffer);
AngleToDisplay -= 20;
if ( AngleToDisplay < 0 )
AngleToDisplay += 360.0;
x0 += 4 * 5 * Compass_LineDelta;
} while (x0 < ( 400 - 20 -40 ) );
// static int x_test = 320;
// x_test += 2;
// snprintf(buffer,bsize,"%03d", x_test);
// getdisplay().setCursor(x_test, Compass_Y0 - 60);
// getdisplay().print(buffer);
// if ( x_test > 390)
// x_test = 320;
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageCompass(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageCompass(
"Compass", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"HDM","HDT", "COG", "STW", "SOG", "DBS"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,28 +1,28 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageDST810 : public Page
{
public:
bool keylock = false; // Keylock
public:
PageDST810(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageDST810");
common.logger->logDebug(GwLog::LOG,"Show PageDST810");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
@@ -47,8 +47,8 @@ public:
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -56,8 +56,8 @@ public:
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -65,8 +65,8 @@ public:
name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
@@ -74,8 +74,8 @@ public:
name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
@@ -93,17 +93,17 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// ############### Value 1 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print("Depth"); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
@@ -131,17 +131,17 @@ public:
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
// ############### Value 2 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print("Speed"); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
@@ -169,17 +169,17 @@ public:
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
// ############### Value 3 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 220);
getdisplay().print("Log"); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 240);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
@@ -207,17 +207,17 @@ public:
// ############### Vertical Line ################
// Vertical line 3 pix
getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor);
// ############### Value 4 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(220, 220);
getdisplay().print("Temp"); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(220, 240);
if(holdvalues == false){
getdisplay().print(unit4); // Unit
@@ -242,6 +242,24 @@ public:
unit4old = unit4; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
@@ -22,6 +22,43 @@ TODO
*/
struct Point {
double x;
double y;
};
Point rotatePoint(const Point& origin, const Point& p, double angle) {
// rotate poind around origin by degrees
Point rotated;
double phi = angle * M_PI / 180.0;
double dx = p.x - origin.x;
double dy = p.y - origin.y;
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
return rotated;
}
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
std::vector<Point> rotatedPoints;
for (const auto& p : pts) {
rotatedPoints.push_back(rotatePoint(origin, p, angle));
}
return rotatedPoints;
}
void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
}
void drawTextCentered(int16_t tx, int16_t ty, String text) {
int16_t x, y;
uint16_t w, h;
getdisplay().getTextBounds(text, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(tx - w / 2, ty + h / 2);
getdisplay().print(text);
}
#define fuel_width 16
#define fuel_height 16
static unsigned char fuel_bits[] = {
@@ -57,53 +94,27 @@ static unsigned char gasoline_bits[] = {
0x98, 0xcf, 0x38, 0xe7, 0x78, 0xf0, 0xf8, 0xfa, 0xf8, 0xfa, 0x78, 0xf0,
0x38, 0xe7, 0x98, 0xcf, 0xf8, 0xff, 0xf0, 0x7f };
#define fish_width 16
#define fish_height 16
static unsigned char fish_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xf0, 0x03, 0xf8, 0x37,
0xfc, 0x7f, 0xfc, 0x7f, 0xec, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xf8, 0x37,
0xf0, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00 };
class PageFluid : public Page
{
bool simulation = false;
double simgoto;
double simval;
double simstep;
bool holdvalues = false;
class PageFluid : public Page{
bool keylock = false; // Keylock
int fluidtype;
public:
PageFluid(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageFluid");
simulation = common.config->getBool(common.config->useSimuData);
holdvalues = common.config->getBool(common.config->holdvalues);
simval = double(random(0, 100));
simgoto = double(random(0, 100));
simstep = (simgoto - simval) / 20.0;
common.logger->logDebug(GwLog::LOG,"Show PageFluid");
fluidtype = common.config->getInt("page" + String(common.data.actpage) + "fluid", 0);
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayNew(PageData &pageData){
fluidtype = commonData->config->getInt("page" + String(pageData.pageNumber) + "fluid", 0);
commonData->logger->logDebug(GwLog::LOG,"New PageFluid: fluidtype=%d", fluidtype);
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Old values for hold function
static double value1old;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
String flashLED = config->getString(config->flashLED);
@@ -115,24 +126,13 @@ class PageFluid : public Page
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid");
GwApi::BoatValue *bvalue1 = pageData.values[0];
String name1 = bvalue1->getName();
double fluidlevel = bvalue1->value;
if (!simulation) {
if (holdvalues and bvalue1->valid) {
value1old = bvalue1->value;
}
} else {
fluidlevel = simval;
simval += simstep;
if ((simgoto - simval) < 1.5 * simstep) {
simgoto = double(random(0, 100));
simstep = (simgoto - simval) / 20.0;
}
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid: value=%f", bvalue1->value);
double value1 = bvalue1->value;
bool valid1 = bvalue1->valid;
// Draw page
//***********************************************************
@@ -140,10 +140,10 @@ class PageFluid : public Page
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height());
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// descriptions
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 60);
getdisplay().print("Fluid");
@@ -158,63 +158,57 @@ class PageFluid : public Page
uint8_t r = 110;
// circular frame
getdisplay().drawCircle(c.x, c.y, r+5, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, r+2, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, r-1, commonData->bgcolor);
getdisplay().drawCircle(c.x, c.y, r+5, commonData.fgcolor);
getdisplay().fillCircle(c.x, c.y, r+2, commonData.fgcolor);
getdisplay().fillCircle(c.x, c.y, r-1, commonData.bgcolor);
// center of pointer as dot
getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
// value down centered
char buffer[6];
if (bvalue1->valid or simulation) {
snprintf(buffer, 6, "%3.0f%%", fluidlevel);
if (bvalue1->valid) {
snprintf(buffer, 6, "%3.0f%%", bvalue1->value);
} else {
strcpy(buffer, "---");
}
drawTextCenter(c.x, c.y + r - 20, String(buffer));
drawTextCentered(c.x, c.y + r - 20, String(buffer));
// draw symbol (as bitmap)
switch (fluidtype) {
case 0:
getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData->fgcolor);
getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData.fgcolor);
break;
case 1:
getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData->fgcolor);
break;
case 2: // gray water no symbol yet
// getdisplay().drawXBitmap(c.x-8, c.y-50, gray_bits, gray_width, gray_height, commonData->fgcolor);
break;
case 3:
getdisplay().drawXBitmap(c.x-8, c.y-50, fish_bits, fish_width, fish_height, commonData->fgcolor);
getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData.fgcolor);
break;
case 4:
getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData->fgcolor);
getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData.fgcolor);
break;
case 5:
getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, commonData->fgcolor);
getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, commonData.fgcolor);
break;
case 6:
getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, commonData->fgcolor);
getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, commonData.fgcolor);
break;
}
Point p, pr;
// scale texts
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
p = {c.x, c.y - r + 30};
drawTextCenter(p.x, p.y, "1/2");
drawTextCentered(p.x, p.y, "1/2");
pr = rotatePoint(c, p, -60);
drawTextCenter(pr.x, pr.y, "1/4");
drawTextCentered(pr.x, pr.y, "1/4");
pr = rotatePoint(c, p, 60);
drawTextCenter(pr.x, pr.y, "3/4");
drawTextCentered(pr.x, pr.y, "3/4");
// empty and full
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
p = rotatePoint(c, {c.x, c.y - r + 30}, -130);
drawTextCenter(p.x, p.y, "E");
drawTextCentered(p.x, p.y, "E");
p = rotatePoint(c, {c.x, c.y - r + 30}, 130);
drawTextCenter(p.x, p.y, "F");
drawTextCentered(p.x, p.y, "F");
// lines
std::vector<Point> pts = {
@@ -223,11 +217,11 @@ class PageFluid : public Page
{c.x + 2, c.y - (r - 16)},
{c.x - 2, c.y - (r - 16)}
};
fillPoly4(rotatePoints(c, pts, -120), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, -60), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, 0), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, 60), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, 120), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, -120), commonData.fgcolor);
fillPoly4(rotatePoints(c, pts, -60), commonData.fgcolor);
fillPoly4(rotatePoints(c, pts, 0), commonData.fgcolor);
fillPoly4(rotatePoints(c, pts, 60), commonData.fgcolor);
fillPoly4(rotatePoints(c, pts, 120), commonData.fgcolor);
// dots
// rotate 0 to 360 in 12 degree steps
@@ -236,22 +230,37 @@ class PageFluid : public Page
continue;
}
p = rotatePoint(c, {c.x, c.y - r + 10}, angle);
getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor);
}
// pointer
if (bvalue1->valid or simulation) {
if (bvalue1->valid) {
pts = {
{c.x - 1, c.y - (r - 20)},
{c.x + 1, c.y - (r - 20)},
{c.x + 6, c.y + 15},
{c.x - 6, c.y + 15}
};
fillPoly4(rotatePoints(c, pts, -120 + fluidlevel * 2.4), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, -120 + bvalue1->value * 2.4), commonData.fgcolor);
// Pointer axis is white
getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
}
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 296);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 296);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 296);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,29 +1,28 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageFourValues : public Page
{
bool keylock = false; // Keylock
public:
PageFourValues(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues");
common.logger->logDebug(GwLog::LOG,"Show PageFourValues");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
@@ -46,41 +45,37 @@ class PageFourValues : public Page
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
@@ -98,17 +93,17 @@ class PageFourValues : public Page
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// ############### Value 1 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 45);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 65);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
@@ -119,11 +114,11 @@ class PageFourValues : public Page
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 55);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 58);
}
else{
@@ -146,17 +141,17 @@ class PageFourValues : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 80, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 80, 400, 3, commonData.fgcolor);
// ############### Value 2 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 113);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 133);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
@@ -167,11 +162,11 @@ class PageFourValues : public Page
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 123);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 123);
}
else{
@@ -194,17 +189,17 @@ class PageFourValues : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 146, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 146, 400, 3, commonData.fgcolor);
// ############### Value 3 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 181);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 201);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
@@ -215,11 +210,11 @@ class PageFourValues : public Page
// Switch font if format for any values
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 191);
}
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 191);
}
else{
@@ -242,17 +237,17 @@ class PageFourValues : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 214, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 214, 400, 3, commonData.fgcolor);
// ############### Value 4 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 249);
getdisplay().print(name4); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 269);
if(holdvalues == false){
getdisplay().print(unit4); // Unit
@@ -263,11 +258,11 @@ class PageFourValues : public Page
// Switch font if format for any values
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 259);
}
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 259);
}
else{
@@ -287,6 +282,24 @@ class PageFourValues : public Page
unit4old = unit4; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,29 +1,28 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageFourValues2 : public Page
{
bool keylock = false; // Keylock
public:
PageFourValues2(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues2");
common.logger->logDebug(GwLog::LOG,"Show PageFourValues2");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock; // Toggle keylock
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
@@ -46,41 +45,37 @@ class PageFourValues2 : public Page
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
@@ -98,17 +93,17 @@ class PageFourValues2 : public Page
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// ############### Value 1 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
@@ -119,11 +114,11 @@ class PageFourValues2 : public Page
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(100, 90);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(180, 77);
}
else{
@@ -146,17 +141,17 @@ class PageFourValues2 : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
// ############### Value 2 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
@@ -167,11 +162,11 @@ class PageFourValues2 : public Page
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(100, 180);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(180, 158);
}
else{
@@ -194,17 +189,17 @@ class PageFourValues2 : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
// ############### Value 3 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 220);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 240);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
@@ -215,11 +210,11 @@ class PageFourValues2 : public Page
// Switch font if format for any values
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(50, 240);
}
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(100, 240);
}
else{
@@ -242,17 +237,17 @@ class PageFourValues2 : public Page
// ############### Vertical Line ################
// Vertical line 3 pix
getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor);
// ############### Value 4 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(220, 220);
getdisplay().print(name4); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(220, 240);
if(holdvalues == false){
getdisplay().print(unit4); // Unit
@@ -263,11 +258,11 @@ class PageFourValues2 : public Page
// Switch font if format for any values
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(250, 240);
}
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(300, 240);
}
else{
@@ -287,6 +282,24 @@ class PageFourValues2 : public Page
unit4old = unit4; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
@@ -6,24 +6,26 @@
class PageGenerator : public Page
{
bool init = false; // Marker for init done
bool keylock = false; // Keylock
public:
PageGenerator(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageGenerator");
common.logger->logDebug(GwLog::LOG,"Show PageGenerator");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData)
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
bool simulation = config->getBool(config->useSimuData);
@@ -45,13 +47,13 @@ public:
// Get raw value for trend indicator
if(powerSensor != "off"){
value1 = commonData->data.generatorVoltage; // Use voltage from external sensor
value1 = commonData.data.generatorVoltage; // Use voltage from external sensor
}
else{
value1 = commonData->data.batteryVoltage; // Use internal voltage sensor
value1 = commonData.data.batteryVoltage; // Use internal voltage sensor
}
value2 = commonData->data.generatorCurrent;
value3 = commonData->data.generatorPower;
value2 = commonData.data.generatorCurrent;
value3 = commonData.data.generatorPower;
genPercentage = value3 * 100 / (double)genPower; // Load value
// Limits for battery level
if(genPercentage < 0) genPercentage = 0;
@@ -85,13 +87,13 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print("Power");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(12, 82);
getdisplay().print("Generator");
@@ -102,7 +104,7 @@ public:
if(String(batVoltage) == "12V") bvoltage = 12;
else bvoltage = 24;
getdisplay().print(bvoltage);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show solar power
@@ -110,33 +112,33 @@ public:
getdisplay().setCursor(10, 200);
if(genPower <= 999) getdisplay().print(genPower, 0);
if(genPower > 999) getdisplay().print(float(genPower/1000.0), 1);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
if(genPower <= 999) getdisplay().print("W");
if(genPower > 999) getdisplay().print("kW");
// Show info
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 235);
getdisplay().print("Installed");
getdisplay().setCursor(10, 255);
getdisplay().print("Power Modul");
// Show generator
generatorGraphic(200, 95, commonData->fgcolor, commonData->bgcolor);
generatorGraphic(200, 95, commonData.fgcolor, commonData.bgcolor);
// Show load level in percent
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 200);
getdisplay().print(genPercentage);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("%");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(150, 235);
getdisplay().print("Load");
// Show sensor type info
String i2cAddr = "";
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(270, 60);
if(powerSensor == "off") getdisplay().print("Internal");
if(powerSensor == "INA219"){
@@ -176,7 +178,7 @@ public:
getdisplay().print("---"); // Missing bus data
}
}
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show actual current in A
@@ -188,7 +190,7 @@ public:
if(value2 > 99.9) getdisplay().print(value2, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("A");
// Show actual consumption in W
@@ -200,9 +202,24 @@ public:
if(value3 > 99.9) getdisplay().print(value3, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W");
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};

View File

@@ -1,30 +1,31 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageKeelPosition : public Page
{
bool keylock = false; // Keylock
public:
PageKeelPosition(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageKeelPosition");
common.logger->logDebug(GwLog::LOG,"Show PageKeelPosition");
}
// Key functions
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData)
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
double value1 = 0;
double value1old = 0;
@@ -39,9 +40,9 @@ public:
String rotfunction = config->getString(config->rotFunction);
// Get boat values for Keel position
bool valid1 = commonData->data.validRotAngle; // Valid information
bool valid1 = commonData.data.validRotAngle; // Valid information
if(simulation == false && rotsensor == "AS5600" && rotfunction == "Keel"){
value1 = commonData->data.rotationAngle; // Raw value without unit convertion
value1 = commonData.data.rotationAngle; // Raw value without unit convertion
}
else{
value1 = 0;
@@ -76,9 +77,9 @@ public:
int rInstrument = 110; // Radius of KeelPosition
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, commonData->bgcolor); // Delete half top circle
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor); // Delete half top circle
for(int i=90; i<=270; i=i+10)
{
@@ -109,14 +110,14 @@ public:
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
@@ -129,10 +130,10 @@ public:
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
}
}
@@ -166,7 +167,7 @@ public:
float yy2 = -(rInstrument * 0.6);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -176,36 +177,52 @@ public:
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
// Draw counterweight
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor);
}
// Center circle
getdisplay().fillCircle(200, 140, startwidth + 22, commonData->bgcolor);
getdisplay().fillCircle(200, 140, startwidth + 20, commonData->fgcolor); // Boat circle
getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData->bgcolor); // Delete half top of boat circle
getdisplay().fillRect(150, 150, 100, 4, commonData->fgcolor); // Water line
getdisplay().fillCircle(200, 140, startwidth + 22, commonData.bgcolor);
getdisplay().fillCircle(200, 140, startwidth + 20, commonData.fgcolor); // Boat circle
getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData.bgcolor); // Delete half top of boat circle
getdisplay().fillRect(150, 150, 100, 4, commonData.fgcolor); // Water line
// Print label
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(100, 70);
getdisplay().print("Keel Position"); // Label
if((rotsensor == "AS5600" && rotfunction == "Keel" && (valid1 == true || holdvalues == true)) || simulation == true){
// Print Unit of keel position
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit1); // Unit
}
else{
// Print Unit of keel position
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(145, 110);
getdisplay().print("No sensor data"); // Info missing sensor
}
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,29 +1,27 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageOneValue : public Page
{
class PageOneValue : public Page{
bool keylock = false; // Keylock
public:
PageOneValue(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageOneValue");
common.logger->logDebug(GwLog::LOG,"Show PageOneValue");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
@@ -40,11 +38,10 @@ class PageOneValue : public Page
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
@@ -63,13 +60,13 @@ class PageOneValue : public Page
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold32pt8b);
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(270, 100);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
@@ -80,11 +77,11 @@ class PageOneValue : public Page
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 180);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold32pt8b);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 200);
}
else{
@@ -104,6 +101,21 @@ class PageOneValue : public Page
unit1old = unit1; // Save the old unit
}
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,29 +1,31 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageRollPitch : public Page
{
bool keylock = false; // Keylock
public:
PageRollPitch(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageRollPitch");
common.logger->logDebug(GwLog::LOG,"Show PageRollPitch");
}
// Key functions
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
double value1 = 0;
double value2 = 0;
@@ -118,7 +120,7 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// Show roll limit
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -126,40 +128,40 @@ public:
getdisplay().print(rolllimit); // Value
//getdisplay().print(svalue1); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 95);
getdisplay().print("Limit"); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 115);
getdisplay().print("DEG");
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
// Show roll value
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 270);
if(holdvalues == false) getdisplay().print(svalue1); // Value
else getdisplay().print(svalue1old);
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 220);
getdisplay().print(name1); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 190);
getdisplay().print("Deg");
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
// Show pitch value
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 270);
if(holdvalues == false) getdisplay().print(svalue2); // Value
else getdisplay().print(svalue2old);
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 220);
getdisplay().print(name2); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 190);
getdisplay().print("Deg");
@@ -169,8 +171,8 @@ public:
int rInstrument = 100; // Radius of instrument
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle
for(int i=0; i<360; i=i+10)
{
@@ -198,14 +200,14 @@ public:
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 20 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
@@ -218,10 +220,10 @@ public:
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
}
}
}
@@ -242,7 +244,7 @@ public:
float yy2 = -(rInstrument * 0.7);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -252,26 +254,26 @@ public:
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
// Draw counterweight
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 22, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 20, commonData->fgcolor); // Boat circle
getdisplay().fillCircle(200, 150, startwidth + 22, commonData.bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 20, commonData.fgcolor); // Boat circle
int x0 = 200;
int y0 = 150;
int x1 = x0 + 50*cos(value1);
int y1 = y0 + 50*sin(value1);
int x2 = x0 + 50*cos(value1 - pi/2);
int y2 = y0 + 50*sin(value1 - pi/2);
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor); // Clear half top side of boat circle (right triangle)
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor); // Clear half top side of boat circle (right triangle)
x1 = x0 + 50*cos(value1 + pi);
y1 = y0 + 50*sin(value1 + pi);
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor); // Clear half top side of boat circle (left triangle)
getdisplay().fillRect(150, 160, 100, 4, commonData->fgcolor); // Water line
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor); // Clear half top side of boat circle (left triangle)
getdisplay().fillRect(150, 160, 100, 4, commonData.fgcolor); // Water line
// Draw roll pointer
startwidth = 4; // Start width of pointer
@@ -286,7 +288,7 @@ public:
float yy2 = -(rInstrument - 15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -296,15 +298,31 @@ public:
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
}
else{
// Print sensor info
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(145, 200);
getdisplay().print("No sensor data"); // Info missing sensor
}
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
@@ -324,9 +342,9 @@ static Page *createPage(CommonData &common){
PageDescription registerPageRollPitch(
"RollPitch", // Page name
createPage, // Action
2, // Number of bus values depends on selection in Web configuration
0, // Number of bus values depends on selection in Web configuration
// {"xdrROLL", "xdrPTCH"},// Bus values we need in the page
//{"xdrRoll", "xdrPitch"},// Bus values we need in the page
{"xdrRoll", "xdrPitch"},// Bus values we need in the page
true // Show display header on/off
);

View File

@@ -1,30 +1,31 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageRudderPosition : public Page
{
bool keylock = false; // Keylock
public:
PageRudderPosition(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Show PageRudderPosition");
}
// Key functions
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String unit1old = "";
double value1 = 0.1;
@@ -41,25 +42,24 @@ public:
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
value1 = bvalue1->value; // Raw value without unit convertion
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
if(valid1 == true){
value1old = value1; // Save old value
unit1old = unit1; // Save old unit
} else {
if(simulation == true){
value1 = (3 + float(random(0, 50)) / 10.0)/360*2*PI;
unit1 = "Deg";
}
else{
value1 = 0;
}
}
if(simulation == true){
value1 = (3 + float(random(0, 50)) / 10.0)/360*2*PI;
unit1 = "Deg";
}
else{
value1 = 0;
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
@@ -82,9 +82,9 @@ public:
int rInstrument = 110; // Radius of RudderPosition
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, commonData->bgcolor); // Delete half top circle
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor); // Delete half top circle
for(int i=90; i<=270; i=i+10)
{
@@ -115,14 +115,14 @@ public:
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
@@ -135,35 +135,35 @@ public:
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
}
}
// Print label
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(80, 70);
getdisplay().print("Rudder Position"); // Label
// Print Unit in RudderPosition
if(valid1 == true || simulation == true){
if(holdvalues == false){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit1); // Unit
}
else{
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit1old); // Unit
}
}
else{
// Print Unit of keel position
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(145, 110);
getdisplay().print("No sensor data"); // Info missing sensor
}
@@ -190,7 +190,7 @@ public:
float yy2 = -(rInstrument * 0.5);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -200,12 +200,28 @@ public:
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,174 +0,0 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
const int SixValues_x1 = 5;
const int SixValues_DeltaX = 200;
const int SixValues_y1 = 23;
const int SixValues_DeltaY = 83;
const int HowManyValues = 6;
class PageSixValues : public Page
{
public:
PageSixValues(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageSixValues");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Old values for hold function
static String OldDataText[HowManyValues] = {"", "", "", "", "", ""};
static String OldDataUnits[HowManyValues] = {"", "", "", "", "", ""};
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
GwApi::BoatValue *bvalue;
String DataName[HowManyValues];
double DataValue[HowManyValues];
bool DataValid[HowManyValues];
String DataText[HowManyValues];
String DataUnits[HowManyValues];
String DataFormat[HowManyValues];
for (int i = 0; i < HowManyValues; i++){
bvalue = pageData.values[i];
DataName[i] = xdrDelete(bvalue->getName());
DataName[i] = DataName[i].substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated
DataValue[i] = bvalue->value; // Value as double in SI unit
DataValid[i] = bvalue->valid;
DataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
DataUnits[i] = formatValue(bvalue, *commonData).unit;
DataFormat[i] = bvalue->getFormat(); // Unit of value
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
if (bvalue == NULL) return;
// Draw page
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
for (int i = 0; i < ( HowManyValues / 2 ); i++){
if (i < (HowManyValues / 2) - 1) { // Don't draw horizontal line after last line of values -> standard design
// Horizontal line 3 pix
getdisplay().fillRect(0, SixValues_y1+(i+1)*SixValues_DeltaY, 400, 3, commonData->fgcolor);
}
for (int j = 0; j < 2; j++){
int ValueIndex = i * 2 + j;
int x0 = SixValues_x1 + j * SixValues_DeltaX;
int y0 = SixValues_y1 + i * SixValues_DeltaY;
LOG_DEBUG(GwLog::LOG,"Drawing at PageSixValue: %d %s %f %s", ValueIndex, DataName[ValueIndex], DataValue[ValueIndex], DataFormat[ValueIndex] );
// Show name
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(x0, y0+25);
getdisplay().print(DataName[ValueIndex]); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(x0, y0+72);
if(holdvalues == false){
getdisplay().print(DataUnits[ValueIndex]); // Unit
}
else{
getdisplay().print(OldDataUnits[ValueIndex]);
}
// Switch font if format for any values
if(DataFormat[ValueIndex] == "formatLatitude" || DataFormat[ValueIndex] == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(x0+10, y0+60);
}
else if(DataFormat[ValueIndex] == "formatTime" || DataFormat[ValueIndex] == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setCursor(x0+20,y0+55);
}
// pressure in hPa
else if(DataFormat[ValueIndex] == "formatXdr:P:P"){
getdisplay().setFont(&DSEG7Classic_BoldItalic26pt7b);
getdisplay().setCursor(x0+5, y0+70);
}
// RPM
else if(DataFormat[ValueIndex] == "formatXdr:T:R"){
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(x0+25, y0+70);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic26pt7b);
if ( DataText[ValueIndex][0] == '-' )
getdisplay().setCursor(x0+25, y0+70);
else
getdisplay().setCursor(x0+65, y0+70);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(DataText[ValueIndex]); // Real value as formated string
}
else{
getdisplay().print(OldDataText[ValueIndex]); // Old value as formated string
}
if(DataValid[ValueIndex] == true){
OldDataText[ValueIndex] = DataText[ValueIndex]; // Save the old value
OldDataUnits[ValueIndex] = DataUnits[ValueIndex]; // Save the old unit
}
}
// Vertical line 3 pix
getdisplay().fillRect(SixValues_x1+SixValues_DeltaX-8, SixValues_y1+i*SixValues_DeltaY, 3, SixValues_DeltaY, commonData->fgcolor);
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageSixValues(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageSixValues(
"SixValues", // Page name
createPage, // Action
6, // Number of bus values depends on selection in Web configuration
true // Show display header on/off
);
#endif

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
@@ -6,23 +6,26 @@
class PageSolar : public Page
{
bool init = false; // Marker for init done
bool keylock = false; // Keylock
public:
PageSolar(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageSolar");
common.logger->logDebug(GwLog::LOG,"Show PageSolar");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
bool simulation = config->getBool(config->useSimuData);
@@ -44,13 +47,13 @@ public:
// Get raw value for trend indicator
if(powerSensor != "off"){
value1 = commonData->data.solarVoltage; // Use voltage from external sensor
value1 = commonData.data.solarVoltage; // Use voltage from external sensor
}
else{
value1 = commonData->data.batteryVoltage; // Use internal voltage sensor
value1 = commonData.data.batteryVoltage; // Use internal voltage sensor
}
value2 = commonData->data.solarCurrent;
value3 = commonData->data.solarPower;
value2 = commonData.data.solarCurrent;
value3 = commonData.data.solarPower;
solPercentage = value3 * 100 / (double)solPower; // Load value
// Limits for battery level
if(solPercentage < 0) solPercentage = 0;
@@ -84,10 +87,10 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print("Solar");
@@ -98,7 +101,7 @@ public:
if(String(batVoltage) == "12V") bvoltage = 12;
else bvoltage = 24;
getdisplay().print(bvoltage);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show solar power
@@ -106,33 +109,33 @@ public:
getdisplay().setCursor(10, 200);
if(solPower <= 999) getdisplay().print(solPower, 0);
if(solPower > 999) getdisplay().print(float(solPower/1000.0), 1);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
if(solPower <= 999) getdisplay().print("W");
if(solPower > 999) getdisplay().print("kW");
// Show info
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 235);
getdisplay().print("Installed");
getdisplay().setCursor(10, 255);
getdisplay().print("Solar Modul");
// Show solar panel
solarGraphic(150, 45, commonData->fgcolor, commonData->bgcolor);
solarGraphic(150, 45, commonData.fgcolor, commonData.bgcolor);
// Show load level in percent
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 200);
getdisplay().print(solPercentage);
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("%");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(150, 235);
getdisplay().print("Load");
// Show sensor type info
String i2cAddr = "";
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(270, 60);
if(powerSensor == "off") getdisplay().print("Internal");
if(powerSensor == "INA219"){
@@ -172,7 +175,7 @@ public:
getdisplay().print("---"); // Missing bus data
}
}
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show actual current in A
@@ -184,7 +187,7 @@ public:
if(value2 > 99.9) getdisplay().print(value2, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("A");
// Show actual consumption in W
@@ -196,9 +199,24 @@ public:
if(value3 > 99.9) getdisplay().print(value3, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W");
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};

View File

@@ -1,399 +0,0 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "images/logo64.xbm"
#include <esp32/clk.h>
#include "qrcode.h"
#ifdef BOARD_OBP40S3
#include <SD.h>
#include <FS.h>
#endif
#define STRINGIZE_IMPL(x) #x
#define STRINGIZE(x) STRINGIZE_IMPL(x)
#define VERSINFO STRINGIZE(GWDEVVERSION)
#define BOARDINFO STRINGIZE(BOARD)
#define PCBINFO STRINGIZE(PCBVERS)
#define DISPLAYINFO STRINGIZE(EPDTYPE)
/*
* Special system page, called directly with fast key sequence 5,4
* Out of normal page order.
* Consists of some sub-pages with following content:
* 1. Hard and software information
* 2. System settings
* 3. NMEA2000 device list
*/
class PageSystem : public Page
{
uint64_t chipid;
bool simulation;
bool sdcard;
String buzzer_mode;
uint8_t buzzer_power;
String cpuspeed;
String rtc_module;
String gps_module;
String env_module;
String batt_sensor;
String solar_sensor;
String gen_sensor;
String rot_sensor;
char mode = 'N'; // (N)ormal, (S)ettings, (D)evice list, (C)ard
public:
PageSystem(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageSystem");
if (hasFRAM) {
mode = fram.read(FRAM_SYSTEM_MODE);
}
chipid = ESP.getEfuseMac();
simulation = common.config->getBool(common.config->useSimuData);
#ifdef BOARD_OBP40S3
sdcard = common.config->getBool(common.config->useSDCard);
#endif
buzzer_mode = common.config->getString(common.config->buzzerMode);
buzzer_mode.toLowerCase();
buzzer_power = common.config->getInt(common.config->buzzerPower);
cpuspeed = common.config->getString(common.config->cpuSpeed);
env_module = common.config->getString(common.config->useEnvSensor);
rtc_module = common.config->getString(common.config->useRTC);
gps_module = common.config->getString(common.config->useGPS);
batt_sensor = common.config->getString(common.config->usePowSensor1);
solar_sensor = common.config->getString(common.config->usePowSensor2);
gen_sensor = common.config->getString(common.config->usePowSensor3);
rot_sensor = common.config->getString(common.config->useRotSensor);
}
virtual void setupKeys(){
commonData->keydata[0].label = "EXIT";
commonData->keydata[1].label = "MODE";
commonData->keydata[2].label = "";
commonData->keydata[3].label = "RST";
commonData->keydata[4].label = "STBY";
commonData->keydata[5].label = "ILUM";
}
virtual int handleKey(int key){
// do *NOT* handle key #1 this handled by obp60task as exit
// Switch display mode
commonData->logger->logDebug(GwLog::LOG, "System keyboard handler");
if (key == 2) {
if (mode == 'N') {
mode = 'S';
} else if (mode == 'S') {
mode = 'D';
} else if (mode == 'D') {
if (sdcard) {
mode = 'C';
} else {
mode = 'N';
}
} else {
mode = 'N';
}
if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode);
return 0;
}
#ifdef BOARD_OBP60S3
// grab cursor key to disable page navigation
if (key == 3) {
return 0;
}
// soft reset
if (key == 4) {
ESP.restart();
}
// standby / deep sleep
if (key == 5) {
deepSleep(*commonData);
}
// Code for keylock
if (key == 11) {
commonData->keylock = !commonData->keylock;
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;
}
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){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Get config data
String flashLED = config->getString(config->flashLED);
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageSystem");
// Draw page
//***********************************************************
uint16_t x0 = 8; // left column
uint16_t y0 = 48; // data table starts here
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
if (mode == 'N') {
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("System Information");
getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt8b);
y0 = 155;
char ssid[13];
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
displayBarcode(String(ssid), 320, 200, 2);
getdisplay().setCursor(8, 70);
getdisplay().print(String("MCUDEVICE-") + String(ssid));
getdisplay().setCursor(8, 95);
getdisplay().print("Firmware version: ");
getdisplay().setCursor(160, 95);
getdisplay().print(VERSINFO);
getdisplay().setCursor(8, 113);
getdisplay().print("Board version: ");
getdisplay().setCursor(160, 113);
getdisplay().print(BOARDINFO);
getdisplay().print(String(" HW ") + String(PCBINFO));
getdisplay().setCursor(8, 131);
getdisplay().print("Display version: ");
getdisplay().setCursor(160, 131);
getdisplay().print(DISPLAYINFO);
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
// Flash memory size
uint32_t flash_size = ESP.getFlashChipSize();
getdisplay().setCursor(8, y0);
getdisplay().print("FLASH:");
getdisplay().setCursor(90, y0);
getdisplay().print(String(flash_size / 1024) + String(" kB"));
// PSRAM memory size
uint32_t psram_size = ESP.getPsramSize();
getdisplay().setCursor(8, y0 + 16);
getdisplay().print("PSRAM:");
getdisplay().setCursor(90, y0 + 16);
getdisplay().print(String(psram_size / 1024) + String(" kB"));
// FRAM available / status
getdisplay().setCursor(8, y0 + 32);
getdisplay().print("FRAM:");
getdisplay().setCursor(90, y0 + 32);
getdisplay().print(hasFRAM ? "available" : "not found");
#ifdef BOARD_OBP40S3
// SD-Card
getdisplay().setCursor(8, y0 + 48);
getdisplay().print("SD-Card:");
getdisplay().setCursor(90, y0 + 48);
if (sdcard) {
uint64_t cardsize = SD.cardSize() / (1024 * 1024);
getdisplay().print(String(cardsize) + String(" MB"));
} else {
getdisplay().print("off");
}
#endif
// CPU speed config / active
getdisplay().setCursor(202, y0);
getdisplay().print("CPU speed:");
getdisplay().setCursor(300, y0);
getdisplay().print(cpuspeed);
getdisplay().print(" / ");
int cpu_freq = esp_clk_cpu_freq() / 1000000;
getdisplay().print(String(cpu_freq));
// total RAM free
int Heap_free = esp_get_free_heap_size();
getdisplay().setCursor(202, y0 + 16);
getdisplay().print("Total free:");
getdisplay().setCursor(300, y0 + 16);
getdisplay().print(String(Heap_free));
// RAM free for task
int RAM_free = uxTaskGetStackHighWaterMark(NULL);
getdisplay().setCursor(202, y0 + 32);
getdisplay().print("Task free:");
getdisplay().setCursor(300, y0 + 32);
getdisplay().print(String(RAM_free));
} else if (mode == 'S') {
// Settings
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(x0, 48);
getdisplay().print("System settings");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
x0 = 8;
y0 = 72;
// left column
getdisplay().setCursor(x0, y0);
getdisplay().print("Simulation:");
getdisplay().setCursor(140, y0);
getdisplay().print(simulation ? "on" : "off");
getdisplay().setCursor(x0, y0 + 16);
getdisplay().print("Environment:");
getdisplay().setCursor(140, y0 + 16);
getdisplay().print(env_module);
getdisplay().setCursor(x0, y0 + 32);
getdisplay().print("Buzzer:");
getdisplay().setCursor(140, y0 + 32);
getdisplay().print(buzzer_mode);
getdisplay().setCursor(x0, y0 + 64);
getdisplay().print("GPS:");
getdisplay().setCursor(140, y0 + 64);
getdisplay().print(gps_module);
getdisplay().setCursor(x0, y0 + 80);
getdisplay().print("RTC:");
getdisplay().setCursor(140, y0 + 80);
getdisplay().print(rtc_module);
getdisplay().setCursor(x0, y0 + 96);
getdisplay().print("Wifi:");
getdisplay().setCursor(140, y0 + 96);
getdisplay().print(commonData->status.wifiApOn ? "on" : "off");
// right column
getdisplay().setCursor(202, y0);
getdisplay().print("Batt. sensor:");
getdisplay().setCursor(320, y0);
getdisplay().print(batt_sensor);
// Solar sensor
getdisplay().setCursor(202, y0 + 16);
getdisplay().print("Solar sensor:");
getdisplay().setCursor(320, y0 + 16);
getdisplay().print(solar_sensor);
// Generator sensor
getdisplay().setCursor(202, y0 + 32);
getdisplay().print("Gen. sensor:");
getdisplay().setCursor(320, y0 + 32);
getdisplay().print(gen_sensor);
// Gyro sensor
} else if (mode == 'C') {
// Card info
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("SD Card info");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
x0 = 20;
y0 = 72;
getdisplay().setCursor(x0, y0);
getdisplay().print("Work in progress...");
} else {
// NMEA2000 device list
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("NMEA2000 device list");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(20, 80);
getdisplay().print("RxD: ");
getdisplay().print(String(commonData->status.n2kRx));
getdisplay().setCursor(20, 100);
getdisplay().print("TxD: ");
getdisplay().print(String(commonData->status.n2kTx));
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page* createPage(CommonData &common){
return new PageSystem(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageSystem(
"System", // Page name
createPage, // Action
0, // No bus values
true // Headers are anabled so far
);
#endif

View File

@@ -1,29 +1,28 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageThreeValues : public Page
{
bool keylock = false; // Keylock
public:
PageThreeValues(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageThreeValue");
common.logger->logDebug(GwLog::LOG,"Show PageThreeValue");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
@@ -44,31 +43,28 @@ class PageThreeValues : public Page
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
@@ -89,13 +85,13 @@ class PageThreeValues : public Page
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
@@ -106,11 +102,11 @@ class PageThreeValues : public Page
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 90);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 68);
}
else{
@@ -133,17 +129,17 @@ class PageThreeValues : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
// ############### Value 2 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
@@ -154,11 +150,11 @@ class PageThreeValues : public Page
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 180);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 158);
}
else{
@@ -181,17 +177,17 @@ class PageThreeValues : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
// ############### Value 3 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 235);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 270);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
@@ -202,11 +198,11 @@ class PageThreeValues : public Page
// Switch font if format for any values
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 270);
}
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 248);
}
else{
@@ -226,6 +222,24 @@ class PageThreeValues : public Page
unit3old = unit3; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};

View File

@@ -1,29 +1,28 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageTwoValues : public Page
{
bool keylock = false; // Keylock
public:
PageTwoValues(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageTwoValue");
common.logger->logDebug(GwLog::LOG,"Show PageTwoValue");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
@@ -42,21 +41,19 @@ class PageTwoValues : public Page
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
@@ -77,13 +74,13 @@ class PageTwoValues : public Page
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 80);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 130);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
@@ -94,11 +91,11 @@ class PageTwoValues : public Page
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 130);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 105);
}
else{
@@ -121,17 +118,17 @@ class PageTwoValues : public Page
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 145, 400, 3, commonData->fgcolor);
getdisplay().fillRect(0, 145, 400, 3, commonData.fgcolor);
// ############### Value 2 ################
// Show name
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 190);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 240);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
@@ -142,11 +139,11 @@ class PageTwoValues : public Page
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 240);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 215);
}
else{
@@ -166,6 +163,24 @@ class PageTwoValues : public Page
unit2old = unit2; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
@@ -7,102 +7,41 @@
class PageVoltage : public Page
{
bool init = false; // Marker for init done
uint8_t average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
bool trend = true; // Trend indicator [0|1], 0=off, 1=on
double raw = 0;
char mode = 'D'; // display mode (A)nalog | (D)igital
public:
PageVoltage(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageVoltage");
if (hasFRAM) {
average = fram.read(FRAM_VOLTAGE_AVG);
trend = fram.read(FRAM_VOLTAGE_TREND);
mode = fram.read(FRAM_VOLTAGE_MODE);
}
common.logger->logDebug(GwLog::LOG,"Show PageVoltage");
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "AVG";
commonData->keydata[1].label = "MODE";
commonData->keydata[4].label = "TRD";
}
virtual int handleKey(int key){
// Change average
if(key == 1){
average ++;
average = average % 4; // Modulo 4
if (hasFRAM) fram.write(FRAM_VOLTAGE_AVG, average);
return 0; // Commit the key
}
// Switch display mode
if (key == 2) {
if (mode == 'A') {
mode = 'D';
} else {
mode = 'A';
}
if (hasFRAM) fram.write(FRAM_VOLTAGE_MODE, mode);
return 0;
}
// Trend indicator
if(key == 5){
trend = !trend;
if (hasFRAM) fram.write(FRAM_VOLTAGE_TREND, trend);
return 0; // Commit the key
}
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
void printAvg(int avg, uint16_t x, uint16_t y, bool prefix) {
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(x, y);
if (prefix) {
getdisplay().print("Avg: ");
}
switch (average) {
case 0:
getdisplay().print("1s");
break;
case 1:
getdisplay().print("10s");
break;
case 2:
getdisplay().print("60s");
break;
case 3:
getdisplay().print("300s");
break;
default:
getdisplay().print("1s");
break;
}
}
void printVoltageSymbol(uint16_t x, uint16_t y, uint16_t color) {
getdisplay().setFont(&Ubuntu_Bold16pt8b);
getdisplay().setCursor(x, y);
getdisplay().print("V");
getdisplay().fillRect(x, y + 6, 22, 3, color);
getdisplay().fillRect(x, y + 11, 6, 3, color);
getdisplay().fillRect(x + 8, y + 11, 6, 3, color);
getdisplay().fillRect(x + 16, y + 11, 6, 3, color);
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
bool simulation = config->getBool(config->useSimuData);
@@ -120,32 +59,32 @@ public:
// Create trend value
if(init == false){ // Load start values for first page run
valueTrend = commonData->data.batteryVoltage10;
valueTrend = commonData.data.batteryVoltage10;
init = true;
}
else{ // Reading trend value
valueTrend = commonData->data.batteryVoltage10;
valueTrend = commonData.data.batteryVoltage10;
}
// Get raw value for trend indicator
raw = commonData->data.batteryVoltage; // Live data
raw = commonData.data.batteryVoltage; // Live data
// Switch average values
switch (average) {
case 0:
value1 = commonData->data.batteryVoltage; // Live data
value1 = commonData.data.batteryVoltage; // Live data
break;
case 1:
value1 = commonData->data.batteryVoltage10; // Average 10s
value1 = commonData.data.batteryVoltage10; // Average 10s
break;
case 2:
value1 = commonData->data.batteryVoltage60; // Average 60s
value1 = commonData.data.batteryVoltage60; // Average 60s
break;
case 3:
value1 = commonData->data.batteryVoltage300; // Average 300s
value1 = commonData.data.batteryVoltage300; // Average 300s
break;
default:
value1 = commonData->data.batteryVoltage; // Default
value1 = commonData.data.batteryVoltage; // Default
break;
}
bool valid1 = true;
@@ -196,192 +135,111 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
if (mode == 'D') {
// Display mode digital
// Show name
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Value name
// Show name
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold32pt8b);
getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Value name
// Show unit
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(270, 100);
getdisplay().print("V");
#if defined BOARD_OBP40S3 && defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR
// Show charge status
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(185, 100);
if(commonData->data.BatteryChargeStatus == true){
getdisplay().print("Charge");
// Show battery type
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(295, 100);
getdisplay().print(batType);
// Show average settings
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(320, 84);
switch (average) {
case 0:
getdisplay().print("Avg: 1s");
break;
case 1:
getdisplay().print("Avg: 10s");
break;
case 2:
getdisplay().print("Avg: 60s");
break;
case 3:
getdisplay().print("Avg: 300s");
break;
default:
getdisplay().print("Avg: 1s");
break;
}
// Reading bus data or using simulation data
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
getdisplay().setCursor(20, 240);
if(simulation == true){
if(batVoltage == "12V"){
value1 = 12.0;
}
else{
getdisplay().print("Discharge");
if(batVoltage == "24V"){
value1 = 24.0;
}
#endif
// Show unit
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setCursor(270, 100);
getdisplay().print("V");
// Show battery type
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(295, 100);
#ifdef BOARD_OBP60S3
getdisplay().print(batType);
#endif
#if defined BOARD_OBP40S3 && defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR
getdisplay().print("LiPo");
#endif
// Show average settings
printAvg(average, 320, 84, true);
// Reading bus data or using simulation data
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
getdisplay().setCursor(20, 240);
if(simulation == true){
if(batVoltage == "12V"){
value1 = 12.0;
}
if(batVoltage == "24V"){
value1 = 24.0;
}
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
}
else{
// Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 < 10){
getdisplay().print(value1,2);
}
if(value1 >= 10 && value1 < 100){
getdisplay().print(value1,1);
}
if(value1 >= 100){
getdisplay().print(value1,0);
}
}
else{
getdisplay().print("---"); // Missing bus data
}
}
// Show trend indicator
if(trend == true){
getdisplay().fillRect(315, 183, 35, 4, commonData->fgcolor); // Draw separator
if(int(raw * 10) > int(valueTrend * 10)){
displayTrendHigh(320, 174, 11, commonData->fgcolor); // Show high indicator
}
if(int(raw * 10) < int(valueTrend * 10)){
displayTrendLow(320, 195, 11, commonData->fgcolor); // Show low indicator
}
}
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
}
else {
// Display mode analog
// center
Point c = {260, 270};
uint8_t r = 240;
Point p1, p2;
std::vector<Point> pts;
// Instrument
getdisplay().drawCircleHelper(c.x, c.y, r + 2, 0x01, commonData->fgcolor);
getdisplay().drawCircleHelper(c.x, c.y, r + 1, 0x01, commonData->fgcolor);
getdisplay().drawCircleHelper(c.x, c.y, r , 0x01, commonData->fgcolor);
// Scale
// angle to voltage scale mapping
std::map<int, String> mapping = {
{15, "10"}, {30, "11"}, {45, "12"}, {60, "13"}, {75, "14"}
};
pts = {
{c.x - r, c.y - 1},
{c.x - r + 12, c.y - 1},
{c.x - r + 12, c.y + 1},
{c.x - r, c.y + 1}
};
getdisplay().setFont(&Ubuntu_Bold10pt8b);
for (int angle = 3; angle < 90; angle += 3) {
if (angle % 15 == 0) {
fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
p1 = rotatePoint(c, {c.x - r + 30, c.y}, angle);
drawTextCenter(p1.x, p1.y, mapping[angle]);
else{
// Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 < 10){
getdisplay().print(value1,2);
}
else {
p1 = rotatePoint(c, {c.x - r, c.y}, angle);
p2 = rotatePoint(c, {c.x - r + 6, c.y}, angle);
getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData->fgcolor);
if(value1 >= 10 && value1 < 100){
getdisplay().print(value1,1);
}
if(value1 >= 100){
getdisplay().print(value1,0);
}
}
else{
getdisplay().print("---"); // Missing bus data
}
}
// Pointer rotation and limits
double angle;
if (not valid1) {
angle = -0.5;
// Trend indicator
// Show trend indicator
if(trend == true){
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area
getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor); // Draw separator
if(int(raw * 10) > int(valueTrend * 10)){
displayTrendHigh(320, 174, 11, commonData.fgcolor); // Show high indicator
}
else {
if (value1 > 15.0) {
angle = 91;
}
else if (value1 <= 9) {
angle = -0.5;
}
else {
angle = (value1 - 9) * 15;
}
if(int(raw * 10) < int(valueTrend * 10)){
displayTrendLow(320, 195, 11, commonData.fgcolor); // Show low indicator
}
}
// No trend indicator
else{
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area
}
// Pointer
// thick part
pts = {
{c.x - 2, c.y + 3},
{c.x - r + 38, c.y + 2},
{c.x - r + 38, c.y - 2},
{c.x - 2, c.y - 3}
};
fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
// thin part
pts = {
{c.x - r + 40, c.y + 1},
{c.x - r + 5, c.y + 1},
{c.x - r + 5, c.y -1},
{c.x - r + 40, c.y - 1},
};
fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
// base
getdisplay().fillCircle(c.x, c.y, 7, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, 4, commonData->bgcolor);
// Symbol
printVoltageSymbol(40, 60, commonData->fgcolor);
// Additional information at right side
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(300, 60);
getdisplay().print("Source:");
getdisplay().setCursor(300, 80);
getdisplay().print(name1);
getdisplay().setCursor(300, 110);
getdisplay().print("Type:");
getdisplay().setCursor(300, 130);
getdisplay().print(batType);
getdisplay().setCursor(300, 160);
getdisplay().print("Avg:");
printAvg(average, 300, 180, false);
// FRAM indicator
if (hasFRAM) {
getdisplay().drawXBitmap(300, 240, fram_bits, icon_width, icon_height, commonData->fgcolor);
// Key Layout
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
getdisplay().setCursor(293, 290);
getdisplay().print("[TRD]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display

View File

@@ -1,39 +1,19 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "MFD_OBP60_400x300_sw.h" // MFD with logo
#include "Logo_OBP_400x300_sw.h" // OBP Logo
class PageWhite : public Page
{
char mode = 'W'; // display mode (W)hite | (L)ogo | (M)FD logo
class PageWhite : public Page{
bool keylock = false; // Keylock
public:
public:
PageWhite(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWhite");
refreshtime = 15000;
common.logger->logDebug(GwLog::LOG,"Show PageWhite");
}
virtual int handleKey(int key) {
// Change display mode
if (key == 1) {
if (mode == 'W') {
mode = 'L';
} else if (mode == 'L') {
mode = 'M';
} else {
mode = 'W';
}
return 0;
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
String flashLED = config->getString(config->flashLED);
@@ -54,23 +34,10 @@ public:
int bgcolor = GxEPD_WHITE;
// Set display in partial refresh mode
if (mode == 'W') {
getdisplay().setFullWindow();
} else {
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
}
if (mode == 'L') {
getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), commonData->fgcolor);
} else if (mode == 'M') {
getdisplay().drawBitmap(0, 0, gImage_MFD_OBP60_400x300_sw, getdisplay().width(), getdisplay().height(), commonData->fgcolor);
}
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Update display
getdisplay().nextPage();
if (mode == 'W') {
getdisplay().hibernate();
}
getdisplay().nextPage(); // Partial update (fast)
};
};
@@ -93,4 +60,4 @@ PageDescription registerPageWhite(
false // Show display header on/off
);
#endif
#endif

View File

@@ -1,645 +0,0 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "N2kMessages.h"
#include "BoatDataCalibration.h"
#define front_width 120
#define front_height 162
static unsigned char front_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfc, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf7, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xff, 0xf3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0xff, 0xe1, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xc1, 0xff, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x80, 0xff,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
0x7f, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x7f, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0xfe, 0x0f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0xfe,
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x1f, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xf0,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x03, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x80,
0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
0x00, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00,
0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f,
0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07,
0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x00,
0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x07, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00,
0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x80, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00,
0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00,
0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf8, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01,
0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 };
class PageWind : public Page
{
bool keylock = false; // Keylock
int8_t lp = 80; // Pointer length
char mode = 'N'; // page mode (N)ormal | (L)ens | e(X)ample
char source = 'A'; // data source (A)pparent | (T)rue
public:
PageWind(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWind");
if (hasFRAM) {
lp = fram.read(FRAM_WIND_SIZE);
source = fram.read(FRAM_WIND_SRC);
mode = fram.read(FRAM_WIND_MODE);
}
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "MODE";
if (mode == 'X') {
commonData->keydata[1].label = "#MINUS";
commonData->keydata[4].label = "#PLUS";
} else {
commonData->keydata[1].label = "SRC";
}
}
// Key functions
virtual int handleKey(int key){
if(key == 1){ // Mode switch
if(mode == 'N'){
mode = 'L';
} else if (mode == 'L') {
mode = 'X';
} else {
mode = 'N';
}
if (hasFRAM) fram.write(FRAM_WIND_MODE, mode);
setupKeys();
return 0; // Commit the key
}
// Set source or reduce instrument size
if(key == 2){
if(mode == 'X'){
// Code for reduce
lp = lp - 10;
if(lp < 10){
lp = 10;
}
if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
} else {
// Code for set source
if(source == 'A'){
source = 'T';
} else {
source = 'A';
}
if (hasFRAM) fram.write(FRAM_WIND_SRC, source);
}
return 0; // Commit the key
}
// Enlarge instrument size
if(key == 5 && mode == 'X'){ // Code for enlarge
lp = lp + 10;
if(lp > 80){
lp = 80;
}
if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
return 0; // Commit the key
}
// Keylock function
if(key == 11){ // Code for keylock
commonData->keylock = !commonData->keylock;
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData)
{
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
bool simulation = config->getBool(config->useSimuData);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
GwApi::BoatValue *bvalue1; // Value 1 for speed on top
GwApi::BoatValue *bvalue2; // Value 2 for angle on bottom
// Get boat values for speed (AWS/TWS)
if (source == 'A') {
bvalue1 = pageData.values[0];
} else {
bvalue1 = pageData.values[2];
}
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
// bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Get boat values for angle (AWD/TWD)
if (source == 'A') {
bvalue2 = pageData.values[1];
} else {
bvalue2 = pageData.values[3];
}
String name2 = bvalue2->getName().c_str(); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
double value2 = bvalue2->value; // Value as double in SI unit
// bool valid2 = bvalue2->valid; // Valid information
if (simulation) {
value2 = 0.62731; // some random value
}
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
if (mode == 'X') {
// Original example code with scaling circle
// Show values AWS/TWS
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setCursor(20, 50);
getdisplay().print(name1); // Value name
getdisplay().print(": ");
if(holdvalues == false){
getdisplay().print(svalue1); // Value
getdisplay().print(" ");
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(svalue1old); // Value old
getdisplay().print(" ");
getdisplay().print(unit1old); // Unit old
}
// Show values AWD/TWD
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setCursor(20, 260);
getdisplay().print(name2); // Value name
getdisplay().print(": ");
if(holdvalues == false){
getdisplay().print(svalue2); // Value
getdisplay().print(" ");
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(svalue2old); // Value old
getdisplay().print(" ");
getdisplay().print(unit2old); // Unit old
}
Point c = {200, 145};
// Draw instrument
getdisplay().fillCircle(c.x, c.y, lp + 5, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, lp + 1, commonData->bgcolor);
// Wind pointer
if (bvalue2->valid or simulation) {
uint8_t lp0 = lp * 0.6; // effective pointer outside size
uint8_t lp1 = lp * 0.4; // effective pointer inside size
// zero position
std::vector<Point> pts = {
{c.x, c.y - lp},
{c.x - 7, c.y - lp + lp0},
{c.x, c.y - lp + lp1},
{c.x + 7, c.y - lp + lp0}
};
fillPoly4(rotatePoints(c, pts, RadToDeg(value2)), commonData->fgcolor);
} else {
getdisplay().setFont(&Ubuntu_Bold12pt8b);
drawTextCenter(c.x, c.y, "no data");
}
} else if (mode == 'L') { // Mode (L)ens
Point c = {200, 155};
uint16_t r = 150;
Point p;
std::vector<Point> pts = { // polygon lines
{c.x - 2, c.y - r},
{c.x + 2, c.y - r},
{c.x + 2, c.y - (r - 16)},
{c.x - 2, c.y - (r - 16)}
};
int angle;
getdisplay().setFont(&Ubuntu_Bold12pt8b);
// starbord
// text with line
angle = 20;
for (int i = 30; i < 150; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(angle));
angle += 10;
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 30; i < 138; i += 6) {
if (i % 15 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 2, commonData->fgcolor);
}
}
// port
angle = 50;
// text with line
for (int i = 240; i <= 330; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(angle));
angle -= 10;
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 228; i < 330; i += 6) {
if (i % 15 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 2, commonData->fgcolor);
}
}
// data source
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 50);
if (source == 'A') {
getdisplay().print("APP");
} else {
getdisplay().print("TRUE");
}
// Wind pointer (angle)
if (bvalue2->valid or simulation) {
float alpha = RadToDeg(value2);
bool port = (alpha > 180);
if (port) {
alpha = 360 - alpha;
}
if (alpha < 15) {
alpha = 15; // stop at start of scale
} else if (alpha > 55) {
alpha = 55; // stop at end of scale
}
alpha = 3 * alpha - 30; // convert to lens scale
if (port) {
alpha *= -1;
}
getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
pts = {
{c.x - 1, c.y - (r - 20)},
{c.x + 1, c.y - (r - 20)},
{c.x + 6, c.y + 15},
{c.x - 6, c.y + 15}
};
fillPoly4(rotatePoints(c, pts, alpha), commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
} else {
getdisplay().setFont(&Ubuntu_Bold12pt8b);
drawTextCenter(c.x, c.y, "no data");
}
// Wind speed as decimal number
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 250);
if (holdvalues == false) {
getdisplay().print(svalue1);
} else {
getdisplay().print(svalue1old);
}
// unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(220, 265);
getdisplay().print("kts");
}
else {
// Normal mode
// data source
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 50);
if (source == 'A') {
getdisplay().print("APP");
} else {
getdisplay().print("TRUE");
}
// draw ship front symbol (as bitmap)
getdisplay().drawXBitmap(140, 30, front_bits, front_width, front_height, commonData->fgcolor);
Point c = {200, 155};
uint16_t r = 150;
Point p;
std::vector<Point> pts = { // polygon lines
{c.x - 2, c.y - r},
{c.x + 2, c.y - r},
{c.x + 2, c.y - (r - 16)},
{c.x - 2, c.y - (r - 16)}
};
int angle;
// starbord
// text with line
for (int i = 30; i < 150; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(i));
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 30; i < 150; i += 10) {
if (i % 30 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
}
}
// port
// text with line
angle = 120;
for (int i = 240; i <= 330; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(angle));
angle -= 30;
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 210; i < 340; i += 10) {
if (i % 30 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
}
}
// Wind speed as decimal number
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 250);
if (holdvalues == false) {
getdisplay().print(svalue1);
} else {
getdisplay().print(svalue1old);
}
// unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(220, 265);
getdisplay().print("kts");
// Wind pointer (angle)
if (bvalue2->valid or simulation) {
float alpha = RadToDeg(value2);
getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
pts = {
{c.x - 1, c.y - (r - 20)},
{c.x + 1, c.y - (r - 20)},
{c.x + 6, c.y + 15},
{c.x - 6, c.y + 15}
};
fillPoly4(rotatePoints(c, pts, alpha), commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
} else {
getdisplay().setFont(&Ubuntu_Bold12pt8b);
drawTextCenter(c.x, c.y, "no data");
}
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageWind(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageWind(
"Wind", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"AWS","AWA", "TWS", "TWA"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,32 +1,32 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageWindRose : public Page
{
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length
public:
PageWindRose(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWindRose");
common.logger->logDebug(GwLog::LOG,"Show PageWindRose");
}
// Key functions
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
@@ -52,12 +52,11 @@ public:
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
value1 = formatValue(bvalue1, commonData).value;// Format only nesaccery for simulation data for pointer
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
if(valid1 == true){
svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit
@@ -67,11 +66,10 @@ public:
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
if(valid2 == true){
svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit
@@ -81,11 +79,10 @@ public:
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
if(valid3 == true){
svalue3old = svalue3; // Save old value
unit3old = unit3; // Save old unit
@@ -95,11 +92,10 @@ public:
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
if(valid4 == true){
svalue4old = svalue4; // Save old value
unit4old = unit4; // Save old unit
@@ -109,11 +105,10 @@ public:
GwApi::BoatValue *bvalue5 = pageData.values[4]; // Second element in list (only one value by PageOneValue)
String name5 = xdrDelete(bvalue5->getName()); // Value name
name5 = name5.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
double value5 = bvalue5->value; // Value as double in SI unit
bool valid5 = bvalue5->valid; // Valid information
String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit5 = formatValue(bvalue5, *commonData).unit; // Unit of value
String svalue5 = formatValue(bvalue5, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit5 = formatValue(bvalue5, commonData).unit; // Unit of value
if(valid5 == true){
svalue5old = svalue5; // Save old value
unit5old = unit5; // Save old unit
@@ -123,11 +118,10 @@ public:
GwApi::BoatValue *bvalue6 = pageData.values[5]; // Second element in list (only one value by PageOneValue)
String name6 = xdrDelete(bvalue6->getName()); // Value name
name6 = name6.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
double value6 = bvalue6->value; // Value as double in SI unit
bool valid6 = bvalue6->valid; // Valid information
String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit6 = formatValue(bvalue6, *commonData).unit; // Unit of value
String svalue6 = formatValue(bvalue6, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit6 = formatValue(bvalue6, commonData).unit; // Unit of value
if(valid6 == true){
svalue6old = svalue6; // Save old value
unit6old = unit6; // Save old unit
@@ -149,16 +143,16 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// Show values AWA
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print(svalue1); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 95);
getdisplay().print(name1); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 115);
getdisplay().print(" ");
if(holdvalues == false){
@@ -169,16 +163,16 @@ public:
}
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
// Show values AWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 270);
getdisplay().print(svalue2); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 220);
getdisplay().print(name2); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 190);
getdisplay().print(" ");
if(holdvalues == false){
@@ -197,10 +191,10 @@ public:
else{
getdisplay().print("---"); // Value
}
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 95);
getdisplay().print(name3); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 115);
getdisplay().print(" ");
if(holdvalues == false){
@@ -211,16 +205,16 @@ public:
}
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
// Show values TWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 270);
getdisplay().print(svalue4); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 220);
getdisplay().print(name4); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 190);
getdisplay().print(" ");
if(holdvalues == false){
@@ -236,10 +230,10 @@ public:
int rInstrument = 110; // Radius of grafic instrument
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument - 10, commonData->fgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument - 13, commonData->bgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor); // Inner circle
for(int i=0; i<360; i=i+10)
{
@@ -270,14 +264,14 @@ public:
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
@@ -290,10 +284,10 @@ public:
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
}
}
@@ -310,7 +304,7 @@ public:
float yy2 = -(rInstrument-15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -320,12 +314,12 @@ public:
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
//*******************************************************************************************
@@ -333,7 +327,7 @@ public:
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 200);
getdisplay().print(svalue5); // Value
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(190, 215);
getdisplay().print(" ");
if(holdvalues == false){
@@ -347,7 +341,7 @@ public:
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 130);
getdisplay().print(svalue6); // Value
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(190, 90);
getdisplay().print(" ");
if(holdvalues == false){
@@ -357,6 +351,21 @@ public:
getdisplay().print(unit6old); // Unit
}
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};

View File

@@ -1,32 +1,32 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "BoatDataCalibration.h"
class PageWindRoseFlex : public Page
{
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length
public:
PageWindRoseFlex(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWindRoseFlex");
common.logger->logDebug(GwLog::LOG,"Show PageWindRoseFlex");
}
// Key functions
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
@@ -52,12 +52,11 @@ public:
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
value1 = formatValue(bvalue1, commonData).value;// Format only nesaccery for simulation data for pointer
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
if(valid1 == true){
svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit
@@ -67,11 +66,10 @@ public:
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
if(valid2 == true){
svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit
@@ -81,11 +79,10 @@ public:
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
if(valid3 == true){
svalue3old = svalue3; // Save old value
unit3old = unit3; // Save old unit
@@ -95,11 +92,10 @@ public:
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
if(valid4 == true){
svalue4old = svalue4; // Save old value
unit4old = unit4; // Save old unit
@@ -109,11 +105,10 @@ public:
GwApi::BoatValue *bvalue5 = pageData.values[4]; // Second element in list (only one value by PageOneValue)
String name5 = xdrDelete(bvalue5->getName()); // Value name
name5 = name5.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
double value5 = bvalue5->value; // Value as double in SI unit
bool valid5 = bvalue5->valid; // Valid information
String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit5 = formatValue(bvalue5, *commonData).unit; // Unit of value
String svalue5 = formatValue(bvalue5, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit5 = formatValue(bvalue5, commonData).unit; // Unit of value
if(valid5 == true){
svalue5old = svalue5; // Save old value
unit5old = unit5; // Save old unit
@@ -123,11 +118,10 @@ public:
GwApi::BoatValue *bvalue6 = pageData.values[5]; // Second element in list (only one value by PageOneValue)
String name6 = xdrDelete(bvalue6->getName()); // Value name
name6 = name6.substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
double value6 = bvalue6->value; // Value as double in SI unit
bool valid6 = bvalue6->valid; // Valid information
String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit6 = formatValue(bvalue6, *commonData).unit; // Unit of value
String svalue6 = formatValue(bvalue6, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit6 = formatValue(bvalue6, commonData).unit; // Unit of value
if(valid6 == true){
svalue6old = svalue6; // Save old value
unit6old = unit6; // Save old unit
@@ -149,18 +143,38 @@ public:
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// Show value 2 at position of value 1 (top left)
// Show values AWA
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print(svalue2); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().print(svalue1); // Value
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 95);
getdisplay().print(name2); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().print(name1); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 115);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old); // Unit
}
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
// Show values AWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 270);
getdisplay().print(svalue2); // Value
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 220);
getdisplay().print(name2); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 190);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit2); // Unit
}
@@ -168,18 +182,20 @@ public:
getdisplay().print(unit2old); // Unit
}
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
// Show value 3 at bottom left
// Show values TWD
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 270);
getdisplay().print(svalue3); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(10, 220);
getdisplay().setCursor(295, 65);
if(valid3 == true){
getdisplay().print(abs(value3 * 180 / PI), 0); // Value
}
else{
getdisplay().print("---"); // Value
}
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 95);
getdisplay().print(name3); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(10, 190);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 115);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit3); // Unit
@@ -188,60 +204,36 @@ public:
getdisplay().print(unit3old); // Unit
}
// Show value 4 at top right
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
// Show values TWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 65);
if(valid3 == true){
// getdisplay().print(abs(value3 * 180 / PI), 0); // Value
getdisplay().print(svalue4); // Value
}
else{
getdisplay().print("---"); // Value
}
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(335, 95);
getdisplay().setCursor(295, 270);
getdisplay().print(svalue4); // Value
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 220);
getdisplay().print(name4); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(335, 115);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 190);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit4); // Unit
}
else{
else{
getdisplay().print(unit4old); // Unit
}
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
// Show value 5 at bottom right
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 270);
getdisplay().print(svalue5); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(335, 220);
getdisplay().print(name5); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(335, 190);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit5); // Unit
}
else{
getdisplay().print(unit5old); // Unit
}
//*******************************************************************************************
// Draw wind rose
int rInstrument = 110; // Radius of grafic instrument
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument - 10, commonData->fgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument - 13, commonData->bgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor); // Inner circle
for(int i=0; i<360; i=i+10)
{
@@ -272,14 +264,14 @@ public:
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
@@ -292,10 +284,10 @@ public:
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
}
}
@@ -312,7 +304,7 @@ public:
float yy2 = -(rInstrument-15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
@@ -322,45 +314,57 @@ public:
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
//*******************************************************************************************
// Show value6, so that it does not collide with the wind pointer
if ( cos(value1) > 0){
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 200);
getdisplay().print(svalue6); // Value
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(190, 215);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit6); // Unit
}
else{
getdisplay().print(unit6old); // Unit
}
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 130);
getdisplay().print(svalue6); // Value
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(190, 90);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit6); // Unit
}
else{
getdisplay().print(unit6old); // Unit
}
}
// Show values DBT
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 200);
getdisplay().print(svalue5); // Value
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(190, 215);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit5); // Unit
}
else{
getdisplay().print(unit5old); // Unit
}
// Show values STW
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 130);
getdisplay().print(svalue6); // Value
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(190, 90);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit6); // Unit
}
else{
getdisplay().print(unit6old); // Unit
}
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
@@ -26,17 +26,12 @@ static unsigned char ship_bits[] PROGMEM = {
0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 };
class PageXTETrack : public Page
{
bool simulation = false;
bool holdvalues = false;
class PageXTETrack : public Page{
bool keylock = false; // Keylock
public:
PageXTETrack(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageXTETrack");
simulation = common.config->getBool(common.config->useSimuData);
holdvalues = common.config->getBool(common.config->holdvalues);
common.logger->logDebug(GwLog::LOG,"Show PageXTETrack");
}
void drawSegment(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
@@ -57,17 +52,16 @@ class PageXTETrack : public Page
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
commonData->keylock = !commonData->keylock;
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
String flashLED = config->getString(config->flashLED);
@@ -91,10 +85,10 @@ class PageXTETrack : public Page
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
// descriptions
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(50, 188);
getdisplay().print("Cross-track error");
getdisplay().setCursor(270, 188);
@@ -111,25 +105,25 @@ class PageXTETrack : public Page
uint16_t w, h;
GwApi::BoatValue *bv_xte = pageData.values[0]; // XTE
String sval_xte = formatValue(bv_xte, *commonData).svalue;
String sval_xte = formatValue(bv_xte, commonData).svalue;
getdisplay().getTextBounds(sval_xte, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(160-w, 170);
getdisplay().print(sval_xte);
GwApi::BoatValue *bv_cog = pageData.values[1]; // COG
String sval_cog = formatValue(bv_cog, *commonData).svalue;
String sval_cog = formatValue(bv_cog, commonData).svalue;
getdisplay().getTextBounds(sval_cog, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(360-w, 170);
getdisplay().print(sval_cog);
GwApi::BoatValue *bv_dtw = pageData.values[2]; // DTW
String sval_dtw = formatValue(bv_dtw, *commonData).svalue;
String sval_dtw = formatValue(bv_dtw, commonData).svalue;
getdisplay().getTextBounds(sval_dtw, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(160-w, 257);
getdisplay().print(sval_dtw);
GwApi::BoatValue *bv_btw = pageData.values[3]; // BTW
String sval_btw = formatValue(bv_btw, *commonData).svalue;
String sval_btw = formatValue(bv_btw, commonData).svalue;
getdisplay().getTextBounds(sval_btw, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(360-w, 257);
getdisplay().print(sval_btw);
@@ -139,16 +133,16 @@ class PageXTETrack : public Page
// XTETrack view
// draw ship symbol (as bitmap)
getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, commonData->fgcolor);
getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, commonData.fgcolor);
// draw next waypoint name
String sval_wpname = "no data";
if (valid) {
sval_wpname = "Tonne 122";
sval_wpname = "Tonne 122";
}
getdisplay().setFont(&Ubuntu_Bold10pt8b);
getdisplay().setFont(&Ubuntu_Bold10pt7b);
getdisplay().getTextBounds(sval_wpname, 0, 150, &x, &y, &w, &h);
// TODO if text don't fix use smaller font size.
// if smallest size does not fit use 2 lines
@@ -158,12 +152,7 @@ class PageXTETrack : public Page
// draw course segments
double diff;
if (!simulation) {
diff = bv_cog->value - bv_btw->value;
} else {
diff = 7.0;
}
double diff = bv_cog->value - bv_btw->value;
if (diff < -180) {
diff += 360;
} else if (diff > 180) {
@@ -199,13 +188,28 @@ class PageXTETrack : public Page
}
// left segments
drawSegment(0, 54, 46, 24, 75, 24, 0, 90, commonData->fgcolor, seg[2]);
drawSegment(0, 100, 82, 24, 112, 24, 50, 100, commonData->fgcolor, seg[1]);
drawSegment(60, 100, 117, 24, 147, 24, 110, 100, commonData->fgcolor,seg[0]);
drawSegment(0, 54, 46, 24, 75, 24, 0, 90, commonData.fgcolor, seg[2]);
drawSegment(0, 100, 82, 24, 112, 24, 50, 100, commonData.fgcolor, seg[1]);
drawSegment(60, 100, 117, 24, 147, 24, 110, 100, commonData.fgcolor,seg[0]);
// right segments
drawSegment(340, 100, 283, 24, 253, 24, 290, 100, commonData->fgcolor, seg[3]);
drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData->fgcolor, seg[4]);
drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData->fgcolor, seg[5]);
drawSegment(340, 100, 283, 24, 253, 24, 290, 100, commonData.fgcolor, seg[3]);
drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData.fgcolor, seg[4]);
drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData.fgcolor, seg[5]);
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 296);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 296);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 296);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)

View File

@@ -3,14 +3,10 @@
#include "GwApi.h"
#include <functional>
#include <vector>
#include "LedSpiTask.h"
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
typedef std::vector<GwApi::BoatValue *> ValueList;
typedef struct{
String pageName;
uint8_t pageNumber; // page number in sequence of visible pages
//the values will always contain the user defined values first
ValueList values;
} PageData;
@@ -31,8 +27,6 @@ typedef struct{
double batteryVoltage300 = 0; // Sliding average over 300 values
double batteryCurrent300 = 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 solarCurrent = 0;
double solarPower = 0;
@@ -43,10 +37,14 @@ typedef struct{
double airHumidity = 0;
double airPressure = 0;
double onewireTemp[8] = {0,0,0,0,0,0,0,0};
double rotationAngle = 0; // Rotation angle in radiant
bool validRotAngle = false; // Valid flag magnet present for rotation sensor
struct tm rtcTime; // UTC time from internal RTC
bool rtcValid = false;
double rotationAngle = 0; // Rotation angle in radiant
bool validRotAngle = false; // Valid flag magnet present for rotation sensor
int rtcYear = 0; // UTC time
int rtcMonth = 0;
int rtcDay = 0;
int rtcHour = 0;
int rtcMinute = 0;
int rtcSecond = 0;
int sunsetHour = 0;
int sunsetMinute = 0;
int sunriseHour = 0;
@@ -62,65 +60,23 @@ typedef struct{
bool sunDown = true;
} SunData;
typedef struct{
String label = "";
bool selected = false; // for virtual keyboard function
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
} TouchKeyData;
typedef struct{
Color color; // red, orange, yellow, green, blue, aqua, violet, white
BacklightMode mode; // off, on, sun, bus, time, key
uint8_t brightness; // 0% (off), user setting from 20% to 100% full power
bool on; // fast on/off detector
} BacklightData;
typedef struct{
GwApi::Status status;
GwLog *logger=NULL;
GwConfigHandler *config=NULL;
SensorData data;
SunData sundata;
TouchKeyData keydata[6];
BacklightData backlight;
GwApi::BoatValue *time=NULL;
GwApi::BoatValue *date=NULL;
uint16_t fgcolor;
uint16_t bgcolor;
bool keylock = false;
String powermode;
} CommonData;
//a base class that all pages must inherit from
class Page{
protected:
CommonData *commonData;
public:
int refreshtime = 1000;
virtual void displayPage(PageData &pageData)=0;
virtual void displayNew(PageData &pageData){}
virtual void setupKeys() {
#ifdef HARDWARE_V21
commonData->keydata[0].label = "";
commonData->keydata[1].label = "";
commonData->keydata[2].label = "#LEFT";
commonData->keydata[3].label = "#RIGHT";
commonData->keydata[4].label = "";
if ((commonData->backlight.mode == KEY) && !(commonData->powermode == "Min Power")) {
commonData->keydata[5].label = "ILUM";
} else {
commonData->keydata[5].label = "";
}
#endif
#ifdef BOARD_OBP40S3
commonData->keydata[0].label = "";
commonData->keydata[1].label = "";
#endif
}
virtual void displayPage(CommonData &commonData, PageData &pageData)=0;
virtual void displayNew(CommonData &commonData, PageData &pageData){}
//return -1 if handled by the page
virtual int handleKey(int key){return key;}
};
@@ -158,23 +114,13 @@ class PageDescription{
}
};
class PageStruct{
public:
Page *page=NULL;
PageData parameters;
PageDescription *description=NULL;
};
// Standard format functions without overhead
String formatDate(String fmttype, uint16_t year, uint8_t month, uint8_t day);
String formatTime(char fmttype, uint8_t hour, uint8_t minute, uint8_t second);
// Structure for formatted boat values
// Structure for formated boat values
typedef struct{
double value;
String svalue;
String unit;
} FormatedData;
// Formatter for boat values
// Formater for boat values
FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata);

View File

@@ -0,0 +1,232 @@
const uint8_t Ubuntu_Bold10pt7bBitmaps[] PROGMEM = {
0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xC0, 0xEF, 0xDF, 0xBF, 0x7E, 0xFD, 0xC0,
0x0E, 0xE0, 0xEE, 0x1D, 0xCF, 0xFF, 0xFF, 0xF1, 0xDC, 0x1D, 0xC3, 0xB8,
0xFF, 0xFF, 0xFF, 0x3B, 0x83, 0xB8, 0x77, 0x07, 0x70, 0x1C, 0x0E, 0x0F,
0xCF, 0xEE, 0x07, 0x03, 0x81, 0xFC, 0x7F, 0x0F, 0xC0, 0xE0, 0x74, 0x3F,
0xF9, 0xF8, 0x38, 0x1C, 0x00, 0x38, 0x38, 0x7C, 0x70, 0xC6, 0x70, 0xC6,
0xE0, 0xC6, 0xE0, 0xC7, 0xC0, 0x7D, 0xDC, 0x3B, 0xBE, 0x03, 0xE3, 0x07,
0x63, 0x07, 0x63, 0x0E, 0x63, 0x0E, 0x3E, 0x1C, 0x1C, 0x1E, 0x01, 0xF8,
0x1F, 0xE0, 0xE7, 0x07, 0x38, 0x1F, 0x80, 0xF8, 0x0F, 0xCE, 0xEF, 0x77,
0x3F, 0x38, 0xF9, 0xFF, 0xC7, 0xFF, 0x1F, 0xBC, 0xFF, 0xFF, 0xC0, 0x08,
0x73, 0x8E, 0x71, 0xCE, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x87, 0x1C, 0x38,
0xE1, 0xC2, 0x43, 0x87, 0x1C, 0x38, 0xE1, 0xC7, 0x1C, 0x71, 0xC7, 0x1C,
0x73, 0x8E, 0x71, 0xCE, 0x10, 0x1C, 0x0E, 0x17, 0x5F, 0xFF, 0xF9, 0xB1,
0xDC, 0x6C, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F, 0xFF, 0xFF, 0xFF, 0xF8,
0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0x77, 0x77, 0xEE, 0xFF, 0xFF, 0xC0,
0x6F, 0xF6, 0x01, 0xC0, 0xE0, 0x38, 0x0E, 0x07, 0x01, 0xC0, 0x70, 0x38,
0x0E, 0x03, 0x81, 0xC0, 0x70, 0x1C, 0x0E, 0x03, 0x80, 0xE0, 0x70, 0x1C,
0x07, 0x03, 0x80, 0x1C, 0x3F, 0x9F, 0xDE, 0xFE, 0x3F, 0x1F, 0x8F, 0xC7,
0xE3, 0xF1, 0xFD, 0xEF, 0xE7, 0xF0, 0xE0, 0x0E, 0x3D, 0xFF, 0xF6, 0xE1,
0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC0, 0x3E, 0x7F, 0xBF, 0xEC,
0x70, 0x38, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0xFF, 0xFF, 0xFC,
0x3C, 0x7F, 0x3F, 0xC8, 0xE0, 0x70, 0x30, 0xF0, 0x7E, 0x07, 0x81, 0xE0,
0xFF, 0xFF, 0xF3, 0xF0, 0x07, 0x07, 0x87, 0xC3, 0xE3, 0xF3, 0xB9, 0x9D,
0xCE, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0x70, 0x38, 0x3F, 0x1F, 0x8F, 0xC7,
0x03, 0x83, 0xF1, 0xFC, 0xFF, 0x07, 0x81, 0xC0, 0xFF, 0xFF, 0xF3, 0xE0,
0x07, 0x0F, 0x8F, 0xCF, 0x07, 0x07, 0xF3, 0xFD, 0xFF, 0xE3, 0xF1, 0xF8,
0xEF, 0xF7, 0xF1, 0xF0, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xE0, 0x70, 0x70,
0x38, 0x38, 0x1C, 0x0E, 0x0E, 0x07, 0x03, 0x80, 0x3E, 0x3F, 0xBF, 0xFC,
0x7E, 0x3F, 0xB9, 0xF8, 0xFE, 0xE7, 0xF1, 0xF8, 0xFF, 0xF7, 0xF1, 0xF0,
0x3E, 0x3F, 0xBF, 0xDC, 0x7E, 0x3F, 0x1F, 0xFE, 0xFF, 0x3F, 0x83, 0xC3,
0xCF, 0xC7, 0xC3, 0x80, 0x6F, 0xF6, 0x00, 0x06, 0xFF, 0x60, 0x33, 0xDE,
0x60, 0x00, 0x00, 0x73, 0x9C, 0xEE, 0x70, 0x01, 0x87, 0xEF, 0xFF, 0xF8,
0xE0, 0x3F, 0x8F, 0xFC, 0x7E, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xE0, 0x00,
0x07, 0xFF, 0xFF, 0xFF, 0x60, 0x3E, 0x3F, 0xE3, 0xF0, 0x38, 0xFF, 0xFE,
0xF8, 0x60, 0x00, 0x7C, 0xFE, 0xFF, 0x07, 0x07, 0x07, 0x0E, 0x1E, 0x3C,
0x38, 0x38, 0x00, 0x30, 0x78, 0x78, 0x30, 0x03, 0xF0, 0x07, 0xFE, 0x0F,
0x03, 0x86, 0x00, 0xE6, 0x1F, 0xB7, 0x3F, 0xCF, 0x3C, 0xE7, 0x9C, 0x73,
0xCE, 0x39, 0xE7, 0x1C, 0xF3, 0xCE, 0x5C, 0xFF, 0xE6, 0x3F, 0xE3, 0x80,
0x00, 0xF0, 0x00, 0x3F, 0xE0, 0x07, 0xF8, 0x00, 0x03, 0x80, 0x0F, 0x80,
0x1F, 0x00, 0x77, 0x00, 0xEE, 0x03, 0xDE, 0x07, 0x1C, 0x1E, 0x3C, 0x3F,
0xF8, 0x7F, 0xF1, 0xFF, 0xF3, 0x80, 0xE7, 0x01, 0xDC, 0x01, 0xC0, 0xFE,
0x3F, 0xCF, 0xFB, 0x8E, 0xE3, 0xBF, 0xCF, 0xF3, 0xFE, 0xE1, 0xF8, 0x7E,
0x1F, 0xFF, 0xFF, 0xBF, 0x80, 0x0F, 0xC7, 0xFD, 0xFF, 0xBC, 0x2F, 0x01,
0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1E, 0x01, 0xE0, 0x3F, 0xF3, 0xFE, 0x1F,
0x80, 0xFF, 0x0F, 0xFC, 0xFF, 0xEE, 0x1E, 0xE0, 0xFE, 0x07, 0xE0, 0x7E,
0x07, 0xE0, 0x7E, 0x0F, 0xE1, 0xEF, 0xFE, 0xFF, 0xCF, 0xF0, 0xFF, 0xFF,
0xFF, 0xFC, 0x0E, 0x07, 0xFB, 0xFD, 0xFE, 0xE0, 0x70, 0x38, 0x1F, 0xFF,
0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xFE, 0xFE, 0xFE, 0xE0, 0xE0,
0xE0, 0xE0, 0xE0, 0xE0, 0x0F, 0xC7, 0xFD, 0xFF, 0xBC, 0x2F, 0x01, 0xC0,
0x38, 0x07, 0x07, 0xE0, 0xFE, 0x1D, 0xE3, 0xBF, 0xF3, 0xFE, 0x1F, 0x80,
0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xC0, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03,
0x81, 0xD1, 0xEF, 0xFF, 0xF3, 0xF0, 0xE0, 0xFE, 0x1E, 0xE3, 0xCE, 0x78,
0xEF, 0x0F, 0xE0, 0xFC, 0x0F, 0xC0, 0xEE, 0x0E, 0x70, 0xE7, 0x8E, 0x3C,
0xE1, 0xEE, 0x0F, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0,
0xE0, 0x70, 0x38, 0x1F, 0xFF, 0xFF, 0xFC, 0x70, 0x1C, 0xF0, 0x79, 0xE0,
0xF3, 0xE3, 0xE7, 0xC7, 0xDD, 0x8D, 0xFB, 0xBB, 0xF3, 0x67, 0xE7, 0xCF,
0xCF, 0x9F, 0x8E, 0x3F, 0x1C, 0x7E, 0x00, 0xFC, 0x01, 0xC0, 0xE0, 0xFE,
0x1F, 0xC3, 0xFC, 0x7F, 0xCF, 0xD9, 0xFB, 0xBF, 0x3F, 0xE7, 0xFC, 0x7F,
0x87, 0xF0, 0xFE, 0x0F, 0xC1, 0xC0, 0x0F, 0xC0, 0xFF, 0xC7, 0xFF, 0x9E,
0x1E, 0xF0, 0x3F, 0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0xF7,
0x87, 0x9F, 0xFE, 0x3F, 0xF0, 0x3F, 0x00, 0xFE, 0x3F, 0xEF, 0xFF, 0x87,
0xE1, 0xF8, 0x7F, 0xFF, 0xFE, 0xFE, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x38,
0x00, 0x0F, 0xC0, 0xFF, 0xC7, 0xFF, 0x9E, 0x1E, 0xF0, 0x3F, 0x80, 0x7E,
0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE, 0x3F, 0xF0,
0x3F, 0x00, 0x3C, 0x00, 0x7E, 0x00, 0x78, 0xFE, 0x1F, 0xF3, 0xFF, 0x70,
0xEE, 0x1D, 0xC3, 0xBF, 0xF7, 0xFC, 0xFF, 0x1C, 0xF3, 0x8E, 0x70, 0xEE,
0x1D, 0xC1, 0xC0, 0x3F, 0x1F, 0xEF, 0xFB, 0x80, 0xE0, 0x3E, 0x07, 0xF0,
0x7E, 0x03, 0xC0, 0x74, 0x1F, 0xFF, 0xFF, 0x9F, 0xC0, 0xFF, 0xFF, 0xFF,
0xFF, 0x87, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38,
0x07, 0x00, 0xE0, 0x1C, 0x00, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F,
0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0xC7, 0xBF, 0xE7, 0xFC, 0x3E,
0x00, 0xE0, 0x0E, 0xE0, 0x39, 0xC0, 0x71, 0xC1, 0xC3, 0x83, 0x87, 0x07,
0x07, 0x1C, 0x0E, 0x38, 0x0E, 0xE0, 0x1D, 0xC0, 0x1F, 0x00, 0x3E, 0x00,
0x7C, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xFC, 0x1C, 0x1D, 0xC3, 0x87, 0x38,
0x78, 0xE7, 0x1F, 0x1C, 0xE3, 0x63, 0x8E, 0x6C, 0xE1, 0xDD, 0xDC, 0x3B,
0xBB, 0x83, 0x63, 0x60, 0x7C, 0x7C, 0x0F, 0x8F, 0x81, 0xE0, 0xF0, 0x1C,
0x1C, 0x00, 0xF0, 0x3D, 0xE1, 0xE3, 0x87, 0x07, 0x38, 0x1F, 0xE0, 0x3F,
0x00, 0x78, 0x01, 0xE0, 0x0F, 0xC0, 0x7F, 0x81, 0xCE, 0x0E, 0x1C, 0x78,
0x7B, 0xC0, 0xF0, 0xE0, 0x3B, 0x83, 0x9C, 0x1C, 0x71, 0xC3, 0xDE, 0x0E,
0xE0, 0x3E, 0x01, 0xF0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70,
0x03, 0x80, 0xFF, 0xFF, 0xFF, 0xFC, 0x0E, 0x07, 0x03, 0x80, 0xE0, 0x70,
0x38, 0x1E, 0x07, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xCE, 0x73,
0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0xFF, 0xF0, 0xE0, 0x1C, 0x07,
0x01, 0xC0, 0x38, 0x0E, 0x03, 0x80, 0x70, 0x1C, 0x07, 0x00, 0xE0, 0x38,
0x0E, 0x01, 0xC0, 0x70, 0x1C, 0x03, 0x80, 0xE0, 0x38, 0x07, 0xFF, 0xFE,
0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x3F, 0xFF, 0xF0, 0x0E,
0x03, 0xE0, 0x7C, 0x1D, 0xC7, 0xBC, 0xE3, 0xB8, 0x3B, 0x06, 0xFF, 0xFF,
0xF0, 0x47, 0x1E, 0x20, 0x7E, 0x3F, 0x9F, 0xE0, 0x73, 0xFB, 0xFF, 0x8F,
0xC7, 0xFF, 0xBF, 0xCF, 0xE0, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x3F,
0xCF, 0xFB, 0xFE, 0xE3, 0xF8, 0x7E, 0x1F, 0x87, 0xE3, 0xFF, 0xEF, 0xFB,
0xF8, 0x1F, 0x3F, 0x7F, 0xF0, 0xE0, 0xE0, 0xE0, 0xF0, 0x7F, 0x7F, 0x1F,
0x01, 0xC0, 0x70, 0x1C, 0x07, 0x01, 0xC7, 0xF7, 0xFD, 0xFF, 0xF1, 0xF8,
0x7E, 0x1F, 0x87, 0xF1, 0xDF, 0xF7, 0xFC, 0x7F, 0x1F, 0x1F, 0xE7, 0xFF,
0x87, 0xFF, 0xFF, 0xFE, 0x03, 0xC0, 0x7F, 0x9F, 0xE1, 0xF8, 0x3F, 0x7E,
0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xFE, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0xE0, 0x1F, 0xDF, 0xF7, 0xFF, 0xC7, 0xE1, 0xF8, 0x7F, 0x1F, 0xFF,
0x7F, 0xCF, 0xF0, 0x1C, 0x0F, 0x7F, 0x9F, 0xE7, 0xE0, 0xE0, 0x38, 0x0E,
0x03, 0x80, 0xE0, 0x3F, 0xCF, 0xFB, 0xFF, 0xE3, 0xF8, 0x7E, 0x1F, 0x87,
0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C,
0x71, 0xC7, 0x00, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1F,
0xFF, 0xBC, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC3, 0xB8, 0xE7,
0x38, 0xEE, 0x1F, 0x83, 0xF8, 0x77, 0x8E, 0x79, 0xC7, 0x38, 0x77, 0x07,
0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x7F, 0xE7, 0xFE, 0xF9,
0xFF, 0xFB, 0xFF, 0xFF, 0x1C, 0x7E, 0x38, 0xFC, 0x71, 0xF8, 0xE3, 0xF1,
0xC7, 0xE3, 0x8F, 0xC7, 0x1F, 0x8E, 0x38, 0xFF, 0x3F, 0xEF, 0xFF, 0x8F,
0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1C, 0x1E, 0x1F, 0xE7,
0xFB, 0xCF, 0xE1, 0xF8, 0x7E, 0x1F, 0xCF, 0x7F, 0x9F, 0xE1, 0xE0, 0xFE,
0x3F, 0xEF, 0xFB, 0x8F, 0xE1, 0xF8, 0x7E, 0x1F, 0x8F, 0xFF, 0xBF, 0xEF,
0xF3, 0x80, 0xE0, 0x38, 0x0E, 0x00, 0x1F, 0xDF, 0xF7, 0xFF, 0xC7, 0xE1,
0xF8, 0x7E, 0x1F, 0xC7, 0x7F, 0xDF, 0xF3, 0xFC, 0x07, 0x01, 0xC0, 0x70,
0x1C, 0x7F, 0xFF, 0xFF, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x80, 0x3E,
0xFE, 0xE0, 0xE0, 0xF8, 0x7E, 0x1F, 0x07, 0x87, 0xFF, 0xFC, 0xE1, 0xC3,
0x87, 0xFF, 0xFF, 0xF8, 0x70, 0xE1, 0xC3, 0x87, 0xF7, 0xE7, 0xC0, 0xE1,
0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0xC7, 0xFF, 0xDF, 0xF3,
0xFC, 0xE0, 0xFE, 0x1D, 0xC7, 0x38, 0xE7, 0xBC, 0x77, 0x0E, 0xE1, 0xFC,
0x1F, 0x03, 0xE0, 0x38, 0x00, 0xE3, 0x8F, 0xC7, 0x1D, 0x8E, 0x33, 0x9E,
0xE7, 0x7D, 0xCE, 0xDB, 0x8D, 0xB6, 0x1F, 0x7C, 0x3C, 0x78, 0x38, 0xE0,
0x71, 0xC0, 0xF1, 0xEF, 0x78, 0xEE, 0x1F, 0xC1, 0xF0, 0x1C, 0x07, 0xC1,
0xFC, 0x3B, 0x8F, 0x7B, 0xC7, 0x80, 0xE0, 0xFC, 0x1D, 0xC7, 0x38, 0xE7,
0x1C, 0x77, 0x0E, 0xE1, 0xFC, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x0F, 0xE1,
0xF8, 0x3E, 0x00, 0xFF, 0xFF, 0xFF, 0x0E, 0x1C, 0x38, 0x38, 0x70, 0xFF,
0xFF, 0xFF, 0x0E, 0x3C, 0xF9, 0xC3, 0x87, 0x0E, 0x1C, 0x79, 0xE3, 0xC7,
0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x7C, 0xF8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xF0, 0xE1, 0xE3, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x3C,
0x3C, 0x79, 0xF3, 0x87, 0x0E, 0x1C, 0x39, 0xF3, 0xE7, 0x00, 0x30, 0x9F,
0x3F, 0xFF, 0x3E, 0x43, 0x00 };
const GFXglyph Ubuntu_Bold10pt7bGlyphs[] PROGMEM = {
{ 0, 0, 0, 5, 0, 1 }, // 0x20 ' '
{ 0, 3, 14, 5, 1, -13 }, // 0x21 '!'
{ 6, 7, 6, 9, 1, -14 }, // 0x22 '"'
{ 12, 12, 14, 14, 1, -13 }, // 0x23 '#'
{ 33, 9, 17, 11, 1, -14 }, // 0x24 '$'
{ 53, 16, 14, 18, 1, -13 }, // 0x25 '%'
{ 81, 13, 14, 14, 1, -13 }, // 0x26 '&'
{ 104, 3, 6, 5, 1, -14 }, // 0x27 '''
{ 107, 6, 20, 7, 1, -15 }, // 0x28 '('
{ 122, 6, 20, 7, 0, -15 }, // 0x29 ')'
{ 137, 9, 8, 10, 1, -13 }, // 0x2A '*'
{ 146, 11, 11, 13, 1, -11 }, // 0x2B '+'
{ 162, 4, 6, 5, 0, -2 }, // 0x2C ','
{ 165, 6, 3, 8, 1, -7 }, // 0x2D '-'
{ 168, 4, 4, 6, 1, -3 }, // 0x2E '.'
{ 170, 10, 20, 9, -1, -15 }, // 0x2F '/'
{ 195, 9, 14, 11, 1, -13 }, // 0x30 '0'
{ 211, 7, 14, 11, 1, -13 }, // 0x31 '1'
{ 224, 9, 14, 11, 1, -13 }, // 0x32 '2'
{ 240, 9, 14, 11, 1, -13 }, // 0x33 '3'
{ 256, 9, 14, 11, 1, -13 }, // 0x34 '4'
{ 272, 9, 14, 11, 1, -13 }, // 0x35 '5'
{ 288, 9, 14, 11, 1, -13 }, // 0x36 '6'
{ 304, 9, 14, 11, 1, -13 }, // 0x37 '7'
{ 320, 9, 14, 11, 1, -13 }, // 0x38 '8'
{ 336, 9, 14, 11, 1, -13 }, // 0x39 '9'
{ 352, 4, 11, 6, 1, -10 }, // 0x3A ':'
{ 358, 5, 14, 6, 0, -10 }, // 0x3B ';'
{ 367, 10, 9, 11, 1, -9 }, // 0x3C '<'
{ 379, 9, 8, 11, 1, -9 }, // 0x3D '='
{ 388, 9, 9, 11, 1, -9 }, // 0x3E '>'
{ 399, 8, 16, 9, 0, -15 }, // 0x3F '?'
{ 415, 17, 17, 19, 1, -13 }, // 0x40 '@'
{ 452, 15, 14, 15, 0, -13 }, // 0x41 'A'
{ 479, 10, 14, 13, 2, -13 }, // 0x42 'B'
{ 497, 11, 14, 13, 1, -13 }, // 0x43 'C'
{ 517, 12, 14, 15, 2, -13 }, // 0x44 'D'
{ 538, 9, 14, 12, 2, -13 }, // 0x45 'E'
{ 554, 8, 14, 11, 2, -13 }, // 0x46 'F'
{ 568, 11, 14, 14, 1, -13 }, // 0x47 'G'
{ 588, 11, 14, 15, 2, -13 }, // 0x48 'H'
{ 608, 3, 14, 7, 2, -13 }, // 0x49 'I'
{ 614, 9, 14, 11, 0, -13 }, // 0x4A 'J'
{ 630, 12, 14, 14, 2, -13 }, // 0x4B 'K'
{ 651, 9, 14, 11, 2, -13 }, // 0x4C 'L'
{ 667, 15, 14, 17, 1, -13 }, // 0x4D 'M'
{ 694, 11, 14, 15, 2, -13 }, // 0x4E 'N'
{ 714, 14, 14, 16, 1, -13 }, // 0x4F 'O'
{ 739, 10, 14, 13, 2, -13 }, // 0x50 'P'
{ 757, 14, 17, 16, 1, -13 }, // 0x51 'Q'
{ 787, 11, 14, 13, 2, -13 }, // 0x52 'R'
{ 807, 10, 14, 12, 1, -13 }, // 0x53 'S'
{ 825, 11, 14, 11, 0, -13 }, // 0x54 'T'
{ 845, 11, 14, 15, 2, -13 }, // 0x55 'U'
{ 865, 15, 14, 15, 0, -13 }, // 0x56 'V'
{ 892, 19, 14, 19, 0, -13 }, // 0x57 'W'
{ 926, 14, 14, 14, 0, -13 }, // 0x58 'X'
{ 951, 13, 14, 13, 0, -13 }, // 0x59 'Y'
{ 974, 10, 14, 12, 1, -13 }, // 0x5A 'Z'
{ 992, 5, 20, 7, 2, -15 }, // 0x5B '['
{ 1005, 10, 20, 9, -1, -15 }, // 0x5C '\'
{ 1030, 5, 20, 7, 0, -15 }, // 0x5D ']'
{ 1043, 11, 8, 11, 0, -13 }, // 0x5E '^'
{ 1054, 10, 2, 10, 0, 3 }, // 0x5F '_'
{ 1057, 5, 4, 6, 1, -15 }, // 0x60 '`'
{ 1060, 9, 11, 11, 1, -10 }, // 0x61 'a'
{ 1073, 10, 16, 12, 1, -15 }, // 0x62 'b'
{ 1093, 8, 11, 10, 1, -10 }, // 0x63 'c'
{ 1104, 10, 16, 12, 1, -15 }, // 0x64 'd'
{ 1124, 10, 11, 12, 1, -10 }, // 0x65 'e'
{ 1138, 8, 16, 8, 1, -15 }, // 0x66 'f'
{ 1154, 10, 15, 12, 1, -10 }, // 0x67 'g'
{ 1173, 10, 16, 12, 1, -15 }, // 0x68 'h'
{ 1193, 3, 16, 5, 1, -15 }, // 0x69 'i'
{ 1199, 6, 20, 5, -2, -15 }, // 0x6A 'j'
{ 1214, 11, 16, 12, 1, -15 }, // 0x6B 'k'
{ 1236, 5, 16, 6, 1, -15 }, // 0x6C 'l'
{ 1246, 15, 11, 17, 1, -10 }, // 0x6D 'm'
{ 1267, 10, 11, 12, 1, -10 }, // 0x6E 'n'
{ 1281, 10, 11, 12, 1, -10 }, // 0x6F 'o'
{ 1295, 10, 15, 12, 1, -10 }, // 0x70 'p'
{ 1314, 10, 15, 12, 1, -10 }, // 0x71 'q'
{ 1333, 7, 11, 8, 1, -10 }, // 0x72 'r'
{ 1343, 8, 11, 10, 1, -10 }, // 0x73 's'
{ 1354, 7, 14, 9, 1, -13 }, // 0x74 't'
{ 1367, 10, 11, 12, 1, -10 }, // 0x75 'u'
{ 1381, 11, 11, 11, 0, -10 }, // 0x76 'v'
{ 1397, 15, 11, 15, 0, -10 }, // 0x77 'w'
{ 1418, 11, 11, 11, 0, -10 }, // 0x78 'x'
{ 1434, 11, 15, 11, 0, -10 }, // 0x79 'y'
{ 1455, 8, 11, 10, 1, -10 }, // 0x7A 'z'
{ 1466, 7, 20, 8, 1, -15 }, // 0x7B '{'
{ 1484, 3, 20, 7, 2, -15 }, // 0x7C '|'
{ 1492, 7, 20, 8, 0, -15 }, // 0x7D '}'
{ 1510, 10, 5, 11, 1, -8 } }; // 0x7E '~'
const GFXfont Ubuntu_Bold10pt7b PROGMEM = {
(uint8_t *)Ubuntu_Bold10pt7bBitmaps,
(GFXglyph *)Ubuntu_Bold10pt7bGlyphs,
0x20, 0x7E, 23 };
// Approx. 2189 bytes

View File

@@ -0,0 +1,290 @@
const uint8_t Ubuntu_Bold12pt7bBitmaps[] PROGMEM = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0xFF, 0x60, 0xF7, 0xFB, 0xFD,
0xFE, 0xFF, 0x7F, 0xBF, 0x9C, 0x0F, 0x3C, 0x1E, 0x78, 0x3C, 0xF0, 0xF3,
0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x3C, 0x3E, 0xF8, 0x79, 0xE3,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x9E, 0x1E, 0x78, 0x3C, 0xF0, 0x79,
0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x01, 0xFC, 0x7F, 0xE7, 0xFE, 0xF0, 0x4F,
0x00, 0xF0, 0x0F, 0xF0, 0x7F, 0xC3, 0xFE, 0x07, 0xF0, 0x1F, 0x00, 0xF6,
0x0F, 0xFF, 0xEF, 0xFC, 0x3F, 0x80, 0xE0, 0x0E, 0x00, 0xE0, 0x3E, 0x0F,
0x07, 0xF0, 0xE0, 0xF7, 0x9E, 0x0E, 0x39, 0xC0, 0xE3, 0xBC, 0x0E, 0x3B,
0x80, 0xF7, 0xF8, 0x07, 0xF7, 0x00, 0x3E, 0xF7, 0xC0, 0x0E, 0xFE, 0x01,
0xFE, 0xF0, 0x1D, 0xC7, 0x03, 0xDC, 0x70, 0x39, 0xC7, 0x07, 0x9E, 0xF0,
0x70, 0xFE, 0x0F, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0xC0, 0x3F, 0xE0, 0x38,
0xE0, 0x38, 0xE0, 0x3D, 0xE0, 0x1F, 0xC0, 0x1F, 0x80, 0x3F, 0x9E, 0x7F,
0x9E, 0xF3, 0xDC, 0xF1, 0xFC, 0xF0, 0xF8, 0xF8, 0xF8, 0xFF, 0xFC, 0x7F,
0xFE, 0x1F, 0x9F, 0xFF, 0xFF, 0xFF, 0xE0, 0x08, 0x3C, 0xF1, 0xE7, 0x8F,
0x1E, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0x78, 0xF1, 0xE1,
0xE3, 0xC3, 0xC2, 0x00, 0x21, 0xE1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E,
0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x3C, 0x78, 0xF3, 0xC7, 0x9E, 0x08,
0x00, 0x0E, 0x01, 0xC1, 0x39, 0x7A, 0xFF, 0xFE, 0x1C, 0x06, 0xC1, 0xDC,
0x7B, 0xC2, 0x20, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F, 0xFF, 0xFF, 0xFF,
0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0x7B, 0xDE, 0xF7, 0xBB, 0xCC,
0xFF, 0xFF, 0xF8, 0x6F, 0xF6, 0x00, 0xF0, 0x1F, 0x01, 0xE0, 0x1E, 0x03,
0xC0, 0x3C, 0x03, 0xC0, 0x78, 0x07, 0x80, 0x78, 0x0F, 0x00, 0xF0, 0x0F,
0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x3C, 0x03, 0xC0, 0x3C, 0x07, 0x80, 0x78,
0x0F, 0x80, 0xF0, 0x00, 0x0F, 0x03, 0xFC, 0x7F, 0xE7, 0x9E, 0x70, 0xEF,
0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xE7,
0x9E, 0x7F, 0xE3, 0xFC, 0x0F, 0x00, 0x07, 0x1F, 0x7F, 0xFF, 0xEF, 0x4F,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x1F,
0x07, 0xFC, 0xFF, 0xE6, 0x3E, 0x01, 0xE0, 0x1E, 0x03, 0xE0, 0x3C, 0x07,
0x80, 0xF8, 0x3F, 0x03, 0xE0, 0x7C, 0x0F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0x3E, 0x1F, 0xF3, 0xFF, 0x21, 0xE0, 0x3C, 0x07, 0x87, 0xE0, 0xF8,
0x1F, 0xC0, 0x78, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0xFF, 0xF7, 0xFC, 0x7F,
0x00, 0x03, 0xC0, 0x7C, 0x0F, 0xC0, 0xFC, 0x1F, 0xC3, 0xBC, 0x3B, 0xC7,
0x3C, 0x73, 0xCF, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x03, 0xC0,
0x3C, 0x03, 0xC0, 0x3F, 0xE3, 0xFE, 0x3F, 0xE3, 0x80, 0x38, 0x07, 0x80,
0x7F, 0x07, 0xFC, 0x7F, 0xE0, 0x3F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x1F,
0xFF, 0xEF, 0xFC, 0x7F, 0x00, 0x01, 0xE0, 0xFE, 0x1F, 0xE3, 0xF0, 0x7C,
0x07, 0x80, 0xFF, 0x8F, 0xFE, 0xFF, 0xEF, 0x1F, 0xF0, 0xFF, 0x0F, 0xF0,
0xF7, 0x9F, 0x7F, 0xE3, 0xFC, 0x1F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
0x1E, 0x03, 0xE0, 0x7C, 0x07, 0x80, 0x78, 0x0F, 0x00, 0xF0, 0x1F, 0x01,
0xE0, 0x1E, 0x01, 0xE0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x1F, 0x83, 0xFE,
0x7F, 0xEF, 0x9F, 0xF0, 0xFF, 0x0F, 0xF9, 0xF7, 0xFE, 0x3F, 0xC7, 0xFE,
0xF9, 0xFF, 0x0F, 0xF0, 0xFF, 0x8F, 0xFF, 0xE7, 0xFE, 0x1F, 0x80, 0x1F,
0x03, 0xFC, 0x7F, 0xEF, 0x9E, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x8F, 0x7F,
0xF7, 0xFF, 0x1F, 0xF0, 0x1E, 0x03, 0xE0, 0x7C, 0x7F, 0x87, 0xF0, 0x78,
0x00, 0x6F, 0xF6, 0x00, 0x00, 0x06, 0xFF, 0x60, 0x33, 0xDE, 0x60, 0x00,
0x00, 0x03, 0xDE, 0xF7, 0xBD, 0xDE, 0x60, 0x00, 0x60, 0x3E, 0x1F, 0xFF,
0xFF, 0xFF, 0x8F, 0x00, 0xFF, 0x8F, 0xFF, 0x1F, 0xF0, 0x3E, 0x00, 0x60,
0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x60,
0x07, 0xC0, 0xFF, 0x8F, 0xFF, 0x1F, 0xF0, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF,
0x87, 0xC0, 0x60, 0x00, 0x3E, 0x3F, 0xEF, 0xF9, 0x0F, 0x03, 0xC0, 0xF0,
0x7C, 0x1E, 0x0F, 0x83, 0xC1, 0xE0, 0x78, 0x1C, 0x07, 0x00, 0x00, 0x30,
0x1E, 0x07, 0x80, 0xC0, 0x01, 0xFC, 0x00, 0x3F, 0xFC, 0x03, 0xFF, 0xF0,
0x7E, 0x07, 0xC3, 0xC0, 0x0F, 0x3C, 0x7E, 0x39, 0xC7, 0xF8, 0xFE, 0x7F,
0xC7, 0xE7, 0x8E, 0x3F, 0x38, 0x71, 0xF9, 0xC3, 0x8F, 0xCE, 0x1C, 0x7E,
0x78, 0xE7, 0x71, 0xFF, 0xF9, 0xCF, 0xFF, 0x8F, 0x1F, 0xF8, 0x3C, 0x00,
0x01, 0xF8, 0x00, 0x07, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x1F, 0xE0, 0x00,
0x03, 0xE0, 0x01, 0xF0, 0x01, 0xFC, 0x00, 0xFE, 0x00, 0x77, 0x00, 0x7B,
0xC0, 0x3D, 0xE0, 0x3C, 0x78, 0x1E, 0x3C, 0x0F, 0x1E, 0x0F, 0xFF, 0x87,
0xFF, 0xC3, 0xFF, 0xE3, 0xC0, 0x79, 0xE0, 0x3D, 0xF0, 0x1E, 0xF0, 0x07,
0x80, 0xFF, 0x87, 0xFF, 0x3F, 0xF9, 0xE3, 0xEF, 0x0F, 0x78, 0x7B, 0xC7,
0xDF, 0xFC, 0xFF, 0xE7, 0xFF, 0xBC, 0x3F, 0xE0, 0xFF, 0x07, 0xF8, 0x7F,
0xFF, 0xDF, 0xFC, 0xFF, 0x80, 0x07, 0xF0, 0x7F, 0xF3, 0xFF, 0xDF, 0x82,
0x78, 0x03, 0xE0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00,
0x3E, 0x00, 0x78, 0x01, 0xF0, 0x23, 0xFF, 0xC7, 0xFF, 0x07, 0xF0, 0xFF,
0x81, 0xFF, 0xE3, 0xFF, 0xE7, 0x87, 0xEF, 0x03, 0xDE, 0x07, 0xFC, 0x07,
0xF8, 0x0F, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x81, 0xFF, 0x03, 0xDE,
0x1F, 0xBF, 0xFE, 0x7F, 0xF8, 0xFF, 0x80, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF,
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F,
0x00, 0xF0, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF,
0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xFE, 0xFF, 0xDF, 0xFB, 0xC0,
0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x00, 0x07, 0xF0, 0x7F,
0xF3, 0xFF, 0xDF, 0x02, 0x78, 0x03, 0xE0, 0x0F, 0x00, 0x3C, 0x00, 0xF0,
0x3F, 0xC0, 0xFF, 0x03, 0xFE, 0x0F, 0x78, 0x3D, 0xF0, 0xF3, 0xFF, 0xC7,
0xFF, 0x07, 0xF8, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F,
0xC0, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFC, 0x0F,
0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3C, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0,
0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E,
0x87, 0xDF, 0xF7, 0xFE, 0x3F, 0x00, 0xF0, 0xFF, 0xC7, 0xEF, 0x1F, 0x3C,
0xF8, 0xF7, 0xC3, 0xFE, 0x0F, 0xF0, 0x3F, 0x80, 0xFF, 0x03, 0xFC, 0x0F,
0x78, 0x3D, 0xF0, 0xF3, 0xE3, 0xC7, 0x8F, 0x1F, 0x3C, 0x3E, 0xF0, 0x7C,
0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00,
0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xF0, 0x78, 0x03, 0xCF, 0x80, 0xF9, 0xF0, 0x1F, 0x3F, 0x07, 0xE7,
0xE0, 0xFC, 0xFE, 0x3F, 0xBD, 0xC7, 0xFF, 0xBC, 0xEF, 0xF3, 0xB9, 0xFE,
0x77, 0x3F, 0xCF, 0xE7, 0xF8, 0xF8, 0xFF, 0x1F, 0x1F, 0xE1, 0xC3, 0xFC,
0x38, 0x7F, 0x80, 0x0F, 0xF0, 0x01, 0xE0, 0xF0, 0x3F, 0xE0, 0xFF, 0x83,
0xFF, 0x0F, 0xFE, 0x3F, 0xF8, 0xFF, 0x73, 0xFD, 0xCF, 0xF3, 0xBF, 0xCF,
0xFF, 0x1F, 0xFC, 0x3F, 0xF0, 0xFF, 0xC1, 0xFF, 0x07, 0xFC, 0x0F, 0xF0,
0x3C, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x8F, 0x83, 0xE7, 0x80, 0xF7,
0xC0, 0x7F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01,
0xFF, 0x01, 0xF7, 0x80, 0xF3, 0xE0, 0xF8, 0xFF, 0xF8, 0x3F, 0xF8, 0x07,
0xF0, 0x00, 0xFF, 0x0F, 0xFC, 0xFF, 0xEF, 0x1F, 0xF0, 0xFF, 0x0F, 0xF0,
0xFF, 0x1F, 0xFF, 0xEF, 0xFC, 0xFF, 0x8F, 0x00, 0xF0, 0x0F, 0x00, 0xF0,
0x0F, 0x00, 0xF0, 0x00, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x8F, 0x83,
0xE7, 0x80, 0xF7, 0xC0, 0x7F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8,
0x03, 0xFC, 0x01, 0xFF, 0x01, 0xF7, 0x80, 0xF3, 0xE0, 0xF8, 0xFF, 0xF8,
0x3F, 0xF8, 0x07, 0xF0, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x1F, 0xE0, 0x07,
0xF0, 0x00, 0x70, 0xFF, 0x83, 0xFF, 0x8F, 0xFF, 0x3C, 0x3E, 0xF0, 0x7B,
0xC1, 0xEF, 0x07, 0xBC, 0x3E, 0xFF, 0xF3, 0xFF, 0x8F, 0xFC, 0x3C, 0xF8,
0xF1, 0xF3, 0xC3, 0xCF, 0x0F, 0xBC, 0x1E, 0xF0, 0x7C, 0x1F, 0x87, 0xFE,
0x7F, 0xCF, 0x04, 0xF0, 0x0F, 0x00, 0xFC, 0x07, 0xF8, 0x3F, 0xC0, 0xFE,
0x01, 0xF0, 0x0F, 0x00, 0xF4, 0x1F, 0xFF, 0xEF, 0xFE, 0x3F, 0x80, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01,
0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00,
0x78, 0x01, 0xE0, 0x07, 0x80, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF,
0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0,
0xFF, 0x07, 0xBC, 0x79, 0xFF, 0xC7, 0xFC, 0x0F, 0x80, 0xF0, 0x07, 0xFC,
0x07, 0x9E, 0x03, 0xCF, 0x01, 0xE7, 0xC1, 0xE1, 0xE0, 0xF0, 0xF0, 0x78,
0x3C, 0x78, 0x1E, 0x3C, 0x0F, 0x1E, 0x03, 0xDE, 0x01, 0xEF, 0x00, 0xF7,
0x80, 0x3F, 0x80, 0x1F, 0xC0, 0x0F, 0xE0, 0x03, 0xE0, 0x00, 0xF0, 0x00,
0x1F, 0xE0, 0x00, 0x3F, 0xE0, 0xE0, 0xFB, 0xC3, 0xE1, 0xE7, 0x87, 0xC3,
0xCF, 0x0F, 0x87, 0x9E, 0x1F, 0x8F, 0x3C, 0x77, 0x3E, 0x7C, 0xEE, 0x7C,
0x7B, 0xDE, 0xF0, 0xF7, 0x1D, 0xE1, 0xEE, 0x3B, 0xC3, 0xFC, 0x7F, 0x83,
0xF0, 0x7E, 0x07, 0xE0, 0xFC, 0x0F, 0xC1, 0xF8, 0x1F, 0x01, 0xF0, 0xF8,
0x1F, 0x7C, 0x3E, 0x3C, 0x3C, 0x3E, 0x7C, 0x1F, 0xF8, 0x0F, 0xF0, 0x0F,
0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x07, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, 0x1F,
0xF8, 0x3E, 0x7C, 0x3C, 0x3C, 0x7C, 0x3E, 0xF8, 0x1F, 0xF8, 0x1F, 0x78,
0x1E, 0x7C, 0x3E, 0x3C, 0x3C, 0x3E, 0x7C, 0x1E, 0xF8, 0x0F, 0xF0, 0x0F,
0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03,
0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0x03, 0xE0, 0x1E, 0x01, 0xF0, 0x1F, 0x00, 0xF0, 0x0F, 0x80, 0xF8, 0x07,
0x80, 0x7C, 0x07, 0xC0, 0x3E, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF,
0xFF, 0xFF, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C,
0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0xFF, 0xFF, 0x80, 0xF0, 0x07, 0x80, 0x78,
0x07, 0x80, 0x3C, 0x03, 0xC0, 0x3C, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x0F,
0x00, 0xF0, 0x0F, 0x00, 0x78, 0x07, 0x80, 0x78, 0x03, 0xC0, 0x3C, 0x03,
0xC0, 0x1E, 0x01, 0xE0, 0x1E, 0x00, 0xF0, 0xFF, 0xFF, 0xF8, 0xF1, 0xE3,
0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78,
0xFF, 0xFF, 0xFF, 0x80, 0x07, 0x00, 0x7C, 0x03, 0xE0, 0x3F, 0x83, 0xDE,
0x1E, 0xF1, 0xE3, 0xCE, 0x0E, 0xF0, 0x79, 0x01, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xF0, 0x23, 0xC7, 0x8F, 0x08, 0x7F, 0x1F, 0xE7, 0xFC, 0x0F, 0x03,
0xCF, 0xF7, 0xFF, 0xCF, 0xF3, 0xFC, 0xFF, 0xFD, 0xFF, 0x3F, 0x80, 0x70,
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0x8F, 0xFC, 0xFF,
0xEF, 0x1F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x1E, 0xFF,
0xEF, 0xFC, 0x7F, 0x00, 0x0F, 0x8F, 0xF7, 0xFD, 0xE0, 0xF0, 0x3C, 0x0F,
0x03, 0xC0, 0xF0, 0x1E, 0x17, 0xFC, 0xFF, 0x0F, 0x80, 0x00, 0x70, 0x0F,
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x1F, 0xF3, 0xFF, 0x7F, 0xFF, 0x8F,
0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xF7, 0x8F, 0x7F, 0xF3, 0xFF,
0x0F, 0xE0, 0x0F, 0x83, 0xFC, 0x7F, 0xE7, 0x9E, 0xF0, 0xFF, 0x0F, 0xFF,
0xFF, 0xFF, 0xF0, 0x07, 0x82, 0x7F, 0xE3, 0xFE, 0x0F, 0xC0, 0x1F, 0x3F,
0x9F, 0xDF, 0x0F, 0x07, 0x83, 0xFD, 0xFE, 0xFF, 0x78, 0x3C, 0x1E, 0x0F,
0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x00, 0x1F, 0xC7, 0xFD, 0xFF,
0xFC, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF9, 0xEF, 0xFD, 0xFF, 0x9F,
0xF0, 0x1E, 0x87, 0xDF, 0xF3, 0xFE, 0x7F, 0x00, 0x70, 0x1E, 0x03, 0xC0,
0x78, 0x0F, 0x01, 0xE0, 0x3F, 0xE7, 0xFE, 0xFF, 0xDE, 0x7F, 0xC7, 0xF8,
0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7, 0x80, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1E, 0x3C, 0x78,
0xF0, 0x00, 0x07, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E,
0x3C, 0x78, 0xFF, 0xFF, 0xBE, 0x00, 0x70, 0x0F, 0x00, 0xF0, 0x0F, 0x00,
0xF0, 0x0F, 0x00, 0xF1, 0xFF, 0x3E, 0xF7, 0xCF, 0xF8, 0xFF, 0x0F, 0xE0,
0xFF, 0x0F, 0xF8, 0xF7, 0x8F, 0x7C, 0xF3, 0xEF, 0x1E, 0xF1, 0xF0, 0x73,
0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3E, 0xFD,
0xF3, 0xC0, 0x7F, 0x3F, 0x3F, 0xFF, 0xEF, 0xFF, 0xFB, 0xCF, 0x9F, 0xF1,
0xE3, 0xFC, 0x78, 0xFF, 0x1E, 0x3F, 0xC7, 0x8F, 0xF1, 0xE3, 0xFC, 0x78,
0xFF, 0x1E, 0x3F, 0xC7, 0x8F, 0xF1, 0xE3, 0xC0, 0x7F, 0x1F, 0xFB, 0xFF,
0x79, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8,
0xFF, 0x1E, 0x0F, 0x81, 0xFF, 0x1F, 0xFC, 0xF1, 0xEF, 0x07, 0xF8, 0x3F,
0xC1, 0xFE, 0x0F, 0xF0, 0x7B, 0xC7, 0x9F, 0xFC, 0x7F, 0xC0, 0xF8, 0x00,
0x7F, 0x0F, 0xFC, 0xFF, 0xEF, 0x1E, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F,
0xF0, 0xFF, 0x1F, 0xFF, 0xEF, 0xFC, 0xFF, 0x8F, 0x00, 0xF0, 0x0F, 0x00,
0xF0, 0x00, 0x0F, 0xF1, 0xFF, 0xDF, 0xFE, 0xF0, 0xFF, 0x07, 0xF8, 0x3F,
0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC3, 0xDF, 0xFE, 0x7F, 0xF1, 0xFF, 0x80,
0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x3F, 0xFF, 0xFF, 0xFE, 0x0F, 0x07,
0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x00, 0x1F, 0x9F, 0xEF,
0xFB, 0xC0, 0xF0, 0x3F, 0xE7, 0xFC, 0xFF, 0x03, 0xE0, 0xFF, 0xFF, 0xFE,
0x7E, 0x00, 0x70, 0x78, 0x3C, 0x1E, 0x0F, 0xF7, 0xFB, 0xFD, 0xE0, 0xF0,
0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xFC, 0xFE, 0x3F, 0x00, 0xF1, 0xFE,
0x3F, 0xC7, 0xF8, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xFF, 0x3D,
0xFF, 0xBF, 0xF1, 0xFC, 0xF0, 0x7F, 0xC7, 0xDE, 0x3C, 0xF1, 0xE7, 0x8F,
0x1C, 0xF0, 0xF7, 0x87, 0xBC, 0x3D, 0xC0, 0xFE, 0x07, 0xF0, 0x1F, 0x00,
0xF8, 0x00, 0xF0, 0xE1, 0xFE, 0x1C, 0x3D, 0xC7, 0xC7, 0x3C, 0xF9, 0xE7,
0x9F, 0x3C, 0xF7, 0xE7, 0x8E, 0xEE, 0xE1, 0xDD, 0xDC, 0x3F, 0x3F, 0x83,
0xE3, 0xE0, 0x7C, 0x7C, 0x0F, 0x07, 0x80, 0xE0, 0xE0, 0xF8, 0xFB, 0xC7,
0x8F, 0x78, 0x7B, 0xC1, 0xFC, 0x07, 0xC0, 0x1C, 0x01, 0xF0, 0x1F, 0xC1,
0xEF, 0x0F, 0x78, 0xFB, 0xEF, 0x8F, 0x80, 0xF0, 0x7F, 0xC7, 0xDE, 0x3C,
0xF1, 0xE7, 0x8F, 0x1E, 0xF0, 0xF7, 0x87, 0xBC, 0x1D, 0xC0, 0xFE, 0x07,
0xF0, 0x1F, 0x00, 0xF8, 0x0F, 0x83, 0xFC, 0x1F, 0xC0, 0xFC, 0x00, 0xFF,
0xFF, 0xFF, 0xFC, 0x3E, 0x0F, 0x87, 0xC3, 0xE0, 0xF8, 0x7C, 0x1F, 0x0F,
0xFF, 0xFF, 0xFF, 0xC0, 0x0F, 0x1F, 0x3F, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
0x3C, 0x7C, 0xF8, 0xF0, 0xF8, 0x7C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
0x3F, 0x1F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
0xF0, 0xF8, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3E, 0x1F, 0x0F,
0x1F, 0x3E, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xF8, 0xF0, 0x38,
0x27, 0xE7, 0xFF, 0xFE, 0x7E, 0x41, 0xC0 };
const GFXglyph Ubuntu_Bold12pt7bGlyphs[] PROGMEM = {
{ 0, 0, 0, 6, 0, 1 }, // 0x20 ' '
{ 0, 4, 17, 8, 2, -16 }, // 0x21 '!'
{ 9, 9, 7, 11, 1, -17 }, // 0x22 '"'
{ 17, 15, 17, 17, 1, -16 }, // 0x23 '#'
{ 49, 12, 22, 14, 1, -18 }, // 0x24 '$'
{ 82, 20, 17, 22, 1, -16 }, // 0x25 '%'
{ 125, 16, 17, 17, 1, -16 }, // 0x26 '&'
{ 159, 4, 7, 6, 1, -17 }, // 0x27 '''
{ 163, 7, 23, 9, 2, -18 }, // 0x28 '('
{ 184, 7, 23, 9, 0, -18 }, // 0x29 ')'
{ 205, 11, 10, 12, 1, -16 }, // 0x2A '*'
{ 219, 11, 11, 13, 1, -12 }, // 0x2B '+'
{ 235, 5, 8, 6, 0, -3 }, // 0x2C ','
{ 240, 7, 3, 9, 1, -8 }, // 0x2D '-'
{ 243, 4, 4, 6, 1, -3 }, // 0x2E '.'
{ 245, 12, 23, 10, -1, -18 }, // 0x2F '/'
{ 280, 12, 17, 14, 1, -16 }, // 0x30 '0'
{ 306, 8, 17, 14, 2, -16 }, // 0x31 '1'
{ 323, 12, 17, 14, 1, -16 }, // 0x32 '2'
{ 349, 11, 17, 14, 1, -16 }, // 0x33 '3'
{ 373, 12, 17, 14, 1, -16 }, // 0x34 '4'
{ 399, 12, 17, 14, 1, -16 }, // 0x35 '5'
{ 425, 12, 17, 14, 1, -16 }, // 0x36 '6'
{ 451, 12, 17, 14, 1, -16 }, // 0x37 '7'
{ 477, 12, 17, 14, 1, -16 }, // 0x38 '8'
{ 503, 12, 17, 14, 1, -16 }, // 0x39 '9'
{ 529, 4, 13, 6, 1, -12 }, // 0x3A ':'
{ 536, 5, 17, 6, 0, -12 }, // 0x3B ';'
{ 547, 12, 11, 14, 1, -12 }, // 0x3C '<'
{ 564, 11, 8, 14, 2, -10 }, // 0x3D '='
{ 575, 12, 11, 14, 1, -12 }, // 0x3E '>'
{ 592, 10, 19, 11, 0, -18 }, // 0x3F '?'
{ 616, 21, 21, 23, 1, -16 }, // 0x40 '@'
{ 672, 17, 17, 17, 0, -16 }, // 0x41 'A'
{ 709, 13, 17, 16, 2, -16 }, // 0x42 'B'
{ 737, 14, 17, 16, 1, -16 }, // 0x43 'C'
{ 767, 15, 17, 18, 2, -16 }, // 0x44 'D'
{ 799, 12, 17, 15, 2, -16 }, // 0x45 'E'
{ 825, 11, 17, 14, 2, -16 }, // 0x46 'F'
{ 849, 14, 17, 17, 1, -16 }, // 0x47 'G'
{ 879, 14, 17, 18, 2, -16 }, // 0x48 'H'
{ 909, 4, 17, 8, 2, -16 }, // 0x49 'I'
{ 918, 11, 17, 13, 0, -16 }, // 0x4A 'J'
{ 942, 14, 17, 16, 2, -16 }, // 0x4B 'K'
{ 972, 12, 17, 14, 2, -16 }, // 0x4C 'L'
{ 998, 19, 17, 21, 1, -16 }, // 0x4D 'M'
{ 1039, 14, 17, 18, 2, -16 }, // 0x4E 'N'
{ 1069, 17, 17, 19, 1, -16 }, // 0x4F 'O'
{ 1106, 12, 17, 15, 2, -16 }, // 0x50 'P'
{ 1132, 17, 22, 19, 1, -16 }, // 0x51 'Q'
{ 1179, 14, 17, 16, 2, -16 }, // 0x52 'R'
{ 1209, 12, 17, 14, 1, -16 }, // 0x53 'S'
{ 1235, 14, 17, 14, 0, -16 }, // 0x54 'T'
{ 1265, 13, 17, 17, 2, -16 }, // 0x55 'U'
{ 1293, 17, 17, 17, 0, -16 }, // 0x56 'V'
{ 1330, 23, 17, 23, 0, -16 }, // 0x57 'W'
{ 1379, 16, 17, 16, 0, -16 }, // 0x58 'X'
{ 1413, 16, 17, 16, 0, -16 }, // 0x59 'Y'
{ 1447, 13, 17, 15, 1, -16 }, // 0x5A 'Z'
{ 1475, 7, 23, 9, 2, -18 }, // 0x5B '['
{ 1496, 12, 23, 10, -1, -18 }, // 0x5C '\'
{ 1531, 7, 23, 9, 0, -18 }, // 0x5D ']'
{ 1552, 13, 10, 13, 0, -16 }, // 0x5E '^'
{ 1569, 12, 3, 12, 0, 2 }, // 0x5F '_'
{ 1574, 6, 5, 7, 1, -18 }, // 0x60 '`'
{ 1578, 10, 13, 13, 1, -12 }, // 0x61 'a'
{ 1595, 12, 19, 15, 2, -18 }, // 0x62 'b'
{ 1624, 10, 13, 12, 1, -12 }, // 0x63 'c'
{ 1641, 12, 19, 15, 1, -18 }, // 0x64 'd'
{ 1670, 12, 13, 14, 1, -12 }, // 0x65 'e'
{ 1690, 9, 19, 10, 2, -18 }, // 0x66 'f'
{ 1712, 11, 17, 14, 1, -12 }, // 0x67 'g'
{ 1736, 11, 19, 15, 2, -18 }, // 0x68 'h'
{ 1763, 4, 19, 8, 2, -18 }, // 0x69 'i'
{ 1773, 7, 23, 6, -2, -18 }, // 0x6A 'j'
{ 1794, 12, 19, 14, 2, -18 }, // 0x6B 'k'
{ 1823, 6, 19, 8, 2, -18 }, // 0x6C 'l'
{ 1838, 18, 13, 22, 2, -12 }, // 0x6D 'm'
{ 1868, 11, 13, 15, 2, -12 }, // 0x6E 'n'
{ 1886, 13, 13, 15, 1, -12 }, // 0x6F 'o'
{ 1908, 12, 17, 15, 2, -12 }, // 0x70 'p'
{ 1934, 13, 17, 15, 1, -12 }, // 0x71 'q'
{ 1962, 9, 13, 11, 2, -12 }, // 0x72 'r'
{ 1977, 10, 13, 12, 1, -12 }, // 0x73 's'
{ 1994, 9, 17, 11, 2, -16 }, // 0x74 't'
{ 2014, 11, 13, 15, 2, -12 }, // 0x75 'u'
{ 2032, 13, 13, 13, 0, -12 }, // 0x76 'v'
{ 2054, 19, 13, 19, 0, -12 }, // 0x77 'w'
{ 2085, 13, 13, 13, 0, -12 }, // 0x78 'x'
{ 2107, 13, 17, 13, 0, -12 }, // 0x79 'y'
{ 2135, 10, 13, 12, 1, -12 }, // 0x7A 'z'
{ 2152, 8, 23, 9, 1, -18 }, // 0x7B '{'
{ 2175, 3, 23, 7, 2, -18 }, // 0x7C '|'
{ 2184, 8, 23, 9, 0, -18 }, // 0x7D '}'
{ 2207, 12, 5, 14, 1, -9 } }; // 0x7E '~'
const GFXfont Ubuntu_Bold12pt7b PROGMEM = {
(uint8_t *)Ubuntu_Bold12pt7bBitmaps,
(GFXglyph *)Ubuntu_Bold12pt7bGlyphs,
0x20, 0x7E, 28 };
// Approx. 2887 bytes

View File

@@ -0,0 +1,402 @@
const uint8_t Ubuntu_Bold16pt7bBitmaps[] PROGMEM = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x00, 0x0E, 0xFF, 0xFF,
0xF7, 0x00, 0xF9, 0xFF, 0x9F, 0xF9, 0xFF, 0x9F, 0xF9, 0xFF, 0x9F, 0xF9,
0xFF, 0x1E, 0x70, 0xE0, 0x07, 0xCF, 0x81, 0xF3, 0xE0, 0x7D, 0xF8, 0x3E,
0x7C, 0x0F, 0x9F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC7, 0xCF, 0x81, 0xF3, 0xE0, 0x7C, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x7C, 0x0F, 0x9F, 0x07, 0xEF, 0x81, 0xF3,
0xE0, 0x7C, 0xF8, 0x00, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x07, 0xF8,
0x1F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFC, 0x7E, 0x0C, 0x7C, 0x00, 0x7C, 0x00,
0x7E, 0x00, 0x7F, 0xE0, 0x3F, 0xF8, 0x1F, 0xFC, 0x0F, 0xFE, 0x01, 0xFF,
0x00, 0x3F, 0x00, 0x1F, 0x00, 0x1F, 0x70, 0x3F, 0x7F, 0xFE, 0xFF, 0xFE,
0xFF, 0xFC, 0x1F, 0xF0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x1F, 0x80, 0xF8, 0x0F, 0xF0, 0x3C, 0x07, 0xFE, 0x1F, 0x03, 0xE7, 0xC7,
0x80, 0xF0, 0xF3, 0xE0, 0x3C, 0x3C, 0xF0, 0x0F, 0x0F, 0x78, 0x03, 0xC3,
0xFE, 0x00, 0xF9, 0xFF, 0x00, 0x1F, 0xFF, 0xDF, 0x83, 0xFD, 0xEF, 0xF0,
0x7E, 0xFF, 0xFE, 0x00, 0x3F, 0xE7, 0xC0, 0x1F, 0xF0, 0xF0, 0x07, 0xBC,
0x3C, 0x03, 0xCF, 0x0F, 0x01, 0xF3, 0xC3, 0xC0, 0x78, 0xF9, 0xF0, 0x3E,
0x1F, 0xF8, 0x0F, 0x03, 0xFC, 0x07, 0xC0, 0x7E, 0x00, 0x07, 0xF0, 0x00,
0x7F, 0xE0, 0x07, 0xFF, 0x00, 0x7F, 0xFC, 0x03, 0xE3, 0xE0, 0x1F, 0x1F,
0x00, 0xFD, 0xF0, 0x03, 0xFF, 0x80, 0x1F, 0xF8, 0x00, 0xFF, 0x00, 0x0F,
0xFC, 0xF8, 0xFF, 0xF7, 0xC7, 0xDF, 0xBE, 0x7C, 0x7F, 0xE3, 0xE1, 0xFF,
0x1F, 0x07, 0xF0, 0xFC, 0x1F, 0x87, 0xFF, 0xFE, 0x1F, 0xFF, 0xF8, 0x7F,
0xFF, 0xE0, 0xFE, 0x3F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x70, 0x04,
0x07, 0x87, 0xE3, 0xE3, 0xF1, 0xF1, 0xF8, 0xF8, 0x7C, 0x3E, 0x3E, 0x1F,
0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x07, 0xC3, 0xE1,
0xF0, 0xFC, 0x3E, 0x1F, 0x87, 0xC3, 0xF0, 0xF0, 0x20, 0x10, 0x3C, 0x3F,
0x0F, 0x87, 0xE1, 0xF0, 0xFC, 0x3E, 0x1F, 0x0F, 0x83, 0xE1, 0xF0, 0xF8,
0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF1, 0xF0, 0xF8, 0x7C, 0x7E,
0x3E, 0x3F, 0x1F, 0x1F, 0x87, 0x80, 0x80, 0x0F, 0x80, 0x7C, 0x1B, 0xCC,
0xEE, 0xEF, 0xFF, 0xFF, 0xFC, 0x1C, 0x03, 0xF8, 0x3D, 0xE3, 0xEF, 0x8E,
0x38, 0x11, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x83,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1E, 0x00, 0x78, 0x01, 0xE0,
0x07, 0x80, 0x1E, 0x00, 0x7D, 0xF7, 0xDF, 0x7D, 0xE7, 0xBE, 0xF0, 0xC0,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7B, 0xFF, 0xFF, 0xFD, 0xE0, 0x00, 0x3E,
0x00, 0xFC, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E, 0x00,
0xFC, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E, 0x00, 0xFC,
0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E, 0x00, 0xFC, 0x01,
0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E, 0x00, 0xFC, 0x01, 0xF0,
0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x00, 0x07, 0xE0, 0x1F, 0xF8, 0x3F,
0xFC, 0x3F, 0xFC, 0x7E, 0x7E, 0x7C, 0x3E, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
0x1F, 0x7C, 0x3E, 0x7E, 0x7E, 0x3F, 0xFC, 0x3F, 0xFC, 0x1F, 0xF8, 0x07,
0xE0, 0x03, 0xC1, 0xF1, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0x7D, 0x1F, 0x07,
0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0,
0x7C, 0x1F, 0x07, 0xC0, 0x0F, 0xC0, 0x7F, 0xE3, 0xFF, 0xE7, 0xFF, 0xE7,
0x8F, 0xC4, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0xF8, 0x03, 0xF0, 0x0F,
0xC0, 0x3F, 0x00, 0xFE, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x3E, 0x00,
0xFF, 0xFD, 0xFF, 0xFB, 0xFF, 0xF7, 0xFF, 0xE0, 0x1F, 0xC0, 0xFF, 0xE3,
0xFF, 0xE3, 0xFF, 0xE6, 0x0F, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x7C, 0x1F,
0xF8, 0x3F, 0xC0, 0x7F, 0xE0, 0xFF, 0xE0, 0x0F, 0xE0, 0x07, 0xC0, 0x0F,
0x80, 0x1F, 0x60, 0x7F, 0xFF, 0xFB, 0xFF, 0xF7, 0xFF, 0xC3, 0xFC, 0x00,
0x00, 0x7C, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0xFC, 0x07, 0xFC, 0x0F, 0xFC,
0x0F, 0x7C, 0x1F, 0x7C, 0x3E, 0x7C, 0x3C, 0x7C, 0x78, 0x7C, 0xF8, 0x7C,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7C, 0x00, 0x7C,
0x00, 0x7C, 0x00, 0x7C, 0x00, 0x7C, 0x3F, 0xFC, 0x7F, 0xF8, 0xFF, 0xF1,
0xFF, 0xE3, 0xC0, 0x07, 0x80, 0x1F, 0x00, 0x3F, 0xC0, 0x7F, 0xF0, 0xFF,
0xF1, 0xFF, 0xF0, 0x0F, 0xF0, 0x07, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F,
0x40, 0x7F, 0xFF, 0xFB, 0xFF, 0xE7, 0xFF, 0x83, 0xFC, 0x00, 0x00, 0x3E,
0x01, 0xFE, 0x07, 0xFE, 0x0F, 0xFE, 0x1F, 0xE0, 0x3F, 0x00, 0x7E, 0x00,
0x7C, 0x00, 0xFF, 0xF0, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0xFE, 0xF8, 0x3F,
0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0x7C, 0x3F, 0x7F, 0xFE, 0x3F, 0xFC,
0x1F, 0xF8, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x3E, 0x00, 0x7C, 0x00, 0xFC, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0xF0,
0x01, 0xF0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x07, 0xC0, 0x07, 0xC0,
0x07, 0xC0, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0xE0,
0x3F, 0xF8, 0x7F, 0xFC, 0x7F, 0xFE, 0xFC, 0x7E, 0xF8, 0x3E, 0xF8, 0x3E,
0xFC, 0x7C, 0x7F, 0xFC, 0x3F, 0xF0, 0x3F, 0xFC, 0x7F, 0xFE, 0xFC, 0x3E,
0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F, 0x7F, 0xFE, 0x7F, 0xFE,
0x3F, 0xFC, 0x07, 0xF0, 0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE,
0xFC, 0x3E, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x1F, 0x7F, 0xFF,
0x7F, 0xFF, 0x3F, 0xFF, 0x0F, 0xDF, 0x00, 0x3E, 0x00, 0x7E, 0x00, 0xFE,
0x03, 0xFC, 0x3F, 0xF8, 0x3F, 0xF0, 0x3F, 0xC0, 0x3E, 0x00, 0x7B, 0xFF,
0xFF, 0xFD, 0xE0, 0x00, 0x00, 0x00, 0x1E, 0xFF, 0xFF, 0xFF, 0x78, 0x7B,
0xFF, 0xFF, 0xFD, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xF7, 0xDF, 0x7D,
0xE7, 0xBE, 0xF0, 0xC0, 0x00, 0x0C, 0x01, 0xF8, 0x3F, 0xFB, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3F, 0xE0, 0x7C, 0x00, 0xFF, 0x81, 0xFF, 0xF3, 0xFF,
0xFB, 0xFF, 0xF0, 0xFF, 0xE0, 0x1F, 0x80, 0x03, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x60, 0x01, 0xF0, 0x0F, 0xFC, 0x3F,
0xFE, 0xFF, 0xFC, 0xFF, 0xF0, 0x3F, 0xC0, 0x1F, 0x03, 0xFC, 0xFF, 0xFF,
0xFF, 0xFF, 0xFE, 0xFF, 0xC1, 0xF0, 0x06, 0x00, 0x00, 0x3F, 0x8F, 0xFC,
0xFF, 0xE7, 0xFF, 0x63, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x03, 0xE0, 0x7E,
0x0F, 0xC0, 0xF8, 0x1F, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x00, 0x00, 0x00,
0x1E, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x01, 0xE0, 0x00, 0x7F, 0x80,
0x00, 0x7F, 0xFC, 0x00, 0x7F, 0xFF, 0xC0, 0x3F, 0x03, 0xF8, 0x1F, 0x00,
0x3F, 0x0F, 0x80, 0x03, 0xC3, 0xC1, 0xF8, 0x79, 0xE1, 0xFF, 0x1E, 0x78,
0xFF, 0xC7, 0xFE, 0x3C, 0xF0, 0xFF, 0x1E, 0x3C, 0x3F, 0xC7, 0x8F, 0x0F,
0xF1, 0xE3, 0xC3, 0xFC, 0x78, 0xF0, 0xFF, 0x1E, 0x3C, 0x3F, 0xC7, 0x8F,
0x0F, 0xF1, 0xE3, 0xC7, 0xBE, 0x3C, 0xF1, 0xE7, 0x8F, 0xFF, 0xF1, 0xE1,
0xFF, 0xF8, 0x3C, 0x3E, 0xF8, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00,
0x3F, 0x80, 0x40, 0x07, 0xFF, 0xF0, 0x00, 0x7F, 0xFC, 0x00, 0x03, 0xFE,
0x00, 0x00, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0x80, 0x07, 0xFC, 0x00,
0x3F, 0xF0, 0x03, 0xEF, 0x80, 0x1F, 0x7C, 0x00, 0xFB, 0xF0, 0x0F, 0x8F,
0x80, 0x7C, 0x7E, 0x03, 0xE3, 0xF0, 0x3E, 0x0F, 0x81, 0xFF, 0xFC, 0x1F,
0xFF, 0xF0, 0xFF, 0xFF, 0x87, 0xFF, 0xFC, 0x7E, 0x03, 0xF3, 0xE0, 0x0F,
0x9F, 0x00, 0x7D, 0xF8, 0x03, 0xFF, 0x80, 0x0F, 0x80, 0xFF, 0xE0, 0x7F,
0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF, 0x83, 0xF7, 0xC0, 0xFB, 0xE0, 0x7D,
0xF0, 0x7E, 0xFF, 0xFE, 0x7F, 0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF, 0x81,
0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, 0xBF,
0xFF, 0xDF, 0xFF, 0x87, 0xFF, 0x00, 0x01, 0xFC, 0x03, 0xFF, 0xC7, 0xFF,
0xE7, 0xFF, 0xE3, 0xF0, 0x33, 0xF0, 0x01, 0xF0, 0x01, 0xF0, 0x00, 0xF8,
0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03,
0xF0, 0x00, 0xFC, 0x00, 0x7F, 0x03, 0x1F, 0xFF, 0x87, 0xFF, 0xE1, 0xFF,
0xF0, 0x3F, 0xC0, 0xFF, 0xE0, 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7F, 0xFF,
0xCF, 0x83, 0xF9, 0xF0, 0x1F, 0xBE, 0x01, 0xF7, 0xC0, 0x3F, 0xF8, 0x03,
0xFF, 0x00, 0x7F, 0xE0, 0x0F, 0xFC, 0x01, 0xFF, 0x80, 0x3F, 0xF0, 0x0F,
0xFE, 0x01, 0xF7, 0xC0, 0x7E, 0xF8, 0x3F, 0x9F, 0xFF, 0xF3, 0xFF, 0xFC,
0x7F, 0xFE, 0x0F, 0xFE, 0x00, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF,
0xFE, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFC, 0xFF,
0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0x00, 0x3E, 0x00,
0x7C, 0x00, 0xFF, 0xFD, 0xFF, 0xFB, 0xFF, 0xF7, 0xFF, 0xEF, 0x80, 0x1F,
0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0,
0x0F, 0x80, 0x00, 0x01, 0xFE, 0x01, 0xFF, 0xF1, 0xFF, 0xFC, 0xFF, 0xFE,
0x3F, 0x01, 0x9F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E,
0x00, 0x0F, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xF7, 0xC0,
0x7D, 0xF8, 0x1F, 0x7F, 0x07, 0xCF, 0xFF, 0xF1, 0xFF, 0xFC, 0x3F, 0xFF,
0x01, 0xFF, 0x00, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xE0, 0x0F, 0xFC, 0x01,
0xFF, 0x80, 0x3F, 0xF0, 0x07, 0xFE, 0x00, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xF0, 0x07,
0xFE, 0x00, 0xFF, 0xC0, 0x1F, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xE0, 0x0F,
0xFC, 0x01, 0xFF, 0x80, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x7C, 0x01, 0xF0, 0x07,
0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01,
0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x60,
0xFD, 0xFF, 0xEF, 0xFF, 0xBF, 0xFC, 0x1F, 0xC0, 0xF8, 0x1F, 0xDF, 0x07,
0xF3, 0xE1, 0xFC, 0x7C, 0x7F, 0x0F, 0x9F, 0xC1, 0xF7, 0xF0, 0x3F, 0xFC,
0x07, 0xFF, 0x00, 0xFF, 0xC0, 0x1F, 0xF0, 0x03, 0xFF, 0x00, 0x7F, 0xF0,
0x0F, 0xFF, 0x01, 0xF7, 0xE0, 0x3E, 0x7E, 0x07, 0xC7, 0xE0, 0xF8, 0x7E,
0x1F, 0x07, 0xE3, 0xE0, 0x7E, 0x7C, 0x0F, 0xEF, 0x80, 0xFE, 0xF8, 0x03,
0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00,
0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80,
0x3E, 0x00, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3E,
0x00, 0x7C, 0x3E, 0x00, 0x7C, 0x3F, 0x00, 0xFC, 0x7F, 0x00, 0xFE, 0x7F,
0x80, 0xFE, 0x7F, 0x81, 0xFE, 0x7F, 0xC1, 0xFE, 0x7F, 0xC3, 0xFE, 0x7F,
0xE3, 0xFE, 0x7D, 0xE7, 0xBE, 0x79, 0xF7, 0x9E, 0x78, 0xF7, 0x9E, 0x78,
0xFF, 0x1E, 0xF8, 0x7F, 0x1E, 0xF8, 0x7E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8,
0x3E, 0x1F, 0xF8, 0x3C, 0x1F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x1F, 0xF8,
0x00, 0x1F, 0xF8, 0x03, 0xFF, 0x80, 0x7F, 0xF8, 0x0F, 0xFF, 0x01, 0xFF,
0xF0, 0x3F, 0xFF, 0x07, 0xFF, 0xF0, 0xFF, 0xFF, 0x1F, 0xFB, 0xE3, 0xFF,
0x3E, 0x7F, 0xE3, 0xEF, 0xFC, 0x7D, 0xFF, 0x87, 0xFF, 0xF0, 0x7F, 0xFE,
0x07, 0xFF, 0xC0, 0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0xFF, 0xE0, 0x1F, 0xFC,
0x01, 0xFF, 0x80, 0x3E, 0x01, 0xF8, 0x00, 0xFF, 0xF0, 0x1F, 0xFF, 0x83,
0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xE0, 0x7E, 0x7C, 0x03, 0xEF, 0x80, 0x1F,
0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01,
0xFF, 0x80, 0x1F, 0x7C, 0x03, 0xE7, 0xE0, 0x7E, 0x7F, 0x0F, 0xE3, 0xFF,
0xFC, 0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x01, 0xF8, 0x00, 0xFF, 0xE0, 0x7F,
0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF, 0x83, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F,
0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x1F, 0xFF, 0xFF, 0xDF, 0xFF, 0xCF, 0xFF,
0xC7, 0xFF, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E,
0x00, 0x1F, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF8, 0x00, 0xFF, 0xF0, 0x1F,
0xFF, 0x83, 0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xE0, 0x7E, 0x7C, 0x03, 0xEF,
0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F,
0xF8, 0x01, 0xFF, 0x80, 0x1F, 0x7C, 0x03, 0xF7, 0xE0, 0x7E, 0x3F, 0x0F,
0xE3, 0xFF, 0xFC, 0x1F, 0xFF, 0xC0, 0xFF, 0xF0, 0x01, 0xFE, 0x00, 0x07,
0xC0, 0x00, 0x7F, 0x00, 0x03, 0xFE, 0x00, 0x1F, 0xE0, 0x00, 0xFC, 0x00,
0x03, 0xC0, 0xFF, 0xE0, 0x3F, 0xFF, 0x0F, 0xFF, 0xE3, 0xFF, 0xFC, 0xF8,
0x3F, 0xBE, 0x03, 0xEF, 0x80, 0xFB, 0xE0, 0x3E, 0xF8, 0x0F, 0xBE, 0x0F,
0xEF, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0xFC, 0x3F, 0xFE, 0x0F, 0x9F, 0xC3,
0xE3, 0xF0, 0xF8, 0x7E, 0x3E, 0x0F, 0xCF, 0x83, 0xF3, 0xE0, 0x7E, 0xF8,
0x0F, 0xC0, 0x07, 0xF0, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0xFC, 0x0C,
0xF8, 0x00, 0xF8, 0x00, 0xFC, 0x00, 0x7F, 0x80, 0x7F, 0xF0, 0x1F, 0xFC,
0x07, 0xFE, 0x00, 0xFF, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x1F, 0x70, 0x3F,
0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0x1F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07,
0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00,
0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8,
0x00, 0x7C, 0x00, 0x3E, 0x00, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F,
0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8,
0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01,
0xFF, 0x80, 0x7F, 0xF0, 0x3F, 0x7E, 0x1F, 0x9F, 0xFF, 0xE3, 0xFF, 0xF0,
0x7F, 0xF8, 0x07, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xE0, 0x0F, 0x9F, 0x00,
0x7C, 0xF8, 0x03, 0xE7, 0xE0, 0x3E, 0x1F, 0x01, 0xF0, 0xF8, 0x1F, 0x87,
0xE0, 0xF8, 0x1F, 0x07, 0xC0, 0xF8, 0x7E, 0x07, 0xE3, 0xE0, 0x1F, 0x1F,
0x00, 0xFD, 0xF8, 0x07, 0xEF, 0x80, 0x1F, 0x7C, 0x00, 0xFF, 0xE0, 0x03,
0xFE, 0x00, 0x1F, 0xF0, 0x00, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0x1F, 0xC0,
0x00, 0xF8, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x0F, 0xDF, 0x03, 0xE0, 0x7C,
0xF8, 0x1F, 0x03, 0xE7, 0xC1, 0xFC, 0x1F, 0x3E, 0x0F, 0xE0, 0xF8, 0xF0,
0x7F, 0x0F, 0x87, 0xC3, 0xF8, 0x7C, 0x3E, 0x3D, 0xE3, 0xE1, 0xF1, 0xEF,
0x1F, 0x07, 0x8F, 0x78, 0xF0, 0x3E, 0xFB, 0xEF, 0x81, 0xF7, 0x8F, 0x7C,
0x0F, 0xBC, 0x7B, 0xE0, 0x3D, 0xE3, 0xFE, 0x01, 0xFF, 0x1F, 0xF0, 0x0F,
0xF0, 0x7F, 0x80, 0x3F, 0x83, 0xF8, 0x01, 0xFC, 0x1F, 0xC0, 0x0F, 0xC0,
0x7E, 0x00, 0x3E, 0x03, 0xE0, 0x00, 0xFC, 0x01, 0xFB, 0xF0, 0x1F, 0x8F,
0xC1, 0xF8, 0x3E, 0x0F, 0x81, 0xF8, 0xFC, 0x07, 0xEF, 0xC0, 0x1F, 0xFC,
0x00, 0xFF, 0xE0, 0x03, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0x3E, 0x00, 0x03,
0xF8, 0x00, 0x3F, 0xE0, 0x03, 0xFF, 0x80, 0x1F, 0xFC, 0x01, 0xFB, 0xF0,
0x1F, 0x8F, 0xC1, 0xF8, 0x3E, 0x0F, 0xC1, 0xF8, 0xFC, 0x07, 0xEF, 0xC0,
0x1F, 0x80, 0xFC, 0x01, 0xFB, 0xE0, 0x1F, 0x9F, 0x80, 0xFC, 0x7E, 0x0F,
0xC1, 0xF0, 0x7C, 0x0F, 0xC7, 0xE0, 0x3F, 0x7E, 0x01, 0xFB, 0xF0, 0x07,
0xFF, 0x00, 0x1F, 0xF0, 0x00, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0x0F, 0x80,
0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07,
0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7F, 0xFF,
0xBF, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xF0, 0x03, 0xF0, 0x03, 0xF0, 0x03,
0xF0, 0x03, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xFC, 0x00,
0xFC, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E,
0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83,
0xE0, 0xF8, 0x3E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x01, 0xF8,
0x01, 0xF0, 0x03, 0xE0, 0x07, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF8, 0x01,
0xF0, 0x03, 0xE0, 0x07, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x80, 0x1F,
0x00, 0x3E, 0x00, 0x7E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0xF0,
0x03, 0xE0, 0x07, 0xE0, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07,
0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0,
0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F,
0x07, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xC0, 0x01, 0xF0,
0x01, 0xFC, 0x00, 0xFE, 0x00, 0xFF, 0x80, 0x7B, 0xC0, 0x7D, 0xF0, 0x7C,
0x7C, 0x3C, 0x1E, 0x3E, 0x0F, 0xBE, 0x03, 0xEF, 0x01, 0xE1, 0x00, 0x40,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0xE3, 0xE3, 0xE3,
0xE3, 0x82, 0x00, 0x1F, 0xE0, 0xFF, 0xC3, 0xFF, 0x8F, 0xFF, 0x00, 0xFC,
0x01, 0xF1, 0xFF, 0xDF, 0xFF, 0x7F, 0xFF, 0xF1, 0xFF, 0x87, 0xFE, 0x1F,
0xFF, 0xFD, 0xFF, 0xF7, 0xFF, 0xC7, 0xFC, 0x38, 0x00, 0xF8, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xFB,
0xE0, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xFE, 0xF8, 0x3E, 0xF8, 0x3F, 0xF8,
0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x3F, 0xF8, 0x7E, 0xFF,
0xFE, 0xFF, 0xFC, 0xFF, 0xF8, 0x3F, 0xE0, 0x03, 0xF8, 0x3F, 0xF3, 0xFF,
0xDF, 0xFE, 0x7E, 0x03, 0xF0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0,
0x0F, 0xC0, 0x1F, 0x80, 0x7F, 0xFC, 0xFF, 0xF1, 0xFF, 0xC1, 0xFE, 0x00,
0x07, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00,
0x1F, 0x00, 0x1F, 0x07, 0xDF, 0x1F, 0xFF, 0x3F, 0xFF, 0x7F, 0xFF, 0x7C,
0x1F, 0xFC, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC,
0x1F, 0x7E, 0x1F, 0x7F, 0xFF, 0x3F, 0xFF, 0x1F, 0xFF, 0x07, 0xFC, 0x07,
0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0x7C, 0x3F, 0xF8, 0x1F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x04, 0x7F,
0xFE, 0x3F, 0xFE, 0x1F, 0xFE, 0x07, 0xF8, 0x0F, 0xE3, 0xFF, 0x7F, 0xE7,
0xFE, 0xFC, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF,
0xFE, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F,
0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x07, 0xF8, 0x3F, 0xFC, 0xFF,
0xFB, 0xFF, 0xF7, 0xC3, 0xFF, 0x87, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F,
0xF0, 0x7F, 0xF0, 0xFB, 0xFF, 0xF7, 0xFF, 0xE7, 0xFF, 0xC3, 0xFF, 0x80,
0x1F, 0x00, 0x3E, 0x40, 0xFD, 0xFF, 0xF3, 0xFF, 0xE7, 0xFF, 0x03, 0xF8,
0x00, 0x38, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F,
0x80, 0x3E, 0x00, 0xFF, 0xE3, 0xFF, 0xCF, 0xFF, 0xBF, 0xFE, 0xF8, 0xFF,
0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F,
0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0x77, 0xFF, 0xF7, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x07,
0xC3, 0xE1, 0xF0, 0x70, 0x00, 0x00, 0x00, 0x0F, 0x87, 0xC3, 0xE1, 0xF0,
0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E,
0x1F, 0x0F, 0x8F, 0xFF, 0xFF, 0xEF, 0xE7, 0xE0, 0x38, 0x01, 0xF0, 0x03,
0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8,
0xFF, 0xF1, 0xFB, 0xE7, 0xE7, 0xDF, 0x8F, 0xFF, 0x1F, 0xFC, 0x3F, 0xF0,
0x7F, 0xC0, 0xFF, 0xC1, 0xFF, 0xC3, 0xFF, 0xC7, 0xDF, 0x8F, 0x9F, 0x9F,
0x1F, 0xBE, 0x3F, 0x7C, 0x3F, 0x38, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xFC, 0xFF, 0x7F, 0x7F, 0x1E, 0x3F, 0xC3, 0xF1, 0xFF, 0xFF, 0xF3, 0xFF,
0xFF, 0xF7, 0xFF, 0xFF, 0xEF, 0x8F, 0xC7, 0xFF, 0x0F, 0x87, 0xFE, 0x1F,
0x0F, 0xFC, 0x3E, 0x1F, 0xF8, 0x7C, 0x3F, 0xF0, 0xF8, 0x7F, 0xE1, 0xF0,
0xFF, 0xC3, 0xE1, 0xFF, 0x87, 0xC3, 0xFF, 0x0F, 0x87, 0xFE, 0x1F, 0x0F,
0xFC, 0x3E, 0x1F, 0x3F, 0xC3, 0xFF, 0xCF, 0xFF, 0xBF, 0xFE, 0xF8, 0xFF,
0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F,
0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0x07, 0xF0, 0x0F, 0xFE, 0x0F,
0xFF, 0x8F, 0xFF, 0xE7, 0xE3, 0xF7, 0xE0, 0xFF, 0xE0, 0x3F, 0xF0, 0x1F,
0xF8, 0x0F, 0xFC, 0x07, 0xFF, 0x07, 0xEF, 0xC7, 0xE7, 0xFF, 0xF1, 0xFF,
0xF0, 0x7F, 0xF0, 0x0F, 0xE0, 0x3F, 0xC0, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF,
0xFE, 0xF8, 0x7E, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
0x1F, 0xF8, 0x3F, 0xF8, 0x3E, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8, 0xFB,
0xF0, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8,
0x00, 0x03, 0xFE, 0x0F, 0xFF, 0xCF, 0xFF, 0xEF, 0xFF, 0xF7, 0xE0, 0xFF,
0xE0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFF, 0x03,
0xEF, 0xC1, 0xF7, 0xFF, 0xF9, 0xFF, 0xFC, 0x7F, 0xFE, 0x0F, 0xDF, 0x00,
0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C,
0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8,
0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0x0F, 0xE1,
0xFF, 0x9F, 0xFD, 0xFF, 0xEF, 0x81, 0x7C, 0x03, 0xFF, 0xDF, 0xFE, 0x7F,
0xF9, 0xFF, 0xC0, 0x3F, 0x81, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0x8F, 0xF0,
0x38, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE,
0xFF, 0xEF, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80,
0xFC, 0x0F, 0xFE, 0x7F, 0xE3, 0xFF, 0x0F, 0xE0, 0xF8, 0x7F, 0xE1, 0xFF,
0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F,
0xE1, 0xFF, 0x87, 0xFF, 0x1F, 0x7F, 0xFD, 0xFF, 0xF3, 0xFF, 0xC3, 0xFC,
0xF8, 0x0F, 0xFE, 0x0F, 0xDF, 0x07, 0xCF, 0x83, 0xE7, 0xE3, 0xF1, 0xF1,
0xF0, 0xF8, 0xF8, 0x7E, 0xFC, 0x1F, 0x7C, 0x0F, 0xBE, 0x03, 0xFE, 0x01,
0xFF, 0x00, 0xFF, 0x00, 0x3F, 0x80, 0x1F, 0xC0, 0x07, 0xC0, 0xF8, 0x38,
0x1F, 0xF8, 0x3C, 0x1F, 0x7C, 0x7C, 0x3E, 0x7C, 0x7C, 0x3E, 0x7C, 0x7E,
0x3E, 0x3C, 0x7E, 0x3C, 0x3C, 0xFE, 0x3C, 0x3E, 0xEE, 0x7C, 0x1E, 0xEF,
0x78, 0x1E, 0xEF, 0x78, 0x1F, 0xE7, 0xF8, 0x0F, 0xC7, 0xF0, 0x0F, 0xC3,
0xF0, 0x0F, 0xC3, 0xF0, 0x07, 0x83, 0xE0, 0x07, 0x81, 0xE0, 0xFC, 0x1F,
0xBF, 0x1F, 0x8F, 0xDF, 0x87, 0xEF, 0xC1, 0xFF, 0xC0, 0x7F, 0xC0, 0x3F,
0xE0, 0x0F, 0xE0, 0x07, 0xF0, 0x07, 0xF8, 0x03, 0xFE, 0x03, 0xFF, 0x83,
0xF7, 0xE1, 0xFB, 0xF1, 0xF8, 0xFD, 0xF8, 0x3F, 0xF8, 0x0F, 0xFE, 0x0F,
0xDF, 0x07, 0xCF, 0x83, 0xE7, 0xC3, 0xF1, 0xF1, 0xF0, 0xF8, 0xF8, 0x7C,
0x78, 0x1F, 0x7C, 0x0F, 0xBE, 0x03, 0xDE, 0x01, 0xFF, 0x00, 0x7F, 0x00,
0x3F, 0x80, 0x0F, 0xC0, 0x07, 0xC0, 0x03, 0xE0, 0x03, 0xE0, 0x1F, 0xF0,
0x1F, 0xF0, 0x0F, 0xF0, 0x03, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x03, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF8, 0x1F, 0xC0, 0xFE,
0x03, 0xF0, 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03,
0xE1, 0xFC, 0x3F, 0x8F, 0xF1, 0xF8, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03,
0xE0, 0x7C, 0x0F, 0x83, 0xF1, 0xFC, 0x3F, 0x87, 0xE0, 0xFE, 0x07, 0xE0,
0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xF0, 0x7F,
0x87, 0xF0, 0x7E, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0x83, 0xF8,
0x7F, 0x83, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F,
0x81, 0xF8, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE3, 0xF0, 0x7C, 0x0F, 0x81,
0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x07, 0xE3, 0xFC, 0x7F, 0x0F, 0xE1,
0xF0, 0x00, 0x1E, 0x06, 0x3F, 0x8F, 0x7F, 0xFF, 0xFF, 0xFE, 0xF1, 0xFC,
0x60, 0x78 };
const GFXglyph Ubuntu_Bold16pt7bGlyphs[] PROGMEM = {
{ 0, 0, 0, 7, 0, 1 }, // 0x20 ' '
{ 0, 5, 21, 9, 2, -20 }, // 0x21 '!'
{ 14, 12, 9, 14, 2, -23 }, // 0x22 '"'
{ 28, 18, 21, 22, 2, -20 }, // 0x23 '#'
{ 76, 16, 28, 18, 1, -23 }, // 0x24 '$'
{ 132, 26, 21, 28, 1, -20 }, // 0x25 '%'
{ 201, 21, 21, 22, 1, -20 }, // 0x26 '&'
{ 257, 5, 9, 9, 2, -23 }, // 0x27 '''
{ 263, 9, 30, 11, 2, -23 }, // 0x28 '('
{ 297, 9, 30, 11, 0, -23 }, // 0x29 ')'
{ 331, 13, 12, 16, 2, -20 }, // 0x2A '*'
{ 351, 14, 14, 18, 2, -15 }, // 0x2B '+'
{ 376, 6, 10, 8, 1, -4 }, // 0x2C ','
{ 384, 9, 4, 11, 1, -10 }, // 0x2D '-'
{ 389, 6, 6, 8, 1, -5 }, // 0x2E '.'
{ 394, 15, 30, 14, -1, -23 }, // 0x2F '/'
{ 451, 16, 21, 18, 1, -20 }, // 0x30 '0'
{ 493, 10, 21, 18, 3, -20 }, // 0x31 '1'
{ 520, 15, 21, 18, 1, -20 }, // 0x32 '2'
{ 560, 15, 21, 18, 1, -20 }, // 0x33 '3'
{ 600, 16, 21, 18, 1, -20 }, // 0x34 '4'
{ 642, 15, 21, 18, 1, -20 }, // 0x35 '5'
{ 682, 16, 21, 18, 1, -20 }, // 0x36 '6'
{ 724, 16, 21, 18, 1, -20 }, // 0x37 '7'
{ 766, 16, 21, 18, 1, -20 }, // 0x38 '8'
{ 808, 16, 21, 18, 1, -20 }, // 0x39 '9'
{ 850, 6, 17, 8, 1, -16 }, // 0x3A ':'
{ 863, 6, 22, 8, 1, -16 }, // 0x3B ';'
{ 880, 15, 15, 18, 1, -16 }, // 0x3C '<'
{ 909, 15, 11, 18, 1, -14 }, // 0x3D '='
{ 930, 14, 15, 18, 2, -16 }, // 0x3E '>'
{ 957, 12, 24, 14, 1, -23 }, // 0x3F '?'
{ 993, 26, 27, 30, 2, -21 }, // 0x40 '@'
{ 1081, 21, 21, 21, 0, -20 }, // 0x41 'A'
{ 1137, 17, 21, 21, 2, -20 }, // 0x42 'B'
{ 1182, 17, 21, 20, 2, -20 }, // 0x43 'C'
{ 1227, 19, 21, 23, 2, -20 }, // 0x44 'D'
{ 1277, 16, 21, 19, 2, -20 }, // 0x45 'E'
{ 1319, 15, 21, 18, 2, -20 }, // 0x46 'F'
{ 1359, 18, 21, 22, 2, -20 }, // 0x47 'G'
{ 1407, 19, 21, 23, 2, -20 }, // 0x48 'H'
{ 1457, 5, 21, 9, 2, -20 }, // 0x49 'I'
{ 1471, 14, 21, 16, 0, -20 }, // 0x4A 'J'
{ 1508, 19, 21, 21, 2, -20 }, // 0x4B 'K'
{ 1558, 14, 21, 17, 2, -20 }, // 0x4C 'L'
{ 1595, 24, 21, 28, 2, -20 }, // 0x4D 'M'
{ 1658, 19, 21, 23, 2, -20 }, // 0x4E 'N'
{ 1708, 20, 21, 24, 2, -20 }, // 0x4F 'O'
{ 1761, 17, 21, 20, 2, -20 }, // 0x50 'P'
{ 1806, 20, 27, 24, 2, -20 }, // 0x51 'Q'
{ 1874, 18, 21, 21, 2, -20 }, // 0x52 'R'
{ 1922, 16, 21, 18, 1, -20 }, // 0x53 'S'
{ 1964, 17, 21, 19, 1, -20 }, // 0x54 'T'
{ 2009, 18, 21, 22, 2, -20 }, // 0x55 'U'
{ 2057, 21, 21, 21, 0, -20 }, // 0x56 'V'
{ 2113, 29, 21, 31, 1, -20 }, // 0x57 'W'
{ 2190, 21, 21, 21, 0, -20 }, // 0x58 'X'
{ 2246, 21, 21, 21, 0, -20 }, // 0x59 'Y'
{ 2302, 17, 21, 19, 1, -20 }, // 0x5A 'Z'
{ 2347, 10, 30, 12, 2, -23 }, // 0x5B '['
{ 2385, 15, 30, 14, -1, -23 }, // 0x5C '\'
{ 2442, 10, 30, 12, 0, -23 }, // 0x5D ']'
{ 2480, 17, 13, 19, 1, -21 }, // 0x5E '^'
{ 2508, 16, 4, 16, 0, 3 }, // 0x5F '_'
{ 2516, 7, 7, 9, 1, -24 }, // 0x60 '`'
{ 2523, 14, 16, 17, 1, -15 }, // 0x61 'a'
{ 2551, 16, 24, 19, 2, -23 }, // 0x62 'b'
{ 2599, 14, 16, 16, 1, -15 }, // 0x63 'c'
{ 2627, 16, 24, 19, 1, -23 }, // 0x64 'd'
{ 2675, 16, 16, 18, 1, -15 }, // 0x65 'e'
{ 2707, 12, 24, 14, 2, -23 }, // 0x66 'f'
{ 2743, 15, 22, 18, 1, -15 }, // 0x67 'g'
{ 2785, 14, 24, 18, 2, -23 }, // 0x68 'h'
{ 2827, 5, 24, 9, 2, -23 }, // 0x69 'i'
{ 2842, 9, 30, 9, -2, -23 }, // 0x6A 'j'
{ 2876, 15, 24, 18, 2, -23 }, // 0x6B 'k'
{ 2921, 8, 24, 10, 2, -23 }, // 0x6C 'l'
{ 2945, 23, 16, 27, 2, -15 }, // 0x6D 'm'
{ 2991, 14, 16, 18, 2, -15 }, // 0x6E 'n'
{ 3019, 17, 16, 19, 1, -15 }, // 0x6F 'o'
{ 3053, 16, 22, 19, 2, -15 }, // 0x70 'p'
{ 3097, 17, 22, 19, 1, -15 }, // 0x71 'q'
{ 3144, 11, 16, 13, 2, -15 }, // 0x72 'r'
{ 3166, 13, 16, 15, 1, -15 }, // 0x73 's'
{ 3192, 12, 21, 15, 2, -20 }, // 0x74 't'
{ 3224, 14, 16, 18, 2, -15 }, // 0x75 'u'
{ 3252, 17, 16, 17, 0, -15 }, // 0x76 'v'
{ 3286, 24, 16, 24, 0, -15 }, // 0x77 'w'
{ 3334, 17, 16, 17, 0, -15 }, // 0x78 'x'
{ 3368, 17, 22, 17, 0, -15 }, // 0x79 'y'
{ 3415, 14, 16, 16, 1, -15 }, // 0x7A 'z'
{ 3443, 11, 30, 12, 1, -23 }, // 0x7B '{'
{ 3485, 4, 30, 10, 3, -23 }, // 0x7C '|'
{ 3500, 11, 30, 12, 0, -23 }, // 0x7D '}'
{ 3542, 16, 6, 18, 1, -11 } }; // 0x7E '~'
const GFXfont Ubuntu_Bold16pt7b PROGMEM = {
(uint8_t *)Ubuntu_Bold16pt7bBitmaps,
(GFXglyph *)Ubuntu_Bold16pt7bGlyphs,
0x20, 0x7E, 36 };
// Approx. 4226 bytes

View File

@@ -0,0 +1,578 @@
const uint8_t Ubuntu_Bold20pt7bBitmaps[] PROGMEM = {
0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,
0x7E, 0x7E, 0x7E, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x3C, 0x7E, 0xFF, 0xFF,
0xFF, 0x7E, 0x3C, 0xFC, 0x7F, 0xF8, 0xFF, 0xF1, 0xFF, 0xE3, 0xFF, 0xC7,
0xFF, 0x8F, 0xFF, 0x1F, 0xFE, 0x3F, 0xF8, 0x7C, 0xF0, 0x79, 0xE0, 0xF0,
0x01, 0xF9, 0xF8, 0x03, 0xF3, 0xF0, 0x07, 0xEF, 0xE0, 0x1F, 0x9F, 0x80,
0x3F, 0x3F, 0x00, 0x7E, 0x7E, 0x00, 0xFC, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0x3F, 0x00, 0x7E,
0x7E, 0x01, 0xFD, 0xFC, 0x03, 0xF3, 0xF0, 0x07, 0xE7, 0xE0, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xF9, 0xF8,
0x03, 0xF3, 0xF0, 0x07, 0xE7, 0xE0, 0x0F, 0xCF, 0xC0, 0x3F, 0xBF, 0x00,
0x7E, 0x7E, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03,
0xE0, 0x00, 0x7C, 0x00, 0x1F, 0xF0, 0x1F, 0xFF, 0x87, 0xFF, 0xF1, 0xFF,
0xFE, 0x3F, 0xFF, 0x8F, 0xE0, 0x71, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xF0,
0x00, 0xFF, 0x80, 0x1F, 0xFE, 0x01, 0xFF, 0xF0, 0x1F, 0xFF, 0x81, 0xFF,
0xF8, 0x0F, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0xFE, 0x00, 0x0F, 0xC0, 0x01,
0xF8, 0x00, 0x3F, 0x78, 0x0F, 0xEF, 0xFF, 0xF9, 0xFF, 0xFF, 0x7F, 0xFF,
0xC7, 0xFF, 0xF0, 0x1F, 0xF8, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8,
0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0x80, 0x03, 0xF0, 0x0F, 0xF8,
0x01, 0xF8, 0x07, 0xFF, 0x00, 0x7E, 0x01, 0xFF, 0xC0, 0x3F, 0x00, 0xF8,
0xF8, 0x0F, 0x80, 0x3C, 0x1E, 0x07, 0xE0, 0x0F, 0x07, 0x83, 0xF0, 0x03,
0xC1, 0xE0, 0xF8, 0x00, 0xF0, 0x78, 0x7E, 0x00, 0x3C, 0x1E, 0x1F, 0x00,
0x0F, 0x07, 0x8F, 0xC0, 0x03, 0xE3, 0xE7, 0xE1, 0xF0, 0x7F, 0xF1, 0xF1,
0xFF, 0x1F, 0xFC, 0xFC, 0xFF, 0xE3, 0xFE, 0x3E, 0x3F, 0xF8, 0x3E, 0x1F,
0x9F, 0x1F, 0x00, 0x0F, 0xC7, 0x83, 0xC0, 0x03, 0xE1, 0xE0, 0xF0, 0x01,
0xF8, 0x78, 0x3C, 0x00, 0x7C, 0x1E, 0x0F, 0x00, 0x3F, 0x07, 0x83, 0xC0,
0x1F, 0x81, 0xE0, 0xF0, 0x07, 0xC0, 0x7C, 0x7C, 0x03, 0xF0, 0x0F, 0xFE,
0x01, 0xF8, 0x03, 0xFF, 0x80, 0x7E, 0x00, 0x7F, 0xC0, 0x3F, 0x00, 0x07,
0xC0, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x07,
0xFF, 0xF0, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0x8F, 0xC0, 0x07, 0xE1, 0xF8,
0x00, 0xFC, 0x3F, 0x00, 0x1F, 0xCF, 0xC0, 0x01, 0xFF, 0xF8, 0x00, 0x3F,
0xFE, 0x00, 0x03, 0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x3F, 0xFC, 0x3E,
0x0F, 0xFF, 0xC7, 0xE3, 0xFB, 0xFC, 0xFC, 0x7E, 0x3F, 0xFF, 0x1F, 0x83,
0xFF, 0xE3, 0xF0, 0x3F, 0xF8, 0x7E, 0x07, 0xFF, 0x0F, 0xC0, 0x7F, 0xC1,
0xFE, 0x07, 0xFC, 0x1F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF,
0xFF, 0x83, 0xFF, 0xF7, 0xF8, 0x0F, 0xF0, 0x7F, 0x80, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xF9, 0xE7, 0x80, 0x01, 0x00, 0x70, 0x1F, 0x87, 0xE0,
0xFC, 0x3F, 0x07, 0xE1, 0xF8, 0x3F, 0x07, 0xE1, 0xF8, 0x3F, 0x07, 0xE1,
0xFC, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8,
0x3F, 0x07, 0xE0, 0xFC, 0x0F, 0xC1, 0xF8, 0x3F, 0x03, 0xF0, 0x7E, 0x0F,
0xC0, 0xFC, 0x1F, 0x81, 0xF8, 0x3F, 0x03, 0xF0, 0x38, 0x02, 0x00, 0x10,
0x07, 0x03, 0xF0, 0x3F, 0x07, 0xE0, 0x7E, 0x0F, 0xC0, 0xFC, 0x1F, 0x83,
0xF0, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x81, 0xF8, 0x3F, 0x07, 0xE0, 0xFC,
0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x0F, 0xE1, 0xF8, 0x3F,
0x07, 0xE1, 0xF8, 0x3F, 0x07, 0xE1, 0xF8, 0x3F, 0x0F, 0xC1, 0xF8, 0x7E,
0x03, 0x80, 0x20, 0x00, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x0C, 0x7C,
0x67, 0x9C, 0xF3, 0xEE, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFC, 0x03,
0xF8, 0x03, 0xDE, 0x03, 0xEF, 0x83, 0xF7, 0xE0, 0xF1, 0xE0, 0x38, 0xE0,
0x08, 0x20, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00,
0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0x00, 0x03, 0xE0, 0x00,
0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x7E, 0x7E, 0x7E, 0x7C, 0xFC, 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x38, 0xFB, 0xFF, 0xFF, 0xEF,
0x8E, 0x00, 0x00, 0x07, 0xE0, 0x01, 0xFC, 0x00, 0x3F, 0x00, 0x07, 0xE0,
0x01, 0xFC, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x01, 0xFC, 0x00, 0x3F, 0x00,
0x07, 0xE0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x01, 0xF8, 0x00,
0x3F, 0x00, 0x07, 0xE0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x01,
0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07,
0xE0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x01, 0xF8, 0x00, 0x3F,
0x00, 0x0F, 0xE0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x0F, 0xE0, 0x01, 0xF8,
0x00, 0x3F, 0x00, 0x0F, 0xE0, 0x01, 0xF8, 0x00, 0x00, 0x01, 0xF8, 0x00,
0x7F, 0xE0, 0x0F, 0xFF, 0x01, 0xFF, 0xF8, 0x3F, 0xFF, 0xC3, 0xF0, 0xFE,
0x7E, 0x07, 0xE7, 0xE0, 0x7E, 0xFE, 0x07, 0xEF, 0xC0, 0x3F, 0xFC, 0x03,
0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0,
0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFC, 0x07, 0xF7, 0xE0, 0x7E, 0x7E,
0x07, 0xE7, 0xF0, 0xFE, 0x3F, 0xFF, 0xC1, 0xFF, 0xF8, 0x1F, 0xFF, 0x00,
0x7F, 0xE0, 0x01, 0xF8, 0x00, 0x00, 0xF8, 0x0F, 0xC0, 0xFE, 0x0F, 0xF1,
0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xBF, 0x79, 0xF9, 0x0F, 0xC0, 0x7E, 0x03,
0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E,
0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0,
0x7E, 0x07, 0xF8, 0x03, 0xFF, 0xC1, 0xFF, 0xFC, 0x7F, 0xFF, 0xC7, 0xFF,
0xFC, 0xF8, 0x3F, 0x8C, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01,
0xF8, 0x00, 0x7E, 0x00, 0x1F, 0xC0, 0x07, 0xF0, 0x01, 0xFE, 0x00, 0x7F,
0x80, 0x1F, 0xE0, 0x07, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0x80, 0x0F, 0xE0,
0x03, 0xF8, 0x00, 0x7E, 0x00, 0x1F, 0xFF, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF,
0xEF, 0xFF, 0xFD, 0xFF, 0xFF, 0x80, 0x07, 0xF0, 0x07, 0xFF, 0xC3, 0xFF,
0xFC, 0x3F, 0xFF, 0xC7, 0xFF, 0xF8, 0x70, 0x3F, 0x88, 0x03, 0xF0, 0x00,
0x7E, 0x00, 0x0F, 0xC0, 0x07, 0xF8, 0x3F, 0xFE, 0x07, 0xFF, 0x80, 0xFF,
0xE0, 0x1F, 0xFE, 0x03, 0xFF, 0xF0, 0x01, 0xFE, 0x00, 0x0F, 0xE0, 0x00,
0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0xFE, 0xE0, 0x3F, 0xDF, 0xFF,
0xF7, 0xFF, 0xFE, 0xFF, 0xFF, 0x9F, 0xFF, 0xC0, 0x3F, 0xC0, 0x00, 0x00,
0x1F, 0x80, 0x03, 0xF8, 0x00, 0x7F, 0x80, 0x0F, 0xF8, 0x01, 0xFF, 0x80,
0x1F, 0xF8, 0x03, 0xFF, 0x80, 0x7F, 0xF8, 0x07, 0xDF, 0x80, 0xF9, 0xF8,
0x1F, 0x9F, 0x81, 0xF1, 0xF8, 0x3E, 0x1F, 0x83, 0xE1, 0xF8, 0x7C, 0x1F,
0x8F, 0xC1, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x01, 0xF8, 0x00,
0x1F, 0x80, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x1F, 0xFF, 0xC3, 0xFF, 0xF8,
0x7F, 0xFF, 0x0F, 0xFF, 0xE1, 0xFF, 0xFC, 0x3E, 0x00, 0x07, 0xC0, 0x00,
0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFF, 0x80, 0x1F, 0xFE, 0x03,
0xFF, 0xF0, 0x7F, 0xFF, 0x0F, 0xFF, 0xF0, 0x03, 0xFE, 0x00, 0x0F, 0xE0,
0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0xFE, 0xC0, 0x3F, 0xDF,
0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0xFF, 0x1F, 0xFF, 0xC0, 0x7F, 0xC0, 0x00,
0x00, 0x07, 0xC0, 0x07, 0xFC, 0x01, 0xFF, 0xC0, 0x3F, 0xFC, 0x0F, 0xFF,
0xC1, 0xFF, 0xC0, 0x1F, 0xE0, 0x03, 0xF8, 0x00, 0x7F, 0x00, 0x07, 0xE0,
0x00, 0x7F, 0xFC, 0x0F, 0xFF, 0xF8, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0xFF,
0xFF, 0xEF, 0xC0, 0xFF, 0xFC, 0x07, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF,
0xC0, 0x3F, 0x7E, 0x07, 0xF7, 0xF0, 0xFE, 0x3F, 0xFF, 0xE3, 0xFF, 0xFC,
0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x01, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x07, 0xE0, 0x03, 0xF0,
0x01, 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x07, 0xE0, 0x01,
0xF8, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x07, 0xE0, 0x01, 0xF8,
0x00, 0x7E, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00,
0x7E, 0x00, 0x1F, 0x80, 0x07, 0xE0, 0x01, 0xF8, 0x00, 0x03, 0xF8, 0x01,
0xFF, 0xC0, 0x7F, 0xFC, 0x1F, 0xFF, 0xC3, 0xFF, 0xFC, 0xFE, 0x3F, 0x9F,
0x83, 0xF3, 0xF0, 0x7E, 0x7E, 0x0F, 0xCF, 0xE3, 0xF0, 0xFE, 0x7E, 0x0F,
0xFF, 0x80, 0xFF, 0xE0, 0x1F, 0xFE, 0x07, 0xFF, 0xE1, 0xF9, 0xFE, 0x7E,
0x0F, 0xDF, 0x80, 0xFF, 0xF0, 0x1F, 0xFE, 0x03, 0xFF, 0xC0, 0x7F, 0xFC,
0x1F, 0xDF, 0xFF, 0xF3, 0xFF, 0xFE, 0x3F, 0xFF, 0x83, 0xFF, 0xE0, 0x0F,
0xE0, 0x00, 0x03, 0xF8, 0x01, 0xFF, 0xC0, 0x7F, 0xFC, 0x1F, 0xFF, 0xC7,
0xFF, 0xF8, 0xFE, 0x3F, 0xBF, 0x83, 0xF7, 0xE0, 0x3F, 0xFC, 0x07, 0xFF,
0x80, 0xFF, 0xF0, 0x1F, 0xFF, 0x03, 0xF7, 0xFF, 0xFE, 0xFF, 0xFF, 0xCF,
0xFF, 0xF8, 0xFF, 0xFF, 0x07, 0xFF, 0xE0, 0x01, 0xF8, 0x00, 0x7F, 0x00,
0x0F, 0xC0, 0x07, 0xF8, 0x07, 0xFE, 0x0F, 0xFF, 0x81, 0xFF, 0xE0, 0x3F,
0xF8, 0x07, 0xFC, 0x00, 0xF8, 0x00, 0x00, 0x38, 0xFB, 0xFF, 0xFF, 0xEF,
0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x3E, 0xFF, 0xFF, 0xFB,
0xE3, 0x80, 0x1C, 0x3E, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x7E, 0x7E,
0x7E, 0x7C, 0xFC, 0x18, 0x00, 0x01, 0x80, 0x01, 0xF0, 0x01, 0xFF, 0x03,
0xFF, 0xE3, 0xFF, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0xC7, 0xFF, 0xC0, 0xFF,
0x80, 0x1F, 0x80, 0x03, 0xFE, 0x00, 0x7F, 0xFC, 0x0F, 0xFF, 0xF1, 0xFF,
0xFF, 0x8F, 0xFF, 0xF0, 0x3F, 0xFE, 0x00, 0x7F, 0xC0, 0x01, 0xF0, 0x00,
0x06, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x30, 0x00,
0x07, 0xC0, 0x01, 0xFF, 0x00, 0x3F, 0xFE, 0x07, 0xFF, 0xF8, 0xFF, 0xFF,
0xC7, 0xFF, 0xF8, 0x1F, 0xFF, 0x00, 0x3F, 0xE0, 0x00, 0xFC, 0x00, 0xFF,
0x81, 0xFF, 0xF1, 0xFF, 0xFE, 0xFF, 0xFF, 0xDF, 0xFF, 0xE3, 0xFF, 0xE0,
0x7F, 0xC0, 0x07, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x7F, 0xF8,
0xFF, 0xFC, 0x7F, 0xFE, 0x7F, 0xFF, 0x70, 0x7F, 0x00, 0x3F, 0x00, 0x3F,
0x00, 0x3F, 0x00, 0x7E, 0x00, 0xFE, 0x01, 0xFC, 0x01, 0xF8, 0x03, 0xF8,
0x03, 0xF0, 0x07, 0xE0, 0x07, 0xC0, 0x07, 0xC0, 0x07, 0xC0, 0x00, 0x00,
0x00, 0x00, 0x03, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0,
0x07, 0xC0, 0x03, 0x80, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xE0,
0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0xE0, 0x07, 0xFC, 0x07,
0xFC, 0x03, 0xF8, 0x00, 0x3F, 0x81, 0xFC, 0x00, 0x07, 0xF0, 0x7C, 0x00,
0x00, 0xFC, 0x3F, 0x01, 0xFC, 0x1F, 0x8F, 0x81, 0xFF, 0xC3, 0xE7, 0xC1,
0xFF, 0xF0, 0xF9, 0xF0, 0x7F, 0xFC, 0x1F, 0xFC, 0x3F, 0x1F, 0x07, 0xFE,
0x0F, 0x87, 0xC1, 0xFF, 0x87, 0xC1, 0xF0, 0x7F, 0xE1, 0xF0, 0x7C, 0x1F,
0xF8, 0x7C, 0x1F, 0x07, 0xFE, 0x1F, 0x07, 0xC1, 0xFF, 0x87, 0xC1, 0xF0,
0x7F, 0xE1, 0xF0, 0x7C, 0x3E, 0xF8, 0x7E, 0x1F, 0x0F, 0xBF, 0x0F, 0xC7,
0xC7, 0xE7, 0xC3, 0xFF, 0xFF, 0xF1, 0xF0, 0x7F, 0xFF, 0xF8, 0x7E, 0x0F,
0xFF, 0xFC, 0x0F, 0x80, 0xF8, 0xFC, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x7E,
0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x20, 0x00,
0x3F, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xC0,
0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00,
0x01, 0xFF, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x0F, 0xFE, 0x00, 0x01, 0xFF,
0xC0, 0x00, 0x7E, 0xF8, 0x00, 0x0F, 0xDF, 0x80, 0x01, 0xFB, 0xF0, 0x00,
0x7E, 0x3F, 0x00, 0x0F, 0xC7, 0xE0, 0x03, 0xF8, 0xFC, 0x00, 0x7E, 0x0F,
0xC0, 0x0F, 0xC1, 0xF8, 0x03, 0xF8, 0x3F, 0x80, 0x7E, 0x03, 0xF0, 0x0F,
0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF,
0x83, 0xFF, 0xFF, 0xF8, 0x7E, 0x00, 0x3F, 0x1F, 0xC0, 0x07, 0xE3, 0xF8,
0x00, 0xFE, 0x7E, 0x00, 0x0F, 0xDF, 0xC0, 0x01, 0xFB, 0xF8, 0x00, 0x3F,
0x80, 0x7F, 0xFC, 0x07, 0xFF, 0xFC, 0x3F, 0xFF, 0xF1, 0xFF, 0xFF, 0xCF,
0xFF, 0xFF, 0x7E, 0x03, 0xFB, 0xF0, 0x0F, 0xDF, 0x80, 0x7E, 0xFC, 0x03,
0xF7, 0xE0, 0x7F, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0x8F, 0xFF, 0xFC, 0x7F,
0xFF, 0xF3, 0xFF, 0xFF, 0xDF, 0x80, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, 0x0F,
0xFF, 0x00, 0x7F, 0xF8, 0x03, 0xFF, 0xC0, 0x3F, 0xFE, 0x03, 0xFF, 0xFF,
0xFF, 0xDF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x0F, 0xFF, 0x00,
0x00, 0x3F, 0xC0, 0x07, 0xFF, 0xE0, 0x7F, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F,
0xFF, 0xF8, 0xFF, 0x81, 0xE3, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0x7E, 0x00,
0x03, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03,
0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF8,
0x00, 0x07, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0x80, 0x00, 0xFF, 0x00,
0xE1, 0xFF, 0xFF, 0x87, 0xFF, 0xFE, 0x0F, 0xFF, 0xFC, 0x0F, 0xFF, 0xE0,
0x07, 0xFC, 0x00, 0x7F, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xE0,
0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFC, 0x07, 0xFC, 0xFC, 0x01, 0xFC,
0xFC, 0x00, 0xFE, 0xFC, 0x00, 0x7E, 0xFC, 0x00, 0x7F, 0xFC, 0x00, 0x3F,
0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x3F,
0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xFC, 0x00, 0x7E,
0xFC, 0x00, 0xFE, 0xFC, 0x01, 0xFC, 0xFC, 0x0F, 0xFC, 0xFF, 0xFF, 0xF8,
0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x80, 0x7F, 0xF8, 0x00,
0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF,
0xEF, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0,
0x00, 0xFF, 0xFF, 0xCF, 0xFF, 0xFC, 0xFF, 0xFF, 0xCF, 0xFF, 0xFC, 0xFF,
0xFF, 0xCF, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F,
0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xC0, 0x03,
0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xFF, 0xFE, 0xFF,
0xFF, 0xBF, 0xFF, 0xEF, 0xFF, 0xFB, 0xFF, 0xFE, 0xFC, 0x00, 0x3F, 0x00,
0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03,
0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x7F, 0xC0,
0x07, 0xFF, 0xE0, 0x7F, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, 0xF8, 0xFF,
0x81, 0xE3, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0x7E, 0x00, 0x03, 0xF8, 0x00,
0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x03, 0xFF,
0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF8, 0x03, 0xF7, 0xE0,
0x0F, 0xDF, 0xC0, 0x3F, 0x7F, 0x80, 0xFC, 0xFF, 0x03, 0xF1, 0xFF, 0xFF,
0xC3, 0xFF, 0xFF, 0x07, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0x07, 0xFE, 0x00,
0xFC, 0x00, 0x7F, 0xF8, 0x00, 0xFF, 0xF0, 0x01, 0xFF, 0xE0, 0x03, 0xFF,
0xC0, 0x07, 0xFF, 0x80, 0x0F, 0xFF, 0x00, 0x1F, 0xFE, 0x00, 0x3F, 0xFC,
0x00, 0x7F, 0xF8, 0x00, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00,
0x7F, 0xF8, 0x00, 0xFF, 0xF0, 0x01, 0xFF, 0xE0, 0x03, 0xFF, 0xC0, 0x07,
0xFF, 0x80, 0x0F, 0xFF, 0x00, 0x1F, 0xFE, 0x00, 0x3F, 0xFC, 0x00, 0x7F,
0xF8, 0x00, 0xFF, 0xF0, 0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F,
0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0,
0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00,
0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F,
0x00, 0x1F, 0xDE, 0x0F, 0xE7, 0xFF, 0xF9, 0xFF, 0xFE, 0xFF, 0xFF, 0x1F,
0xFF, 0x00, 0xFF, 0x00, 0xFC, 0x01, 0xFE, 0xFC, 0x03, 0xFC, 0xFC, 0x07,
0xF8, 0xFC, 0x0F, 0xF0, 0xFC, 0x1F, 0xE0, 0xFC, 0x3F, 0xC0, 0xFC, 0x7F,
0x80, 0xFC, 0xFF, 0x00, 0xFD, 0xFE, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0xF8,
0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xE0, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xF8,
0x00, 0xFF, 0xFC, 0x00, 0xFD, 0xFE, 0x00, 0xFC, 0xFE, 0x00, 0xFC, 0x7F,
0x00, 0xFC, 0x3F, 0x80, 0xFC, 0x3F, 0xC0, 0xFC, 0x1F, 0xE0, 0xFC, 0x0F,
0xF0, 0xFC, 0x07, 0xF8, 0xFC, 0x03, 0xFC, 0xFC, 0x01, 0xFE, 0xFC, 0x00,
0xFF, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00,
0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F,
0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0,
0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00,
0x3F, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFC, 0x3F, 0x00, 0x01, 0xF8, 0x7F, 0x00, 0x07, 0xF0, 0xFE, 0x00,
0x0F, 0xE1, 0xFE, 0x00, 0x3F, 0xC7, 0xFC, 0x00, 0x7F, 0xCF, 0xFC, 0x01,
0xFF, 0x9F, 0xF8, 0x03, 0xFF, 0x3F, 0xF8, 0x07, 0xFE, 0x7F, 0xF0, 0x1F,
0xFC, 0xFF, 0xE0, 0x3F, 0xF9, 0xFF, 0xE0, 0xFB, 0xF3, 0xF7, 0xC1, 0xF7,
0xE7, 0xEF, 0xC7, 0xEF, 0xCF, 0xCF, 0x8F, 0x9F, 0x9F, 0x9F, 0x1F, 0x3F,
0x3E, 0x1F, 0x7C, 0x3E, 0x7C, 0x3E, 0xF8, 0x7D, 0xF8, 0x7F, 0xE0, 0xFB,
0xF0, 0x7F, 0xC1, 0xFF, 0xE0, 0xFF, 0x03, 0xFF, 0xC0, 0xFE, 0x07, 0xFF,
0x81, 0xFC, 0x0F, 0xFF, 0x01, 0xF0, 0x1F, 0xFE, 0x03, 0xE0, 0x3F, 0xFC,
0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x01, 0xF8, 0xF8,
0x00, 0x7F, 0xF8, 0x00, 0xFF, 0xF8, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xF8,
0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0,
0x7F, 0xFF, 0xF0, 0xFF, 0xF7, 0xE1, 0xFF, 0xE7, 0xE3, 0xFF, 0xCF, 0xE7,
0xFF, 0x8F, 0xCF, 0xFF, 0x0F, 0xDF, 0xFE, 0x0F, 0xFF, 0xFC, 0x1F, 0xFF,
0xF8, 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0x3F, 0xFF,
0x80, 0x3F, 0xFF, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFC, 0x00, 0xFF, 0xF8,
0x00, 0xFF, 0xF0, 0x00, 0xF8, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0xFE, 0x00,
0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF0, 0x7F, 0xC1,
0xFF, 0x0F, 0xE0, 0x0F, 0xE3, 0xF8, 0x00, 0xFE, 0x7E, 0x00, 0x0F, 0xDF,
0xC0, 0x01, 0xFF, 0xF0, 0x00, 0x1F, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x00,
0x7F, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x3F, 0xFC,
0x00, 0x07, 0xFF, 0xC0, 0x01, 0xFD, 0xF8, 0x00, 0x3F, 0x3F, 0x80, 0x0F,
0xE3, 0xF8, 0x03, 0xF8, 0x7F, 0xC1, 0xFF, 0x07, 0xFF, 0xFF, 0xC0, 0x7F,
0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x00, 0x3F, 0xFE, 0x00, 0x01, 0xFF, 0x00,
0x00, 0x7F, 0xF8, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x8F, 0xFF, 0xFC, 0xFF,
0xFF, 0xEF, 0xC0, 0xFE, 0xFC, 0x07, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF,
0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x7F, 0xFC, 0x0F, 0xEF, 0xFF, 0xFE,
0xFF, 0xFF, 0xCF, 0xFF, 0xF8, 0xFF, 0xFF, 0x0F, 0xFF, 0x80, 0xFC, 0x00,
0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0,
0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x3F, 0xFE, 0x00, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0x01, 0xFF,
0xFF, 0xF0, 0x7F, 0xC1, 0xFF, 0x0F, 0xE0, 0x0F, 0xE3, 0xF8, 0x00, 0xFE,
0x7E, 0x00, 0x0F, 0xDF, 0xC0, 0x01, 0xFB, 0xF0, 0x00, 0x1F, 0xFE, 0x00,
0x03, 0xFF, 0xC0, 0x00, 0x7F, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x01, 0xFF,
0xE0, 0x00, 0x3F, 0xFC, 0x00, 0x07, 0xFF, 0xC0, 0x01, 0xFD, 0xF8, 0x00,
0x3F, 0x3F, 0x80, 0x0F, 0xE7, 0xF8, 0x03, 0xF8, 0x7F, 0xC1, 0xFF, 0x07,
0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x00, 0x7F, 0xFE,
0x00, 0x01, 0xFF, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00,
0x1F, 0xF0, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x03, 0xE0, 0x7F, 0xF8, 0x01, 0xFF, 0xFE, 0x03, 0xFF, 0xFF,
0x07, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x1F, 0x81, 0xFE, 0x3F, 0x00, 0xFE,
0x7E, 0x00, 0xFC, 0xFC, 0x01, 0xF9, 0xF8, 0x03, 0xF3, 0xF0, 0x0F, 0xE7,
0xE0, 0x3F, 0x8F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, 0x7F,
0xFF, 0x80, 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0x03, 0xF0, 0xFE, 0x07, 0xE0,
0xFE, 0x0F, 0xC0, 0xFE, 0x1F, 0x81, 0xFE, 0x3F, 0x01, 0xFC, 0x7E, 0x01,
0xFC, 0xFC, 0x03, 0xFD, 0xF8, 0x03, 0xFB, 0xF0, 0x03, 0xF8, 0x03, 0xFE,
0x00, 0xFF, 0xFC, 0x3F, 0xFF, 0xE7, 0xFF, 0xFC, 0x7F, 0xFF, 0xCF, 0xE0,
0x1C, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x7F,
0xC0, 0x07, 0xFF, 0x80, 0x3F, 0xFF, 0x01, 0xFF, 0xF8, 0x07, 0xFF, 0xC0,
0x0F, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0x00, 0x03, 0xF0, 0x00, 0x3F,
0x00, 0x03, 0xF7, 0x80, 0x7F, 0x7F, 0xFF, 0xE7, 0xFF, 0xFE, 0xFF, 0xFF,
0xC7, 0xFF, 0xF8, 0x0F, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xF0, 0x00, 0x0F,
0xC0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0,
0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00,
0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3F,
0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00,
0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0xFF,
0xF0, 0x03, 0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF0,
0x03, 0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF0, 0x03,
0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF0, 0x03, 0xFF,
0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF0, 0x03, 0xFF, 0xC0,
0x0F, 0xFF, 0x80, 0x7F, 0x7E, 0x01, 0xF9, 0xFE, 0x1F, 0xE7, 0xFF, 0xFF,
0x8F, 0xFF, 0xFC, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0x00, 0x1F, 0xE0, 0x00,
0xFE, 0x00, 0x0F, 0xEF, 0xC0, 0x01, 0xF9, 0xF8, 0x00, 0x3F, 0x3F, 0x80,
0x0F, 0xE3, 0xF0, 0x01, 0xF8, 0x7E, 0x00, 0x3F, 0x07, 0xE0, 0x0F, 0xC0,
0xFC, 0x01, 0xF8, 0x1F, 0x80, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x3F, 0x01,
0xF8, 0x07, 0xE0, 0x7E, 0x00, 0x7E, 0x0F, 0xC0, 0x0F, 0xC1, 0xF8, 0x00,
0xFC, 0x7E, 0x00, 0x1F, 0x8F, 0xC0, 0x03, 0xF1, 0xF8, 0x00, 0x3F, 0x7E,
0x00, 0x07, 0xEF, 0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x0F, 0xFE, 0x00, 0x01,
0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x07, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x03,
0xFF, 0xC0, 0x00, 0x00, 0x7F, 0x7E, 0x00, 0x00, 0x07, 0xE7, 0xE0, 0x1F,
0x00, 0x7E, 0x7E, 0x03, 0xF8, 0x07, 0xE7, 0xE0, 0x3F, 0x80, 0x7E, 0x7E,
0x03, 0xF8, 0x0F, 0xE3, 0xF0, 0x3F, 0xC0, 0xFC, 0x3F, 0x07, 0xFC, 0x0F,
0xC3, 0xF0, 0x7F, 0xC0, 0xFC, 0x3F, 0x07, 0xFE, 0x0F, 0xC1, 0xF8, 0x7B,
0xE1, 0xF8, 0x1F, 0x8F, 0xBE, 0x1F, 0x81, 0xF8, 0xFB, 0xF1, 0xF8, 0x1F,
0x8F, 0x9F, 0x1F, 0x80, 0xFC, 0xF1, 0xF3, 0xF0, 0x0F, 0xDF, 0x1F, 0xBF,
0x00, 0xFD, 0xF0, 0xFB, 0xF0, 0x07, 0xDF, 0x0F, 0xBE, 0x00, 0x7F, 0xE0,
0xFF, 0xE0, 0x07, 0xFE, 0x07, 0xFE, 0x00, 0x7F, 0xE0, 0x7F, 0xE0, 0x03,
0xFC, 0x07, 0xFC, 0x00, 0x3F, 0xC0, 0x3F, 0xC0, 0x03, 0xFC, 0x03, 0xFC,
0x00, 0x1F, 0xC0, 0x3F, 0x80, 0x01, 0xF8, 0x01, 0xF8, 0x00, 0xFE, 0x00,
0x1F, 0xDF, 0xC0, 0x0F, 0xE3, 0xF8, 0x07, 0xF0, 0xFF, 0x03, 0xFC, 0x1F,
0xC0, 0xFE, 0x03, 0xF8, 0x7F, 0x00, 0x7F, 0x3F, 0x80, 0x1F, 0xCF, 0xE0,
0x03, 0xFF, 0xF0, 0x00, 0x7F, 0xF8, 0x00, 0x1F, 0xFE, 0x00, 0x03, 0xFF,
0x00, 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF8, 0x00, 0x03,
0xFF, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xFF, 0x00,
0x1F, 0xCF, 0xE0, 0x0F, 0xE3, 0xF8, 0x03, 0xF8, 0x7F, 0x01, 0xFC, 0x0F,
0xE0, 0xFE, 0x01, 0xFC, 0x3F, 0x80, 0x7F, 0x1F, 0xC0, 0x0F, 0xEF, 0xE0,
0x01, 0xFC, 0xFE, 0x00, 0x1F, 0xDF, 0xC0, 0x0F, 0xE7, 0xF0, 0x03, 0xF8,
0xFE, 0x01, 0xFC, 0x3F, 0x80, 0x7F, 0x07, 0xF0, 0x3F, 0x80, 0xFC, 0x1F,
0xC0, 0x3F, 0x87, 0xF0, 0x07, 0xF3, 0xF8, 0x01, 0xFC, 0xFE, 0x00, 0x3F,
0xFF, 0x00, 0x07, 0xFF, 0x80, 0x01, 0xFF, 0xE0, 0x00, 0x3F, 0xF0, 0x00,
0x0F, 0xF8, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x0F, 0xC0,
0x00, 0x03, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x0F,
0xC0, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x3F, 0x00, 0x00,
0x0F, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7,
0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0x00, 0x1F, 0xE0, 0x00,
0x7F, 0x00, 0x03, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, 0x07, 0xF8,
0x00, 0x3F, 0xC0, 0x00, 0xFE, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0xC0, 0x01,
0xFE, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xF0,
0x00, 0x3F, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0,
0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E,
0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F,
0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xC0, 0xFC, 0x00, 0x1F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x03,
0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03,
0xF0, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x01,
0xF8, 0x00, 0x3F, 0x00, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x00,
0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00,
0xFC, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x03, 0xF0, 0x00,
0x7E, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00,
0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFE, 0x00, 0x0F, 0xC0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F,
0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83,
0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0,
0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xC0, 0x00, 0xF8, 0x00, 0x0F, 0xE0, 0x00, 0x7F, 0x00, 0x07, 0xFC,
0x00, 0x7F, 0xF0, 0x03, 0xFF, 0x80, 0x3F, 0x7E, 0x01, 0xFB, 0xF0, 0x1F,
0x8F, 0xC1, 0xFC, 0x7F, 0x0F, 0xC1, 0xF8, 0xFC, 0x07, 0xE7, 0xE0, 0x3F,
0x7E, 0x00, 0xFC, 0xF0, 0x07, 0x81, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x10, 0x1C, 0x1E,
0x1F, 0x83, 0xE0, 0xF8, 0x3E, 0x0E, 0x02, 0x00, 0x0F, 0xF0, 0x1F, 0xFE,
0x0F, 0xFF, 0x87, 0xFF, 0xE1, 0xFF, 0xF0, 0x81, 0xFC, 0x00, 0x7E, 0x00,
0x3F, 0x0F, 0xFF, 0x9F, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xFF, 0xE1, 0xFF,
0xE0, 0xFF, 0xF0, 0x7F, 0xFC, 0x3F, 0xFF, 0xFF, 0xBF, 0xFF, 0xDF, 0xFF,
0xE7, 0xFF, 0xF0, 0xFF, 0xC0, 0x1C, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00,
0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00,
0xFC, 0x00, 0x1F, 0xBF, 0x03, 0xFF, 0xF8, 0x7F, 0xFF, 0x8F, 0xFF, 0xF9,
0xFF, 0xFF, 0xBF, 0x87, 0xF7, 0xE0, 0x7F, 0xFC, 0x07, 0xFF, 0x80, 0xFF,
0xF0, 0x1F, 0xFE, 0x03, 0xFF, 0xC0, 0x7F, 0xF8, 0x0F, 0xFF, 0x03, 0xFF,
0xE0, 0x7E, 0xFC, 0x1F, 0xDF, 0xFF, 0xF3, 0xFF, 0xFE, 0x7F, 0xFF, 0x8F,
0xFF, 0xC0, 0x3F, 0xE0, 0x00, 0x01, 0xFE, 0x03, 0xFF, 0xC3, 0xFF, 0xE3,
0xFF, 0xE3, 0xFF, 0xF3, 0xFC, 0x09, 0xF8, 0x01, 0xFC, 0x00, 0xFC, 0x00,
0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xF0, 0x01, 0xF8,
0x00, 0xFF, 0x02, 0x7F, 0xFF, 0x1F, 0xFF, 0xC7, 0xFF, 0xE1, 0xFF, 0xF0,
0x1F, 0xE0, 0x00, 0x00, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0,
0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0,
0x7E, 0xFC, 0x3F, 0xFF, 0x8F, 0xFF, 0xF3, 0xFF, 0xFE, 0xFF, 0xFF, 0xDF,
0xC3, 0xFB, 0xF0, 0x3F, 0xFC, 0x07, 0xFF, 0x80, 0xFF, 0xF0, 0x1F, 0xFE,
0x03, 0xFF, 0xC0, 0x7F, 0xF8, 0x0F, 0xFF, 0x81, 0xFB, 0xF0, 0x3F, 0x7F,
0x07, 0xEF, 0xFF, 0xFC, 0xFF, 0xFF, 0x8F, 0xFF, 0xF0, 0xFF, 0xFE, 0x03,
0xFE, 0x00, 0x01, 0xF8, 0x01, 0xFF, 0xC0, 0x7F, 0xFC, 0x1F, 0xFF, 0xC3,
0xFF, 0xFC, 0xFE, 0x1F, 0x9F, 0x81, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x01, 0xF8, 0x00, 0x1F,
0x80, 0x03, 0xFC, 0x04, 0x7F, 0xFF, 0x87, 0xFF, 0xF8, 0x7F, 0xFF, 0x07,
0xFF, 0xE0, 0x1F, 0xE0, 0x07, 0xF0, 0x7F, 0xF3, 0xFF, 0xDF, 0xFE, 0x7F,
0xFB, 0xF8, 0x2F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xFF, 0xEF, 0xFF, 0xBF,
0xFE, 0xFF, 0xFB, 0xFF, 0xEF, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F,
0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03,
0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x00, 0x03, 0xFE, 0x03,
0xFF, 0xF1, 0xFF, 0xFC, 0xFF, 0xFF, 0x7F, 0xFF, 0xDF, 0xC3, 0xFF, 0xE0,
0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F,
0xFE, 0x0F, 0xFF, 0x87, 0xF7, 0xFF, 0xFD, 0xFF, 0xFF, 0x3F, 0xFF, 0xC7,
0xFF, 0xF0, 0x7E, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x07, 0xF3, 0x03,
0xF8, 0xFF, 0xFE, 0x7F, 0xFF, 0x1F, 0xFF, 0xC7, 0xFF, 0xC0, 0x3F, 0xC0,
0x1C, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0,
0x03, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x7F, 0xF8, 0x3F, 0xFF, 0x1F,
0xFF, 0xCF, 0xFF, 0xF7, 0xFF, 0xFB, 0xF0, 0xFF, 0xF8, 0x3F, 0xFC, 0x1F,
0xFE, 0x0F, 0xFF, 0x07, 0xFF, 0x83, 0xFF, 0xC1, 0xFF, 0xE0, 0xFF, 0xF0,
0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07, 0xFF, 0x83, 0xFF,
0xC1, 0xFF, 0xE0, 0xFC, 0x3C, 0x7E, 0x7E, 0xFF, 0x7E, 0x7E, 0x3C, 0x00,
0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,
0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x01, 0xE0,
0x1F, 0x80, 0xFC, 0x0F, 0xF0, 0x3F, 0x01, 0xF8, 0x07, 0x80, 0x00, 0x00,
0x00, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E,
0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0,
0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F,
0xC0, 0xFE, 0x7F, 0xE3, 0xFF, 0x3F, 0xF1, 0xFF, 0x0F, 0xE0, 0x00, 0x1C,
0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8,
0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x83, 0xFF, 0xF0,
0xFF, 0x7E, 0x3F, 0xCF, 0xC7, 0xF1, 0xF9, 0xFC, 0x3F, 0x7F, 0x87, 0xFF,
0xE0, 0xFF, 0xF8, 0x1F, 0xFE, 0x03, 0xFF, 0x80, 0x7F, 0xF8, 0x0F, 0xFF,
0x81, 0xFF, 0xF8, 0x3F, 0x7F, 0x07, 0xE7, 0xF0, 0xFC, 0x7F, 0x1F, 0x8F,
0xE3, 0xF0, 0xFE, 0x7E, 0x1F, 0xEF, 0xC1, 0xFD, 0xF8, 0x1F, 0xC0, 0x1C,
0x7E, 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, 0x7E, 0x3F, 0x1F,
0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8F, 0xC7, 0xE3,
0xF1, 0xF8, 0xFE, 0x7F, 0xDF, 0xEF, 0xF3, 0xF0, 0x78, 0x1F, 0xF0, 0x7E,
0x0F, 0xFF, 0xDF, 0xF8, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFE, 0xFF,
0xFF, 0xFF, 0xEF, 0xC3, 0xF8, 0x7F, 0xFC, 0x3F, 0x87, 0xFF, 0xC1, 0xF8,
0x3F, 0xFC, 0x1F, 0x83, 0xFF, 0xC1, 0xF8, 0x3F, 0xFC, 0x1F, 0x83, 0xFF,
0xC1, 0xF8, 0x3F, 0xFC, 0x1F, 0x83, 0xFF, 0xC1, 0xF8, 0x3F, 0xFC, 0x1F,
0x83, 0xFF, 0xC1, 0xF8, 0x3F, 0xFC, 0x1F, 0x83, 0xFF, 0xC1, 0xF8, 0x3F,
0xFC, 0x1F, 0x83, 0xFF, 0xC1, 0xF8, 0x3F, 0xFC, 0x1F, 0x83, 0xF0, 0x1F,
0xF0, 0x7F, 0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF, 0xFF, 0xF7, 0xE1, 0xFF,
0xF0, 0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07, 0xFF, 0x83,
0xFF, 0xC1, 0xFF, 0xE0, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE,
0x0F, 0xFF, 0x07, 0xFF, 0x83, 0xFF, 0xC1, 0xF8, 0x01, 0xF8, 0x00, 0x7F,
0xE0, 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x3F, 0xFF, 0xC7, 0xF0, 0xFE, 0x7E,
0x07, 0xEF, 0xE0, 0x7F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF,
0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x7F, 0x7E, 0x07, 0xE7, 0xF0, 0xFE,
0x3F, 0xFF, 0xE3, 0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x01, 0xF8,
0x00, 0x1F, 0xF0, 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7F, 0xFF, 0xCF, 0xFF,
0xF9, 0xF8, 0x3F, 0xBF, 0x03, 0xF7, 0xE0, 0x7F, 0xFC, 0x07, 0xFF, 0x80,
0xFF, 0xF0, 0x1F, 0xFE, 0x03, 0xFF, 0xC0, 0x7F, 0xF8, 0x0F, 0xFF, 0x03,
0xFF, 0xF0, 0xFE, 0xFF, 0xFF, 0xDF, 0xFF, 0xF3, 0xFF, 0xFC, 0x7F, 0xFF,
0x0F, 0xDF, 0x81, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00,
0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x7F,
0xFF, 0x1F, 0xFF, 0xF3, 0xFF, 0xFF, 0x3F, 0xFF, 0xF7, 0xF8, 0x3F, 0x7E,
0x03, 0xFF, 0xE0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF,
0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFE, 0x03, 0xF7, 0xF0, 0x7F,
0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0x03, 0xFB,
0xF0, 0x00, 0x3F, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xF0, 0x00,
0x3F, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x0F, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF,
0xFE, 0xFF, 0xFB, 0xF0, 0x2F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F,
0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03,
0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x00, 0x07, 0xF8, 0x0F, 0xFE, 0x3F,
0xFE, 0x3F, 0xFE, 0x7F, 0xFC, 0x7E, 0x04, 0x7E, 0x00, 0x7F, 0x00, 0x7F,
0xF8, 0x7F, 0xFE, 0x3F, 0xFE, 0x1F, 0xFF, 0x07, 0xFF, 0x00, 0x7F, 0x00,
0x3F, 0x70, 0x3F, 0x7F, 0xFF, 0x7F, 0xFE, 0x7F, 0xFE, 0xFF, 0xF8, 0x1F,
0xE0, 0x1C, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F,
0xFF, 0xBF, 0xFE, 0xFF, 0xFB, 0xFF, 0xEF, 0xFF, 0xBF, 0x00, 0xFC, 0x03,
0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00,
0xFC, 0x03, 0xF8, 0x27, 0xFF, 0x9F, 0xFE, 0x3F, 0xFC, 0x7F, 0xF0, 0x7F,
0x00, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07, 0xFF, 0x83, 0xFF, 0xC1, 0xFF,
0xE0, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07,
0xFF, 0x83, 0xFF, 0xC1, 0xFF, 0xE0, 0xFF, 0xF0, 0x7F, 0xFC, 0x3F, 0x7F,
0xFF, 0xBF, 0xFF, 0xCF, 0xFF, 0xE3, 0xFF, 0xF0, 0x7F, 0xC0, 0xFC, 0x01,
0xFF, 0xF0, 0x1F, 0xDF, 0x80, 0xFC, 0xFC, 0x07, 0xE7, 0xF0, 0x7F, 0x1F,
0x83, 0xF0, 0xFC, 0x1F, 0x87, 0xE0, 0xFC, 0x3F, 0x8F, 0xC0, 0xFC, 0x7E,
0x07, 0xE3, 0xF0, 0x3F, 0xBF, 0x00, 0xFD, 0xF8, 0x07, 0xEF, 0xC0, 0x1F,
0xFC, 0x00, 0xFF, 0xE0, 0x07, 0xFF, 0x00, 0x1F, 0xF0, 0x00, 0xFF, 0x80,
0x03, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFC, 0x0F, 0x80, 0xFF, 0xF0, 0x3E,
0x03, 0xF7, 0xE0, 0xF8, 0x1F, 0x9F, 0x83, 0xF0, 0x7E, 0x7E, 0x0F, 0xC1,
0xF8, 0xF8, 0x7F, 0x07, 0xC3, 0xF1, 0xFC, 0x3F, 0x0F, 0xC7, 0xF8, 0xFC,
0x1F, 0x1F, 0xE3, 0xE0, 0x7C, 0xF7, 0x8F, 0x81, 0xFB, 0xDF, 0x7E, 0x07,
0xEF, 0x7D, 0xF0, 0x0F, 0xBC, 0xF7, 0xC0, 0x3E, 0xE3, 0xDF, 0x00, 0xFF,
0x8F, 0xF8, 0x01, 0xFE, 0x1F, 0xE0, 0x07, 0xF8, 0x7F, 0x80, 0x0F, 0xC1,
0xFC, 0x00, 0x3F, 0x03, 0xF0, 0x00, 0xFC, 0x0F, 0xC0, 0x01, 0xF0, 0x3E,
0x00, 0xFF, 0x03, 0xFD, 0xFC, 0x0F, 0xE3, 0xF8, 0x7F, 0x0F, 0xF3, 0xFC,
0x1F, 0xCF, 0xE0, 0x3F, 0xFF, 0x00, 0x7F, 0xF8, 0x01, 0xFF, 0xE0, 0x03,
0xFF, 0x00, 0x07, 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x03, 0xFF,
0x00, 0x1F, 0xFE, 0x00, 0x7F, 0xF8, 0x03, 0xFF, 0xF0, 0x1F, 0xCF, 0xE0,
0xFF, 0x3F, 0x83, 0xF8, 0x7F, 0x1F, 0xC0, 0xFE, 0xFF, 0x03, 0xFC, 0xFC,
0x01, 0xFF, 0xF0, 0x1F, 0xDF, 0x80, 0xFC, 0xFC, 0x07, 0xE7, 0xF0, 0x7F,
0x1F, 0x83, 0xF0, 0xFC, 0x1F, 0x87, 0xE0, 0xFC, 0x3F, 0x8F, 0xC0, 0xFC,
0x7E, 0x07, 0xE3, 0xF0, 0x1F, 0xBF, 0x00, 0xFD, 0xF8, 0x07, 0xEF, 0xC0,
0x1F, 0xFC, 0x00, 0xFF, 0xE0, 0x07, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0xFF,
0x80, 0x03, 0xF8, 0x00, 0x1F, 0xC0, 0x01, 0xFC, 0x00, 0x1F, 0xE0, 0x0F,
0xFE, 0x00, 0x7F, 0xF0, 0x07, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0xFE, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x01, 0xFC, 0x00, 0xFF, 0x00,
0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE,
0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC0, 0x00, 0xF8, 0x3F, 0xC3, 0xFE, 0x1F, 0xF1, 0xFF, 0x8F, 0xE0, 0x7E,
0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0,
0x7E, 0x03, 0xF0, 0x3F, 0x87, 0xF8, 0x3F, 0x81, 0xFC, 0x0F, 0xF0, 0x7F,
0x80, 0xFE, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8,
0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0xC0, 0xFF, 0xC3, 0xFE, 0x1F, 0xF0,
0x7F, 0x80, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x07, 0xF8, 0x3F,
0xE1, 0xFF, 0x0F, 0xFC, 0x0F, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E,
0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xE0,
0x3F, 0xC0, 0xFE, 0x07, 0xF0, 0x7F, 0x87, 0xFC, 0x3F, 0x81, 0xF8, 0x0F,
0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8,
0x1F, 0xC7, 0xFE, 0x3F, 0xE1, 0xFF, 0x0F, 0xF0, 0x7C, 0x00, 0x0F, 0x00,
0xC3, 0xFC, 0x0F, 0x3F, 0xF1, 0xF7, 0xFF, 0xFE, 0x7F, 0xFF, 0xEF, 0x8F,
0xFC, 0xF0, 0x3F, 0xC3, 0x00, 0xF0 };
const GFXglyph Ubuntu_Bold20pt7bGlyphs[] PROGMEM = {
{ 0, 0, 0, 9, 0, 1 }, // 0x20 ' '
{ 0, 8, 27, 11, 2, -26 }, // 0x21 '!'
{ 27, 15, 11, 18, 2, -29 }, // 0x22 '"'
{ 48, 23, 27, 27, 2, -26 }, // 0x23 '#'
{ 126, 19, 35, 22, 1, -29 }, // 0x24 '$'
{ 210, 34, 27, 36, 1, -26 }, // 0x25 '%'
{ 325, 27, 27, 28, 1, -26 }, // 0x26 '&'
{ 417, 6, 11, 10, 2, -29 }, // 0x27 '''
{ 426, 11, 38, 14, 3, -30 }, // 0x28 '('
{ 479, 11, 38, 14, 0, -30 }, // 0x29 ')'
{ 532, 17, 16, 20, 2, -26 }, // 0x2A '*'
{ 566, 19, 19, 23, 2, -20 }, // 0x2B '+'
{ 612, 8, 12, 9, 0, -5 }, // 0x2C ','
{ 624, 11, 5, 13, 1, -13 }, // 0x2D '-'
{ 631, 7, 7, 9, 1, -5 }, // 0x2E '.'
{ 638, 19, 38, 17, -1, -30 }, // 0x2F '/'
{ 729, 20, 27, 22, 1, -26 }, // 0x30 '0'
{ 797, 13, 27, 22, 3, -26 }, // 0x31 '1'
{ 841, 19, 27, 22, 1, -26 }, // 0x32 '2'
{ 906, 19, 27, 22, 1, -26 }, // 0x33 '3'
{ 971, 20, 27, 22, 1, -26 }, // 0x34 '4'
{ 1039, 19, 27, 22, 1, -26 }, // 0x35 '5'
{ 1104, 20, 27, 22, 1, -26 }, // 0x36 '6'
{ 1172, 18, 27, 22, 2, -26 }, // 0x37 '7'
{ 1233, 19, 27, 22, 2, -26 }, // 0x38 '8'
{ 1298, 19, 27, 22, 1, -26 }, // 0x39 '9'
{ 1363, 7, 21, 9, 1, -19 }, // 0x3A ':'
{ 1382, 8, 26, 9, 0, -19 }, // 0x3B ';'
{ 1408, 19, 19, 22, 2, -20 }, // 0x3C '<'
{ 1454, 18, 14, 22, 2, -17 }, // 0x3D '='
{ 1486, 19, 19, 22, 1, -20 }, // 0x3E '>'
{ 1532, 16, 28, 18, 1, -27 }, // 0x3F '?'
{ 1588, 34, 34, 38, 2, -27 }, // 0x40 '@'
{ 1733, 27, 27, 27, 0, -26 }, // 0x41 'A'
{ 1825, 21, 27, 26, 3, -26 }, // 0x42 'B'
{ 1896, 22, 27, 25, 2, -26 }, // 0x43 'C'
{ 1971, 24, 27, 29, 3, -26 }, // 0x44 'D'
{ 2052, 20, 27, 24, 3, -26 }, // 0x45 'E'
{ 2120, 18, 27, 22, 3, -26 }, // 0x46 'F'
{ 2181, 22, 27, 27, 2, -26 }, // 0x47 'G'
{ 2256, 23, 27, 29, 3, -26 }, // 0x48 'H'
{ 2334, 6, 27, 12, 3, -26 }, // 0x49 'I'
{ 2355, 18, 27, 21, 0, -26 }, // 0x4A 'J'
{ 2416, 24, 27, 27, 3, -26 }, // 0x4B 'K'
{ 2497, 18, 27, 22, 3, -26 }, // 0x4C 'L'
{ 2558, 31, 27, 35, 2, -26 }, // 0x4D 'M'
{ 2663, 23, 27, 29, 3, -26 }, // 0x4E 'N'
{ 2741, 27, 27, 31, 2, -26 }, // 0x4F 'O'
{ 2833, 20, 27, 25, 3, -26 }, // 0x50 'P'
{ 2901, 27, 34, 31, 2, -26 }, // 0x51 'Q'
{ 3016, 23, 27, 26, 3, -26 }, // 0x52 'R'
{ 3094, 20, 27, 23, 1, -26 }, // 0x53 'S'
{ 3162, 22, 27, 24, 1, -26 }, // 0x54 'T'
{ 3237, 22, 27, 28, 3, -26 }, // 0x55 'U'
{ 3312, 27, 27, 27, 0, -26 }, // 0x56 'V'
{ 3404, 36, 27, 38, 1, -26 }, // 0x57 'W'
{ 3526, 26, 27, 26, 0, -26 }, // 0x58 'X'
{ 3614, 26, 27, 26, 0, -26 }, // 0x59 'Y'
{ 3702, 22, 27, 24, 1, -26 }, // 0x5A 'Z'
{ 3777, 11, 38, 14, 3, -30 }, // 0x5B '['
{ 3830, 19, 38, 17, -1, -30 }, // 0x5C '\'
{ 3921, 11, 38, 14, 0, -30 }, // 0x5D ']'
{ 3974, 21, 16, 23, 1, -26 }, // 0x5E '^'
{ 4016, 20, 5, 20, 0, 3 }, // 0x5F '_'
{ 4029, 9, 9, 11, 1, -30 }, // 0x60 '`'
{ 4040, 17, 21, 22, 2, -20 }, // 0x61 'a'
{ 4085, 19, 30, 24, 3, -29 }, // 0x62 'b'
{ 4157, 17, 21, 20, 2, -20 }, // 0x63 'c'
{ 4202, 19, 30, 24, 2, -29 }, // 0x64 'd'
{ 4274, 19, 21, 23, 2, -20 }, // 0x65 'e'
{ 4324, 14, 30, 17, 3, -29 }, // 0x66 'f'
{ 4377, 18, 28, 23, 2, -20 }, // 0x67 'g'
{ 4440, 17, 30, 23, 3, -29 }, // 0x68 'h'
{ 4504, 8, 30, 12, 2, -29 }, // 0x69 'i'
{ 4534, 13, 37, 10, -4, -29 }, // 0x6A 'j'
{ 4595, 19, 30, 23, 3, -29 }, // 0x6B 'k'
{ 4667, 9, 30, 13, 3, -29 }, // 0x6C 'l'
{ 4701, 28, 21, 34, 3, -20 }, // 0x6D 'm'
{ 4775, 17, 21, 23, 3, -20 }, // 0x6E 'n'
{ 4820, 20, 21, 24, 2, -20 }, // 0x6F 'o'
{ 4873, 19, 28, 24, 3, -20 }, // 0x70 'p'
{ 4940, 20, 28, 24, 2, -20 }, // 0x71 'q'
{ 5010, 14, 21, 17, 3, -20 }, // 0x72 'r'
{ 5047, 16, 21, 19, 1, -20 }, // 0x73 's'
{ 5089, 14, 27, 18, 3, -26 }, // 0x74 't'
{ 5137, 17, 21, 23, 3, -20 }, // 0x75 'u'
{ 5182, 21, 21, 21, 0, -20 }, // 0x76 'v'
{ 5238, 30, 21, 30, 0, -20 }, // 0x77 'w'
{ 5317, 22, 21, 22, 0, -20 }, // 0x78 'x'
{ 5375, 21, 28, 21, 0, -20 }, // 0x79 'y'
{ 5449, 18, 21, 20, 1, -20 }, // 0x7A 'z'
{ 5497, 13, 38, 14, 1, -30 }, // 0x7B '{'
{ 5559, 6, 38, 14, 4, -30 }, // 0x7C '|'
{ 5588, 13, 38, 14, 0, -30 }, // 0x7D '}'
{ 5650, 20, 8, 22, 1, -15 } }; // 0x7E '~'
const GFXfont Ubuntu_Bold20pt7b PROGMEM = {
(uint8_t *)Ubuntu_Bold20pt7bBitmaps,
(GFXglyph *)Ubuntu_Bold20pt7bGlyphs,
0x20, 0x7E, 45 };
// Approx. 6342 bytes

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
const uint8_t Ubuntu_Bold8pt7bBitmaps[] PROGMEM = {
0xFF, 0xFC, 0xFC, 0xDE, 0xF7, 0xBD, 0x80, 0x1B, 0x0D, 0x87, 0xDF, 0xFF,
0xF9, 0xB3, 0xFF, 0xFF, 0x6C, 0x36, 0x1B, 0x00, 0x18, 0x30, 0xFF, 0xFC,
0x38, 0x1C, 0x1E, 0x0E, 0x0C, 0x1F, 0xF7, 0xC3, 0x06, 0x00, 0x78, 0x63,
0xF3, 0x0C, 0xCC, 0x33, 0x60, 0xCF, 0xFB, 0xFF, 0xF7, 0xFC, 0xC1, 0xB3,
0x0C, 0xCC, 0x33, 0xF1, 0x87, 0x80, 0x3C, 0x1F, 0x86, 0x61, 0x98, 0x3C,
0x1E, 0x6C, 0xDB, 0x1C, 0xC7, 0x3F, 0xE7, 0xDC, 0xFF, 0xC0, 0x13, 0x66,
0xCC, 0xCC, 0xCC, 0xCC, 0x66, 0x31, 0x8C, 0x66, 0x33, 0x33, 0x33, 0x33,
0x66, 0xC8, 0x39, 0xFF, 0xF8, 0x86, 0xDD, 0xD1, 0x00, 0x18, 0x18, 0x18,
0xFF, 0xFF, 0x18, 0x18, 0x18, 0x6D, 0xEC, 0xFF, 0xC0, 0xFF, 0x80, 0x06,
0x1C, 0x30, 0x60, 0xC3, 0x06, 0x0C, 0x30, 0x60, 0xC3, 0x06, 0x0C, 0x38,
0x60, 0x38, 0xFB, 0xBE, 0x3C, 0x78, 0xF1, 0xE3, 0xEE, 0xF8, 0xE0, 0x1B,
0xFE, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x7D, 0xFD, 0x18, 0x30, 0xE3, 0x8E,
0x38, 0xE1, 0xFF, 0xF8, 0x7D, 0xFC, 0x18, 0x33, 0xE7, 0x81, 0x83, 0x87,
0xFF, 0xE0, 0x06, 0x0E, 0x1E, 0x3E, 0x36, 0x66, 0xE6, 0xFF, 0xFF, 0x06,
0x06, 0x7E, 0xFD, 0x83, 0x0F, 0x9F, 0x83, 0x83, 0x07, 0xFB, 0xE0, 0x1C,
0x79, 0xC7, 0x0F, 0xDF, 0xF1, 0xE3, 0xC6, 0xF8, 0xE0, 0xFF, 0xFC, 0x30,
0xE1, 0x87, 0x0C, 0x18, 0x60, 0xC1, 0x80, 0x3C, 0xFF, 0x1E, 0x3E, 0xEF,
0xBF, 0xE3, 0xC7, 0xFD, 0xF0, 0x38, 0xFB, 0x1E, 0x3C, 0x7F, 0xDF, 0x87,
0x1C, 0xF1, 0xC0, 0xFF, 0x80, 0x3F, 0xE0, 0x77, 0x70, 0x00, 0x06, 0x66,
0xCC, 0x06, 0x3E, 0xF8, 0xC0, 0xF8, 0x3F, 0x06, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x60, 0x7C, 0x1F, 0x03, 0x1F, 0xFC, 0x60, 0x7D, 0xFC, 0x18,
0x30, 0xC3, 0x0C, 0x18, 0x00, 0x70, 0xE1, 0xC0, 0x0F, 0xC0, 0x7F, 0xC3,
0x83, 0x98, 0x06, 0xE7, 0xCF, 0x3F, 0x3D, 0x8C, 0xF6, 0x33, 0xD8, 0xCF,
0xBF, 0xE6, 0x7F, 0x1E, 0x00, 0x3F, 0xC0, 0x3F, 0x00, 0x0E, 0x01, 0xC0,
0x7C, 0x0D, 0x83, 0xB8, 0x63, 0x0C, 0x63, 0xFE, 0x7F, 0xCC, 0x1B, 0x01,
0x80, 0xFC, 0x7F, 0xB0, 0xD8, 0x6F, 0xE7, 0xFB, 0x07, 0x83, 0xC3, 0xFF,
0xBF, 0x80, 0x1F, 0x1F, 0xD8, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0x60,
0x3F, 0xC7, 0xC0, 0xFE, 0x3F, 0xCC, 0x3B, 0x07, 0xC0, 0xF0, 0x3C, 0x0F,
0x07, 0xC3, 0xBF, 0xCF, 0xE0, 0xFF, 0xFF, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0,
0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0,
0xC0, 0xC0, 0xC0, 0x1F, 0x1F, 0xD8, 0x18, 0x0C, 0x06, 0x0F, 0x07, 0x83,
0x71, 0xBF, 0xC7, 0xE0, 0xC1, 0xE0, 0xF0, 0x78, 0x3F, 0xFF, 0xFF, 0x07,
0x83, 0xC1, 0xE0, 0xF0, 0x60, 0xFF, 0xFF, 0xFC, 0x06, 0x0C, 0x18, 0x30,
0x60, 0xC1, 0x83, 0x07, 0xF9, 0xE0, 0xC1, 0xB0, 0xCC, 0x63, 0x30, 0xF8,
0x3C, 0x0D, 0x83, 0x30, 0xC6, 0x30, 0xCC, 0x18, 0xC0, 0xC0, 0xC0, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x60, 0x33, 0x83, 0x9C, 0x1C,
0xF1, 0xED, 0x8D, 0xEE, 0xEF, 0x36, 0x79, 0xF3, 0xC7, 0x1E, 0x38, 0xF0,
0x06, 0xC0, 0xF8, 0x3F, 0x0F, 0xE3, 0xDC, 0xF3, 0xBC, 0x7F, 0x0F, 0xC1,
0xF0, 0x7C, 0x0C, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0,
0x1F, 0x07, 0x71, 0xCF, 0xF8, 0x7C, 0x00, 0xFC, 0xFE, 0xC3, 0xC3, 0xC3,
0xFE, 0xFC, 0xC0, 0xC0, 0xC0, 0xC0, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C,
0x07, 0x80, 0xF0, 0x1F, 0x07, 0x71, 0xCF, 0xF0, 0xF8, 0x07, 0x00, 0x7C,
0x07, 0x80, 0xFC, 0x7F, 0x30, 0xD8, 0x6C, 0x37, 0xF3, 0xE1, 0x98, 0xC6,
0x63, 0xB0, 0xE0, 0x3D, 0xFF, 0x06, 0x0F, 0x0F, 0x87, 0x83, 0x07, 0xFD,
0xF0, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0xBF, 0x8F,
0x80, 0xC0, 0x6C, 0x19, 0x83, 0x38, 0xE3, 0x18, 0x63, 0x06, 0xC0, 0xD8,
0x0E, 0x01, 0xC0, 0x38, 0x00, 0xC0, 0x07, 0x87, 0x0D, 0x8E, 0x33, 0x1C,
0x66, 0x6C, 0xC6, 0xDB, 0x0D, 0xB6, 0x1B, 0x6C, 0x1C, 0x70, 0x38, 0xE0,
0x71, 0xC0, 0xE0, 0xEC, 0x18, 0xC6, 0x0D, 0x80, 0xE0, 0x1C, 0x03, 0x80,
0xD8, 0x31, 0x8C, 0x1B, 0x83, 0x80, 0xC0, 0xD8, 0x67, 0x38, 0xCC, 0x1E,
0x07, 0x80, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0xFF, 0xFF, 0x06, 0x0C,
0x1C, 0x18, 0x30, 0x70, 0x60, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C, 0x63, 0x18,
0xC6, 0x31, 0x8C, 0x63, 0xFF, 0xC1, 0xC1, 0x83, 0x06, 0x06, 0x0C, 0x18,
0x18, 0x30, 0x60, 0x60, 0xC1, 0x83, 0x83, 0xFF, 0xC6, 0x31, 0x8C, 0x63,
0x18, 0xC6, 0x31, 0x8F, 0xFF, 0x08, 0x0E, 0x0F, 0x86, 0xC7, 0x77, 0x1D,
0x04, 0xFF, 0xFF, 0x4E, 0x72, 0x7C, 0xFC, 0x1B, 0xFF, 0xF8, 0xFF, 0xBF,
0xC1, 0x83, 0x06, 0x0F, 0x9F, 0xB3, 0xE3, 0xC7, 0x9F, 0xF7, 0xC0, 0x3D,
0xFE, 0x30, 0xC3, 0x87, 0xCF, 0x06, 0x0C, 0x18, 0x33, 0xEF, 0xF9, 0xE3,
0xC7, 0xCD, 0xF9, 0xF0, 0x38, 0xFB, 0x1F, 0xFF, 0xF8, 0x1F, 0x1E, 0x7F,
0xF1, 0x8F, 0xFF, 0x18, 0xC6, 0x31, 0x80, 0x3E, 0xFF, 0x9E, 0x3C, 0x7C,
0xDF, 0x9F, 0x06, 0xFB, 0xE0, 0xC1, 0x83, 0x06, 0x0F, 0xDF, 0xF1, 0xE3,
0xC7, 0x8F, 0x1E, 0x30, 0xFC, 0xFF, 0xFF, 0x33, 0x30, 0x33, 0x33, 0x33,
0x33, 0x3F, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC6, 0xCC, 0xD8, 0xF0, 0xD8,
0xCC, 0xC6, 0xC7, 0xDB, 0x6D, 0xB6, 0xDB, 0xB0, 0xFD, 0xEF, 0xFF, 0xC6,
0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xFD, 0xFF, 0x1E, 0x3C,
0x78, 0xF1, 0xE3, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C, 0xF9,
0xFB, 0x3E, 0x3C, 0x79, 0xFF, 0x7C, 0xC1, 0x83, 0x00, 0x3E, 0xFF, 0x9E,
0x3C, 0x7C, 0xDF, 0xBF, 0x06, 0x0C, 0x18, 0xFF, 0xF1, 0x8C, 0x63, 0x18,
0x7F, 0xEC, 0x3E, 0x7C, 0x3F, 0xFE, 0xC6, 0x3F, 0xFC, 0x63, 0x18, 0xFB,
0xC0, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xFF, 0xBF, 0xC1, 0xB1, 0x98, 0xCE,
0xE3, 0x61, 0xF0, 0x70, 0x38, 0xC6, 0x79, 0xCD, 0xBB, 0x35, 0x66, 0xAC,
0x77, 0x0E, 0xE1, 0x8C, 0xE3, 0xBB, 0x8D, 0x83, 0x81, 0xC1, 0xB1, 0xDD,
0xC7, 0xE3, 0xB1, 0x98, 0xCE, 0xE3, 0x61, 0xF0, 0x70, 0x38, 0x18, 0x7C,
0x3C, 0x00, 0xFF, 0xF1, 0x8E, 0x71, 0x8F, 0xFF, 0x3B, 0xD8, 0xC6, 0x31,
0x98, 0xC3, 0x18, 0xC6, 0x31, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x8C,
0x63, 0x18, 0xC3, 0x19, 0x8C, 0x63, 0x1B, 0xDC, 0x73, 0xFF, 0xCE };
const GFXglyph Ubuntu_Bold8pt7bGlyphs[] PROGMEM = {
{ 0, 0, 0, 4, 0, 1 }, // 0x20 ' '
{ 0, 2, 11, 4, 1, -10 }, // 0x21 '!'
{ 3, 5, 5, 7, 1, -11 }, // 0x22 '"'
{ 7, 9, 11, 11, 1, -10 }, // 0x23 '#'
{ 20, 7, 15, 9, 1, -12 }, // 0x24 '$'
{ 34, 14, 11, 16, 1, -10 }, // 0x25 '%'
{ 54, 10, 11, 11, 1, -10 }, // 0x26 '&'
{ 68, 2, 5, 4, 1, -11 }, // 0x27 '''
{ 70, 4, 16, 6, 1, -12 }, // 0x28 '('
{ 78, 4, 16, 6, 1, -12 }, // 0x29 ')'
{ 86, 7, 7, 8, 1, -10 }, // 0x2A '*'
{ 93, 8, 8, 10, 1, -8 }, // 0x2B '+'
{ 101, 3, 5, 4, 0, -1 }, // 0x2C ','
{ 103, 5, 2, 7, 1, -5 }, // 0x2D '-'
{ 105, 3, 3, 5, 1, -2 }, // 0x2E '.'
{ 107, 7, 16, 7, 0, -12 }, // 0x2F '/'
{ 121, 7, 11, 9, 1, -10 }, // 0x30 '0'
{ 131, 5, 11, 9, 1, -10 }, // 0x31 '1'
{ 138, 7, 11, 9, 1, -10 }, // 0x32 '2'
{ 148, 7, 11, 9, 1, -10 }, // 0x33 '3'
{ 158, 8, 11, 9, 1, -10 }, // 0x34 '4'
{ 169, 7, 11, 9, 1, -10 }, // 0x35 '5'
{ 179, 7, 11, 9, 1, -10 }, // 0x36 '6'
{ 189, 7, 11, 9, 1, -10 }, // 0x37 '7'
{ 199, 7, 11, 9, 1, -10 }, // 0x38 '8'
{ 209, 7, 11, 9, 1, -10 }, // 0x39 '9'
{ 219, 3, 9, 5, 1, -8 }, // 0x3A ':'
{ 223, 4, 12, 5, 0, -8 }, // 0x3B ';'
{ 229, 8, 7, 9, 1, -7 }, // 0x3C '<'
{ 236, 8, 6, 10, 1, -7 }, // 0x3D '='
{ 242, 8, 7, 9, 0, -7 }, // 0x3E '>'
{ 249, 7, 12, 7, 0, -11 }, // 0x3F '?'
{ 260, 14, 14, 16, 1, -10 }, // 0x40 '@'
{ 285, 11, 11, 11, 0, -10 }, // 0x41 'A'
{ 301, 9, 11, 11, 1, -10 }, // 0x42 'B'
{ 314, 9, 11, 11, 1, -10 }, // 0x43 'C'
{ 327, 10, 11, 12, 1, -10 }, // 0x44 'D'
{ 341, 8, 11, 10, 1, -10 }, // 0x45 'E'
{ 352, 8, 11, 9, 1, -10 }, // 0x46 'F'
{ 363, 9, 11, 11, 1, -10 }, // 0x47 'G'
{ 376, 9, 11, 11, 1, -10 }, // 0x48 'H'
{ 389, 2, 11, 4, 1, -10 }, // 0x49 'I'
{ 392, 7, 11, 8, 0, -10 }, // 0x4A 'J'
{ 402, 10, 11, 11, 1, -10 }, // 0x4B 'K'
{ 416, 8, 11, 9, 1, -10 }, // 0x4C 'L'
{ 427, 13, 11, 15, 1, -10 }, // 0x4D 'M'
{ 445, 10, 11, 12, 1, -10 }, // 0x4E 'N'
{ 459, 11, 11, 13, 1, -10 }, // 0x4F 'O'
{ 475, 8, 11, 10, 1, -10 }, // 0x50 'P'
{ 486, 11, 14, 13, 1, -10 }, // 0x51 'Q'
{ 506, 9, 11, 10, 1, -10 }, // 0x52 'R'
{ 519, 7, 11, 9, 1, -10 }, // 0x53 'S'
{ 529, 8, 11, 8, 0, -10 }, // 0x54 'T'
{ 540, 9, 11, 11, 1, -10 }, // 0x55 'U'
{ 553, 11, 11, 11, 0, -10 }, // 0x56 'V'
{ 569, 15, 11, 15, 0, -10 }, // 0x57 'W'
{ 590, 11, 11, 11, 0, -10 }, // 0x58 'X'
{ 606, 10, 11, 10, 0, -10 }, // 0x59 'Y'
{ 620, 8, 11, 10, 1, -10 }, // 0x5A 'Z'
{ 631, 5, 16, 6, 1, -12 }, // 0x5B '['
{ 641, 7, 16, 7, 0, -12 }, // 0x5C '\'
{ 655, 5, 16, 6, 0, -12 }, // 0x5D ']'
{ 665, 9, 7, 9, 0, -10 }, // 0x5E '^'
{ 673, 8, 2, 8, 0, 2 }, // 0x5F '_'
{ 675, 4, 4, 5, 1, -12 }, // 0x60 '`'
{ 677, 7, 8, 9, 1, -7 }, // 0x61 'a'
{ 684, 7, 12, 9, 1, -11 }, // 0x62 'b'
{ 695, 6, 8, 8, 1, -7 }, // 0x63 'c'
{ 701, 7, 12, 9, 1, -11 }, // 0x64 'd'
{ 712, 7, 8, 9, 1, -7 }, // 0x65 'e'
{ 719, 5, 12, 6, 1, -11 }, // 0x66 'f'
{ 727, 7, 11, 9, 1, -7 }, // 0x67 'g'
{ 737, 7, 12, 9, 1, -11 }, // 0x68 'h'
{ 748, 2, 12, 4, 1, -11 }, // 0x69 'i'
{ 751, 4, 15, 4, -1, -11 }, // 0x6A 'j'
{ 759, 8, 12, 9, 1, -11 }, // 0x6B 'k'
{ 771, 3, 12, 4, 1, -11 }, // 0x6C 'l'
{ 776, 12, 8, 14, 1, -7 }, // 0x6D 'm'
{ 788, 7, 8, 9, 1, -7 }, // 0x6E 'n'
{ 795, 8, 8, 10, 1, -7 }, // 0x6F 'o'
{ 803, 7, 11, 9, 1, -7 }, // 0x70 'p'
{ 813, 7, 11, 9, 1, -7 }, // 0x71 'q'
{ 823, 5, 8, 6, 1, -7 }, // 0x72 'r'
{ 828, 6, 8, 8, 1, -7 }, // 0x73 's'
{ 834, 5, 10, 7, 1, -9 }, // 0x74 't'
{ 841, 7, 8, 9, 1, -7 }, // 0x75 'u'
{ 848, 9, 8, 9, 0, -7 }, // 0x76 'v'
{ 857, 11, 8, 11, 0, -7 }, // 0x77 'w'
{ 868, 9, 8, 9, 0, -7 }, // 0x78 'x'
{ 877, 9, 11, 9, 0, -7 }, // 0x79 'y'
{ 890, 6, 8, 8, 1, -7 }, // 0x7A 'z'
{ 896, 5, 16, 5, 0, -12 }, // 0x7B '{'
{ 906, 2, 16, 4, 1, -12 }, // 0x7C '|'
{ 910, 5, 16, 5, 0, -12 }, // 0x7D '}'
{ 920, 8, 3, 9, 1, -5 } }; // 0x7E '~'
const GFXfont Ubuntu_Bold8pt7b PROGMEM = {
(uint8_t *)Ubuntu_Bold8pt7bBitmaps,
(GFXglyph *)Ubuntu_Bold8pt7bGlyphs,
0x20, 0x7E, 18 };
// Approx. 1595 bytes

View File

@@ -6,12 +6,10 @@ https://gitpod.io/#https://github.com/norbert-walter/esp32-nmea2000-obp60/tree/m
Input in terminal:
cd /workspace/esp32-nmea2000-obp60
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run_installing_tools
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run_obp60_s3
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run_obp40_s3
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run
Compile result for OBP60
########################
Compile result in:
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-all.bin, ready to flash to offset 0x0000
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/bootloader.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/firmware.bin
@@ -20,19 +18,3 @@ Compile result for OBP60
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-dev20231220-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-dev20231220-update.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-all.bin, ready to flash to offset 0x0000
Compile result for OBP40 (CrowPanel 4.2)
########################################
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/bootloader.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/firmware.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/partitions.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-dev20231220-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-dev20231220-update.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-all.bin, ready to flash to offset 0x0000

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
Debugging tool
##############
log.txt = text file with error messages from terminal console
tools/decoder.py -p ESP32S3 -t ~/.platformio/packages/toolchain-xtensa-esp32s3/ -e .pio/build/obp60_s3/firmware.elf log.txt

View File

@@ -1,338 +0,0 @@
const uint8_t Atari16pxBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFF, 0x0F, 0xCF, 0x3C, 0xF3, 0xCF, 0x30, 0x66, 0x66, 0xFF,
0xFF, 0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66, 0x30, 0xC7, 0xFF, 0xC3, 0x0F,
0x9F, 0x0C, 0x3F, 0xFE, 0x30, 0xC0, 0xCF, 0x3D, 0x86, 0x30, 0xC6, 0x1B,
0xCF, 0x30, 0x38, 0xF9, 0xB3, 0x63, 0x87, 0x1C, 0x38, 0xDF, 0xBF, 0x36,
0x6F, 0xEE, 0xC0, 0xFF, 0xF0, 0x36, 0xEC, 0xCC, 0xCC, 0xCE, 0x63, 0xC6,
0x73, 0x33, 0x33, 0x37, 0x6C, 0x66, 0x66, 0x3C, 0x3C, 0xFF, 0xFF, 0x3C,
0x3C, 0x66, 0x66, 0x30, 0xC3, 0x3F, 0xFC, 0xC3, 0x0C, 0x6D, 0xBD, 0x00,
0xFF, 0xF0, 0xFF, 0x0C, 0x30, 0xC6, 0x18, 0xC3, 0x18, 0x63, 0x0C, 0x30,
0x7B, 0xFC, 0xF3, 0xCF, 0x7E, 0xF3, 0xCF, 0x3F, 0xDE, 0x30, 0xC7, 0x1C,
0x30, 0xC3, 0x0C, 0x30, 0xCF, 0xFF, 0x7B, 0xFC, 0xF3, 0x18, 0x63, 0x0C,
0x61, 0x8F, 0xFF, 0xFF, 0xF1, 0x86, 0x30, 0xC1, 0x86, 0xCF, 0x3F, 0xDE,
0x18, 0x63, 0x8E, 0x79, 0xED, 0xB6, 0xFF, 0xF1, 0x86, 0xFF, 0xFC, 0x30,
0xFB, 0xF0, 0xC3, 0x0F, 0x3F, 0xDE, 0x39, 0xEE, 0x30, 0xC3, 0xEF, 0xF3,
0xCF, 0x3F, 0xDE, 0xFF, 0xF0, 0xC3, 0x18, 0x63, 0x0C, 0x61, 0x86, 0x18,
0x7B, 0xFC, 0xF3, 0x79, 0xEC, 0xF3, 0xCF, 0x3F, 0xDE, 0x7B, 0xFC, 0xF3,
0xFD, 0xF0, 0xC3, 0x0C, 0x77, 0x9C, 0xFF, 0x0F, 0xF0, 0x6D, 0xB0, 0x1B,
0x6F, 0x40, 0x0E, 0x38, 0xE3, 0x8E, 0x0E, 0x0E, 0x0E, 0x0E, 0xFF, 0xF0,
0x00, 0xFF, 0xF0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE3, 0x8E, 0x38, 0xE0, 0x7B,
0xFC, 0xF3, 0x18, 0x63, 0x0C, 0x30, 0x03, 0x0C, 0x38, 0xFB, 0x9E, 0x1D,
0xBA, 0xF5, 0xEE, 0xC1, 0xC5, 0xF9, 0xE0, 0x31, 0xEF, 0xF3, 0xCF, 0x3F,
0xFF, 0xCF, 0x3C, 0xF3, 0xFB, 0xFC, 0xF3, 0xFF, 0xEC, 0xF3, 0xCF, 0x3F,
0xFE, 0x7B, 0xFC, 0xF3, 0xC3, 0x0C, 0x30, 0xCF, 0x3F, 0xDE, 0xF3, 0xED,
0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x7F, 0xBC, 0xFF, 0xFC, 0x30, 0xFB, 0xEC,
0x30, 0xC3, 0x0F, 0xFF, 0xFF, 0xFC, 0x30, 0xFB, 0xEC, 0x30, 0xC3, 0x0C,
0x30, 0x7F, 0xFC, 0x30, 0xDF, 0x7C, 0xF3, 0xCF, 0x3F, 0xDE, 0xCF, 0x3C,
0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFF, 0xF3, 0x0C, 0x30, 0xC3,
0x0C, 0x30, 0xCF, 0xFF, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0xCF, 0x3F,
0xDE, 0xCD, 0x9B, 0x66, 0xCF, 0x1E, 0x36, 0x6C, 0xCD, 0x9B, 0x1E, 0x30,
0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0F, 0xFF, 0xC7, 0x8F, 0xBF,
0x7F, 0xFA, 0xF5, 0xE3, 0xC7, 0x8F, 0x1E, 0x30, 0xCF, 0x3C, 0xFB, 0xEF,
0xFF, 0xF7, 0xDF, 0x3C, 0xF3, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF,
0x3F, 0xDE, 0xFB, 0xFC, 0xF3, 0xCF, 0x3F, 0xFE, 0xC3, 0x0C, 0x30, 0x7B,
0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x5F, 0x9B, 0xF9, 0xFB, 0x36, 0x6C,
0xDF, 0xBE, 0x6C, 0xCD, 0x9B, 0x1E, 0x30, 0x7F, 0xFC, 0x30, 0xE1, 0xC3,
0x87, 0x0C, 0x3F, 0xFE, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3,
0x0C, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDE, 0xCF, 0x3C,
0xF3, 0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0xC7, 0x8F, 0x1E, 0x3C, 0x7A,
0xF5, 0xFF, 0xFF, 0xDF, 0x1C, 0x10, 0xCF, 0x3C, 0xDE, 0x78, 0xC3, 0x1E,
0x7B, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0x30, 0xC3, 0x0C,
0xFF, 0xF1, 0x86, 0x30, 0xC6, 0x18, 0xC3, 0x0F, 0xFF, 0xFF, 0xCC, 0xCC,
0xCC, 0xCC, 0xFF, 0xC3, 0x0C, 0x18, 0x60, 0xC3, 0x06, 0x18, 0x30, 0xC3,
0xFF, 0x33, 0x33, 0x33, 0x33, 0xFF, 0x10, 0x20, 0xE1, 0xC6, 0xCD, 0xB1,
0xE3, 0xFF, 0xFC, 0x86, 0x38, 0xE3, 0x8C, 0x20, 0x79, 0xF0, 0xDF, 0xFF,
0x3C, 0xFF, 0x7C, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3F, 0xFE,
0x7B, 0xEC, 0x30, 0xC3, 0x0C, 0x3F, 0x7C, 0x0C, 0x30, 0xDF, 0xFF, 0x3C,
0xF3, 0xCF, 0x3F, 0xDF, 0x7B, 0xFC, 0xF3, 0xFF, 0x0C, 0x3F, 0x7C, 0x1C,
0xF3, 0x0C, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x7F, 0xFC, 0xF3, 0xCF,
0x3F, 0xDF, 0x0F, 0xFF, 0x80, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF,
0x3C, 0xF3, 0x66, 0x0E, 0xE6, 0x66, 0x66, 0xFF, 0x18, 0xC0, 0x31, 0x8C,
0x63, 0x18, 0xC6, 0x3F, 0xF8, 0xC1, 0x83, 0x06, 0x6D, 0xDF, 0x3C, 0x7C,
0xD9, 0x9B, 0x3E, 0x30, 0xEE, 0x66, 0x66, 0x66, 0x66, 0xFF, 0x6D, 0xFF,
0xFE, 0xBD, 0x7A, 0xF1, 0xE3, 0xC6, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3,
0xCC, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0xFB, 0xFC, 0xF3, 0xCF,
0x3C, 0xFF, 0xFB, 0x0C, 0x00, 0x7F, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C,
0x30, 0xC0, 0xFB, 0xFC, 0xF0, 0xC3, 0x0C, 0x30, 0xC0, 0x7F, 0xFC, 0x38,
0x78, 0x70, 0xFF, 0xF8, 0x30, 0xCF, 0xFF, 0x30, 0xC3, 0x0C, 0x30, 0xF1,
0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0xCF, 0x3C, 0xF3, 0xCD,
0xE7, 0x8C, 0x30, 0xC7, 0x8F, 0x5E, 0xBF, 0xFF, 0xFB, 0xE3, 0x82, 0xCF,
0x37, 0x9E, 0x31, 0xE7, 0xB3, 0xCC, 0xCF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDF,
0x0F, 0xFF, 0x80, 0xFF, 0xF1, 0x8C, 0x31, 0x86, 0x3F, 0xFC, 0x0E, 0x30,
0x60, 0xC1, 0x87, 0x3C, 0x78, 0x38, 0x30, 0x60, 0xC1, 0x81, 0xC0, 0xFF,
0xFF, 0xFF, 0xF0, 0xE0, 0x60, 0xC1, 0x83, 0x07, 0x07, 0x8F, 0x38, 0x60,
0xC1, 0x83, 0x1C, 0x00, 0x63, 0xE6, 0xFC, 0xE0, 0xFC, 0x63, 0x18, 0xC6,
0x31, 0x8C, 0x7E, 0x00, 0xF3, 0xFF, 0xFF, 0x30, 0xC7, 0xBF, 0xCF, 0x0C,
0x33, 0xFD, 0xE3, 0x0C, 0x0E, 0x1E, 0x38, 0x30, 0x30, 0x30, 0x30, 0xFE,
0x30, 0x30, 0x30, 0x7F, 0xFF, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E,
0xCF, 0x3C, 0xF3, 0xFD, 0xE3, 0x3F, 0x30, 0xC3, 0x0C, 0xFC, 0x63, 0x18,
0xC6, 0x31, 0x8C, 0x7E, 0x39, 0xB6, 0x4C, 0x7B, 0x3C, 0xDE, 0x32, 0x6D,
0x9C, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0x7D, 0x8E, 0x0D, 0xDA,
0x34, 0x68, 0xDD, 0x83, 0x8D, 0xF0, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF,
0x7C, 0x0F, 0xC0, 0x1A, 0x6D, 0xB6, 0xC6, 0xC6, 0xC6, 0x80, 0xFF, 0xF0,
0xC3, 0x0C, 0xFF, 0x7D, 0x8E, 0x0D, 0xDA, 0xB6, 0x6E, 0xD5, 0x83, 0x8D,
0xF0, 0xFF, 0xFC, 0x76, 0xE3, 0xB7, 0x00, 0x30, 0xC3, 0x3F, 0xFC, 0xC3,
0x0C, 0x03, 0xFF, 0xC0, 0x69, 0x36, 0xCF, 0xF3, 0x63, 0x96, 0xFC, 0x63,
0x18, 0xC6, 0x31, 0x8C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F,
0x5D, 0xC0, 0x80, 0x7B, 0x97, 0x2E, 0x5C, 0xB9, 0x5E, 0x85, 0x0A, 0x14,
0x28, 0x50, 0x6F, 0xF6, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0xD5,
0x50, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0F, 0xC0, 0xB1, 0xB1,
0xB1, 0xB6, 0xDB, 0x2C, 0x00, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E,
0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0xFC, 0x63, 0x18, 0xC6, 0x31,
0x8C, 0x7E, 0x30, 0xC0, 0x0C, 0x30, 0xC6, 0x18, 0xCF, 0x3F, 0xDE, 0xC1,
0x83, 0x00, 0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x0C, 0x63,
0x00, 0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x31, 0xEC, 0xC0,
0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x67, 0xD9, 0x80, 0x7B,
0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0xCF, 0x33, 0x1E, 0xFF, 0x3C,
0xFF, 0xFF, 0x3C, 0xF3, 0xCC, 0x7B, 0x37, 0x8C, 0x7B, 0xFC, 0xF3, 0xFF,
0xFC, 0xF3, 0xCF, 0x30, 0x3E, 0xFF, 0xE6, 0xCD, 0x9B, 0xF7, 0xFC, 0xF9,
0xB3, 0x66, 0xFD, 0xE0, 0x7B, 0xFC, 0xF3, 0xC3, 0x0C, 0x30, 0xCF, 0x3F,
0xDE, 0x19, 0xC0, 0xC1, 0x83, 0x00, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30,
0xFF, 0xF0, 0x0C, 0x63, 0x00, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30, 0xFF,
0xF0, 0x31, 0xEC, 0xC0, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30, 0xFF, 0xF0,
0xCF, 0x30, 0x3F, 0xFF, 0x0F, 0xBE, 0xC3, 0x0C, 0x3F, 0xFC, 0xC1, 0x83,
0x00, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0x0C, 0x63, 0x00,
0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0x31, 0xEC, 0xC0, 0xFF,
0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0xCF, 0x30, 0x3F, 0xFC, 0xC3,
0x0C, 0x30, 0xC3, 0x3F, 0xFC, 0x78, 0xF9, 0xBB, 0x36, 0x7E, 0xFD, 0xB3,
0x66, 0xDD, 0xF3, 0xC0, 0x67, 0xD9, 0x80, 0xCF, 0x3E, 0xFF, 0xFF, 0x7C,
0xF3, 0xCC, 0xC1, 0x83, 0x00, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD,
0xE0, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0,
0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0x67,
0xD9, 0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0xCF, 0x30,
0x1E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0xCD, 0xE3, 0x1E, 0xCC,
0x01, 0x3D, 0x7E, 0x66, 0x66, 0x6E, 0x6E, 0x76, 0x76, 0x66, 0x66, 0x7E,
0xBC, 0x80, 0xC1, 0x83, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD,
0xE0, 0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0,
0x31, 0xEC, 0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0xCF,
0x30, 0x33, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0C, 0x63, 0x00,
0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0x30, 0xC0, 0xC3, 0x0F, 0xBF, 0xCF,
0x3C, 0xFF, 0xFB, 0x0C, 0x30, 0x31, 0xEC, 0xF3, 0xCF, 0xEC, 0xF3, 0xCF,
0xED, 0xB0, 0x80, 0xC1, 0x83, 0x00, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF,
0x7C, 0x0C, 0x63, 0x00, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0x31,
0xEC, 0xC0, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0x67, 0xD9, 0x80,
0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0xCF, 0x30, 0x1E, 0x7C, 0x37,
0xFF, 0xCF, 0x3F, 0xDF, 0x39, 0xB3, 0x80, 0x79, 0xF0, 0xDF, 0xFF, 0x3C,
0xFF, 0x7C, 0x76, 0x7F, 0x1B, 0x7B, 0xFF, 0xD8, 0xD8, 0xFF, 0x7F, 0x7B,
0xEC, 0x30, 0xC3, 0x0C, 0x3F, 0x7C, 0x67, 0x00, 0xC1, 0x83, 0x00, 0x7B,
0xFC, 0xF3, 0xFF, 0x0C, 0x3F, 0x7C, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3,
0xFF, 0x0C, 0x3F, 0x7C, 0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xFF, 0x0C,
0x3F, 0x7C, 0xCF, 0x30, 0x1E, 0xFF, 0x3C, 0xFF, 0xC3, 0x0F, 0xDF, 0xC3,
0x0C, 0x07, 0x38, 0xC6, 0x31, 0x8C, 0xF7, 0x80, 0x19, 0x98, 0x0E, 0x71,
0x8C, 0x63, 0x19, 0xEF, 0x00, 0x31, 0xEC, 0xC0, 0x71, 0xC3, 0x0C, 0x30,
0xC3, 0x1E, 0x78, 0xCF, 0x30, 0x1C, 0x70, 0xC3, 0x0C, 0x30, 0xC7, 0x9E,
0x78, 0xC7, 0x86, 0x7F, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x67, 0xD9,
0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCC, 0xC1, 0x83, 0x00, 0x7B,
0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3,
0xCF, 0x3C, 0xFF, 0x78, 0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C,
0xFF, 0x78, 0x67, 0xD9, 0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78,
0xCF, 0x30, 0x1E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDE, 0x30, 0xC0, 0x3F,
0xFC, 0x03, 0x0C, 0x01, 0x3D, 0x7E, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x7E,
0xBC, 0x80, 0xC1, 0x83, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C,
0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0x31, 0xEC,
0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0xCF, 0x30, 0x33, 0xCF,
0x3C, 0xF3, 0xCF, 0x3F, 0xDF, 0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF,
0x3F, 0xDF, 0x0F, 0xFF, 0x80, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF,
0x3F, 0xFE, 0xC3, 0x00, 0xCF, 0x30, 0x33, 0xCF, 0x3C, 0xF3, 0xCF, 0xF7,
0xC3, 0xFF, 0xE0 };
const GFXglyph Atari16pxGlyphs[] PROGMEM = {
{ 0, 1, 1, 8, 0, 0 }, // 0x20 ' ' U+0020
{ 1, 2, 12, 8, 3, -11 }, // 0x21 '!' U+0021
{ 4, 6, 6, 8, 1, -11 }, // 0x22 '"' U+0022
{ 9, 8, 10, 8, 0, -11 }, // 0x23 '#' U+0023
{ 19, 6, 14, 8, 1, -13 }, // 0x24 '$' U+0024
{ 30, 6, 10, 8, 1, -11 }, // 0x25 '%' U+0025
{ 38, 7, 14, 8, 0, -13 }, // 0x26 '&' U+0026
{ 51, 2, 6, 8, 3, -11 }, // 0x27 ''' U+0027
{ 53, 4, 12, 8, 3, -11 }, // 0x28 '(' U+0028
{ 59, 4, 12, 8, 1, -11 }, // 0x29 ')' U+0029
{ 65, 8, 10, 8, 0, -11 }, // 0x2a '*' U+002A
{ 75, 6, 8, 8, 1, -10 }, // 0x2b '+' U+002B
{ 81, 3, 6, 8, 2, -3 }, // 0x2c ',' U+002C
{ 84, 6, 2, 8, 1, -7 }, // 0x2d '-' U+002D
{ 86, 2, 4, 8, 3, -3 }, // 0x2e '.' U+002E
{ 87, 6, 12, 8, 1, -11 }, // 0x2f '/' U+002F
{ 96, 6, 12, 8, 1, -11 }, // 0x30 '0' U+0030
{ 105, 6, 12, 8, 1, -11 }, // 0x31 '1' U+0031
{ 114, 6, 12, 8, 1, -11 }, // 0x32 '2' U+0032
{ 123, 6, 12, 8, 1, -11 }, // 0x33 '3' U+0033
{ 132, 6, 12, 8, 1, -11 }, // 0x34 '4' U+0034
{ 141, 6, 12, 8, 1, -11 }, // 0x35 '5' U+0035
{ 150, 6, 12, 8, 1, -11 }, // 0x36 '6' U+0036
{ 159, 6, 12, 8, 1, -11 }, // 0x37 '7' U+0037
{ 168, 6, 12, 8, 1, -11 }, // 0x38 '8' U+0038
{ 177, 6, 12, 8, 1, -11 }, // 0x39 '9' U+0039
{ 186, 2, 10, 8, 3, -9 }, // 0x3a ':' U+003A
{ 189, 3, 12, 8, 2, -9 }, // 0x3b ';' U+003B
{ 194, 7, 9, 8, 0, -10 }, // 0x3c '<' U+003C
{ 202, 6, 6, 8, 1, -9 }, // 0x3d '=' U+003D
{ 207, 7, 9, 8, 0, -10 }, // 0x3e '>' U+003E
{ 215, 6, 12, 8, 1, -11 }, // 0x3f '?' U+003F
{ 224, 7, 12, 8, 0, -11 }, // 0x40 '@' U+0040
{ 235, 6, 12, 8, 1, -11 }, // 0x41 'A' U+0041
{ 244, 6, 12, 8, 1, -11 }, // 0x42 'B' U+0042
{ 253, 6, 12, 8, 1, -11 }, // 0x43 'C' U+0043
{ 262, 6, 12, 8, 1, -11 }, // 0x44 'D' U+0044
{ 271, 6, 12, 8, 1, -11 }, // 0x45 'E' U+0045
{ 280, 6, 12, 8, 1, -11 }, // 0x46 'F' U+0046
{ 289, 6, 12, 8, 1, -11 }, // 0x47 'G' U+0047
{ 298, 6, 12, 8, 1, -11 }, // 0x48 'H' U+0048
{ 307, 6, 12, 8, 1, -11 }, // 0x49 'I' U+0049
{ 316, 6, 12, 8, 1, -11 }, // 0x4a 'J' U+004A
{ 325, 7, 12, 8, 0, -11 }, // 0x4b 'K' U+004B
{ 336, 6, 12, 8, 1, -11 }, // 0x4c 'L' U+004C
{ 345, 7, 12, 8, 0, -11 }, // 0x4d 'M' U+004D
{ 356, 6, 12, 8, 1, -11 }, // 0x4e 'N' U+004E
{ 365, 6, 12, 8, 1, -11 }, // 0x4f 'O' U+004F
{ 374, 6, 12, 8, 1, -11 }, // 0x50 'P' U+0050
{ 383, 6, 12, 8, 1, -11 }, // 0x51 'Q' U+0051
{ 392, 7, 12, 8, 0, -11 }, // 0x52 'R' U+0052
{ 403, 6, 12, 8, 1, -11 }, // 0x53 'S' U+0053
{ 412, 6, 12, 8, 1, -11 }, // 0x54 'T' U+0054
{ 421, 6, 12, 8, 1, -11 }, // 0x55 'U' U+0055
{ 430, 6, 12, 8, 1, -11 }, // 0x56 'V' U+0056
{ 439, 7, 12, 8, 0, -11 }, // 0x57 'W' U+0057
{ 450, 6, 12, 8, 1, -11 }, // 0x58 'X' U+0058
{ 459, 6, 12, 8, 1, -11 }, // 0x59 'Y' U+0059
{ 468, 6, 12, 8, 1, -11 }, // 0x5a 'Z' U+005A
{ 477, 4, 12, 8, 3, -11 }, // 0x5b '[' U+005B
{ 483, 6, 12, 8, 1, -11 }, // 0x5c '\' U+005C
{ 492, 4, 12, 8, 1, -11 }, // 0x5d ']' U+005D
{ 498, 7, 8, 8, 0, -12 }, // 0x5e '^' U+005E
{ 505, 7, 2, 8, 0, -1 }, // 0x5f '_' U+005F
{ 507, 5, 7, 8, 1, -13 }, // 0x60 '`' U+0060
{ 512, 6, 9, 8, 1, -8 }, // 0x61 'a' U+0061
{ 519, 6, 12, 8, 1, -11 }, // 0x62 'b' U+0062
{ 528, 6, 9, 8, 1, -8 }, // 0x63 'c' U+0063
{ 535, 6, 12, 8, 1, -11 }, // 0x64 'd' U+0064
{ 544, 6, 9, 8, 1, -8 }, // 0x65 'e' U+0065
{ 551, 6, 12, 8, 1, -11 }, // 0x66 'f' U+0066
{ 560, 6, 11, 8, 1, -8 }, // 0x67 'g' U+0067
{ 569, 6, 12, 8, 1, -11 }, // 0x68 'h' U+0068
{ 578, 4, 12, 8, 2, -11 }, // 0x69 'i' U+0069
{ 584, 5, 14, 8, 1, -11 }, // 0x6a 'j' U+006A
{ 593, 7, 12, 8, 0, -11 }, // 0x6b 'k' U+006B
{ 604, 4, 12, 8, 2, -11 }, // 0x6c 'l' U+006C
{ 610, 7, 9, 8, 0, -8 }, // 0x6d 'm' U+006D
{ 618, 6, 9, 8, 1, -8 }, // 0x6e 'n' U+006E
{ 625, 6, 9, 8, 1, -8 }, // 0x6f 'o' U+006F
{ 632, 6, 11, 8, 1, -8 }, // 0x70 'p' U+0070
{ 641, 6, 11, 8, 1, -8 }, // 0x71 'q' U+0071
{ 650, 6, 9, 8, 1, -8 }, // 0x72 'r' U+0072
{ 657, 6, 9, 8, 1, -8 }, // 0x73 's' U+0073
{ 664, 6, 11, 8, 1, -10 }, // 0x74 't' U+0074
{ 673, 6, 9, 8, 1, -8 }, // 0x75 'u' U+0075
{ 680, 6, 9, 8, 1, -8 }, // 0x76 'v' U+0076
{ 687, 7, 9, 8, 0, -8 }, // 0x77 'w' U+0077
{ 695, 6, 9, 8, 1, -8 }, // 0x78 'x' U+0078
{ 702, 6, 11, 8, 1, -8 }, // 0x79 'y' U+0079
{ 711, 6, 9, 8, 1, -8 }, // 0x7a 'z' U+007A
{ 718, 7, 14, 8, 0, -12 }, // 0x7b '{' U+007B
{ 731, 2, 14, 8, 3, -12 }, // 0x7c '|' U+007C
{ 735, 7, 14, 8, 0, -12 }, // 0x7d '}' U+007D
{ 748, 7, 4, 8, 0, -8 }, // 0x7e '~' U+007E
{ 752, 5, 11, 8, 1, -10 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
{ 759, 1, 1, 8, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
{ 760, 2, 12, 8, 3, -10 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
{ 763, 6, 12, 8, 1, -11 }, // 0x82 'CENT SIGN' U+00A2
{ 772, 8, 13, 8, 0, -12 }, // 0x83 'POUND SIGN' U+00A3
{ 785, 5, 11, 8, 1, -10 }, // 0x84 'CURRENCY SIGN' U+00A4
{ 792, 6, 12, 8, 1, -11 }, // 0x85 'YEN SIGN' U+00A5
{ 801, 5, 11, 8, 1, -10 }, // 0x86 'BROKEN BAR' U+00A6
{ 808, 6, 12, 8, 1, -11 }, // 0x87 'SECTION SIGN' U+00A7
{ 817, 5, 11, 8, 1, -10 }, // 0x88 'DIAERESIS' U+00A8
{ 824, 7, 11, 8, 0, -11 }, // 0x89 'COPYRIGHT SIGN' U+00A9
{ 834, 6, 11, 8, 1, -9 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
{ 843, 7, 7, 8, 0, -7 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
{ 850, 6, 5, 8, 1, -4 }, // 0x8c 'NOT SIGN' U+00AC
{ 854, 4, 2, 8, 2, -4 }, // 0x8d 'SOFT HYPHEN' U+00AD
{ 855, 7, 11, 8, 0, -11 }, // 0x8e 'REGISTERED SIGN' U+00AE
{ 865, 7, 2, 8, 0, -12 }, // 0x8f 'MACRON' U+00AF
{ 867, 5, 5, 8, 1, -12 }, // 0x90 'DEGREE SIGN' U+00B0
{ 871, 6, 11, 8, 1, -10 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
{ 880, 4, 6, 8, 1, -11 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
{ 883, 4, 6, 8, 1, -11 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
{ 886, 5, 11, 8, 1, -10 }, // 0x94 'ACUTE ACCENT' U+00B4
{ 893, 8, 10, 8, 0, -8 }, // 0x95 'MICRO SIGN' U+00B5
{ 903, 7, 12, 8, 0, -11 }, // 0x96 'PILCROW SIGN' U+00B6
{ 914, 4, 4, 8, 2, -6 }, // 0x97 'MIDDLE DOT' U+00B7
{ 916, 5, 11, 8, 1, -10 }, // 0x98 'CEDILLA' U+00B8
{ 923, 2, 6, 8, 1, -11 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
{ 925, 6, 11, 8, 1, -9 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
{ 934, 7, 7, 8, 0, -7 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
{ 941, 5, 11, 8, 1, -10 }, // 0x9c 'VULGAR FRACTION ONE QUARTER' U+00BC
{ 948, 5, 11, 8, 1, -10 }, // 0x9d 'VULGAR FRACTION ONE HALF' U+00BD
{ 955, 5, 11, 8, 1, -10 }, // 0x9e 'VULGAR FRACTION THREE QUARTERS' U+00BE
{ 962, 6, 12, 8, 1, -11 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
{ 971, 6, 14, 8, 1, -13 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
{ 982, 6, 14, 8, 1, -13 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
{ 993, 6, 14, 8, 1, -13 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
{ 1004, 6, 14, 8, 1, -13 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
{ 1015, 6, 13, 8, 1, -12 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
{ 1025, 6, 14, 8, 1, -13 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
{ 1036, 7, 13, 8, 0, -12 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
{ 1048, 6, 14, 8, 1, -11 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
{ 1059, 6, 14, 8, 1, -13 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
{ 1070, 6, 14, 8, 1, -13 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
{ 1081, 6, 14, 8, 1, -13 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
{ 1092, 6, 13, 8, 1, -12 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
{ 1102, 6, 14, 8, 1, -13 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
{ 1113, 6, 14, 8, 1, -13 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
{ 1124, 6, 14, 8, 1, -13 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
{ 1135, 6, 13, 8, 1, -12 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
{ 1145, 7, 12, 8, 0, -11 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
{ 1156, 6, 13, 8, 1, -12 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
{ 1166, 6, 14, 8, 1, -13 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
{ 1177, 6, 14, 8, 1, -13 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
{ 1188, 6, 14, 8, 1, -13 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
{ 1199, 6, 14, 8, 1, -13 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
{ 1210, 6, 13, 8, 1, -12 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
{ 1220, 6, 5, 8, 1, -6 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
{ 1224, 8, 14, 8, 0, -12 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
{ 1238, 6, 14, 8, 1, -13 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
{ 1249, 6, 14, 8, 1, -13 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
{ 1260, 6, 14, 8, 1, -13 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
{ 1271, 6, 13, 8, 1, -12 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
{ 1281, 6, 14, 8, 1, -13 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
{ 1292, 6, 12, 8, 1, -11 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
{ 1301, 6, 13, 8, 1, -11 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
{ 1311, 6, 13, 8, 1, -12 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
{ 1321, 6, 13, 8, 1, -12 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
{ 1331, 6, 13, 8, 1, -12 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
{ 1341, 6, 13, 8, 1, -12 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
{ 1351, 6, 12, 8, 1, -11 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
{ 1360, 6, 13, 8, 1, -12 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
{ 1370, 8, 9, 8, 0, -8 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
{ 1379, 6, 11, 8, 1, -8 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
{ 1388, 6, 13, 8, 1, -12 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
{ 1398, 6, 13, 8, 1, -12 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
{ 1408, 6, 13, 8, 1, -12 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
{ 1418, 6, 12, 8, 1, -11 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
{ 1427, 5, 13, 8, 1, -12 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
{ 1436, 5, 13, 8, 2, -12 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
{ 1445, 6, 13, 8, 1, -12 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
{ 1455, 6, 12, 8, 1, -11 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
{ 1464, 6, 13, 8, 1, -12 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
{ 1474, 6, 13, 8, 1, -12 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
{ 1484, 6, 13, 8, 1, -12 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
{ 1494, 6, 13, 8, 1, -12 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
{ 1504, 6, 13, 8, 1, -12 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
{ 1514, 6, 13, 8, 1, -12 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
{ 1524, 6, 12, 8, 1, -11 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
{ 1533, 6, 8, 8, 1, -10 }, // 0xd7 'DIVISION SIGN' U+00F7
{ 1539, 8, 11, 8, 0, -9 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
{ 1550, 6, 13, 8, 1, -12 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
{ 1560, 6, 13, 8, 1, -12 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
{ 1570, 6, 13, 8, 1, -12 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
{ 1580, 6, 12, 8, 1, -11 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
{ 1589, 6, 15, 8, 1, -12 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
{ 1601, 6, 14, 8, 1, -11 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
{ 1612, 6, 14, 8, 1, -11 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
const GFXfont Atari16px PROGMEM = {
(uint8_t *)Atari16pxBitmaps,
(GFXglyph *)Atari16pxGlyphs,
0x20, 0xDF, 16 };
// Approx. 2974 bytes

File diff suppressed because it is too large Load Diff

View File

@@ -1,485 +0,0 @@
const uint8_t Ubuntu_Bold10pt8bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xC0, 0xEF, 0xDF, 0xBF, 0x7E, 0xFD,
0xC0, 0x0E, 0xE0, 0xEE, 0x1D, 0xCF, 0xFF, 0xFF, 0xF1, 0xDC, 0x1D, 0xC3,
0xB8, 0xFF, 0xFF, 0xFF, 0x3B, 0x83, 0xB8, 0x77, 0x07, 0x70, 0x1C, 0x0E,
0x0F, 0xCF, 0xEE, 0x07, 0x03, 0x81, 0xFC, 0x7F, 0x0F, 0xC0, 0xE0, 0x74,
0x3F, 0xF9, 0xF8, 0x38, 0x1C, 0x00, 0x38, 0x38, 0x7C, 0x70, 0xC6, 0x70,
0xC6, 0xE0, 0xC6, 0xE0, 0xC7, 0xC0, 0x7D, 0xDC, 0x3B, 0xBE, 0x03, 0xE3,
0x07, 0x63, 0x07, 0x63, 0x0E, 0x63, 0x0E, 0x3E, 0x1C, 0x1C, 0x1E, 0x01,
0xF8, 0x1F, 0xE0, 0xE7, 0x07, 0x38, 0x1F, 0x80, 0xF8, 0x0F, 0xCE, 0xEF,
0x77, 0x3F, 0x38, 0xF9, 0xFF, 0xC7, 0xFF, 0x1F, 0xBC, 0xFF, 0xFF, 0xC0,
0x08, 0x73, 0x8E, 0x71, 0xCE, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x87, 0x1C,
0x38, 0xE1, 0xC2, 0x43, 0x87, 0x1C, 0x38, 0xE1, 0xC7, 0x1C, 0x71, 0xC7,
0x1C, 0x73, 0x8E, 0x71, 0xCE, 0x10, 0x1C, 0x0E, 0x17, 0x5F, 0xFF, 0xF9,
0xB1, 0xDC, 0x6C, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F, 0xFF, 0xFF, 0xFF,
0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0x77, 0x77, 0xEE, 0xFF, 0xFF,
0xC0, 0x6F, 0xF6, 0x01, 0xC0, 0xE0, 0x38, 0x0E, 0x07, 0x01, 0xC0, 0x70,
0x38, 0x0E, 0x03, 0x81, 0xC0, 0x70, 0x1C, 0x0E, 0x03, 0x80, 0xE0, 0x70,
0x1C, 0x07, 0x03, 0x80, 0x1C, 0x3F, 0x9F, 0xDE, 0xFE, 0x3F, 0x1F, 0x8F,
0xC7, 0xE3, 0xF1, 0xFD, 0xEF, 0xE7, 0xF0, 0xE0, 0x0E, 0x3D, 0xFF, 0xF6,
0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC0, 0x3E, 0x7F, 0xBF,
0xEC, 0x70, 0x38, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0xFF, 0xFF,
0xFC, 0x3C, 0x7F, 0x3F, 0xC8, 0xE0, 0x70, 0x30, 0xF0, 0x7E, 0x07, 0x81,
0xE0, 0xFF, 0xFF, 0xF3, 0xF0, 0x07, 0x07, 0x87, 0xC3, 0xE3, 0xF3, 0xB9,
0x9D, 0xCE, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0x70, 0x38, 0x3F, 0x1F, 0x8F,
0xC7, 0x03, 0x83, 0xF1, 0xFC, 0xFF, 0x07, 0x81, 0xC0, 0xFF, 0xFF, 0xF3,
0xE0, 0x07, 0x0F, 0x8F, 0xCF, 0x07, 0x07, 0xF3, 0xFD, 0xFF, 0xE3, 0xF1,
0xF8, 0xEF, 0xF7, 0xF1, 0xF0, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xE0, 0x70,
0x70, 0x38, 0x38, 0x1C, 0x0E, 0x0E, 0x07, 0x03, 0x80, 0x3E, 0x3F, 0xBF,
0xFC, 0x7E, 0x3F, 0xB9, 0xF8, 0xFE, 0xE7, 0xF1, 0xF8, 0xFF, 0xF7, 0xF1,
0xF0, 0x3E, 0x3F, 0xBF, 0xDC, 0x7E, 0x3F, 0x1F, 0xFE, 0xFF, 0x3F, 0x83,
0xC3, 0xCF, 0xC7, 0xC3, 0x80, 0x6F, 0xF6, 0x00, 0x06, 0xFF, 0x60, 0x33,
0xDE, 0x60, 0x00, 0x00, 0x73, 0x9C, 0xEE, 0x70, 0x01, 0x87, 0xEF, 0xFF,
0xF8, 0xE0, 0x3F, 0x8F, 0xFC, 0x7E, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xE0,
0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x60, 0x3E, 0x3F, 0xE3, 0xF0, 0x38, 0xFF,
0xFE, 0xF8, 0x60, 0x00, 0x7C, 0xFE, 0xFF, 0x07, 0x07, 0x07, 0x0E, 0x1E,
0x3C, 0x38, 0x38, 0x00, 0x30, 0x78, 0x78, 0x30, 0x03, 0xF0, 0x07, 0xFE,
0x0F, 0x03, 0x86, 0x00, 0xE6, 0x1F, 0xB7, 0x3F, 0xCF, 0x3C, 0xE7, 0x9C,
0x73, 0xCE, 0x39, 0xE7, 0x1C, 0xF3, 0xCE, 0x5C, 0xFF, 0xE6, 0x3F, 0xE3,
0x80, 0x00, 0xF0, 0x00, 0x3F, 0xE0, 0x07, 0xF8, 0x00, 0x03, 0x80, 0x0F,
0x80, 0x1F, 0x00, 0x77, 0x00, 0xEE, 0x03, 0xDE, 0x07, 0x1C, 0x1E, 0x3C,
0x3F, 0xF8, 0x7F, 0xF1, 0xFF, 0xF3, 0x80, 0xE7, 0x01, 0xDC, 0x01, 0xC0,
0xFE, 0x3F, 0xCF, 0xFB, 0x8E, 0xE3, 0xBF, 0xCF, 0xF3, 0xFE, 0xE1, 0xF8,
0x7E, 0x1F, 0xFF, 0xFF, 0xBF, 0x80, 0x0F, 0xC7, 0xFD, 0xFF, 0xBC, 0x2F,
0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1E, 0x01, 0xE0, 0x3F, 0xF3, 0xFE,
0x1F, 0x80, 0xFF, 0x0F, 0xFC, 0xFF, 0xEE, 0x1E, 0xE0, 0xFE, 0x07, 0xE0,
0x7E, 0x07, 0xE0, 0x7E, 0x0F, 0xE1, 0xEF, 0xFE, 0xFF, 0xCF, 0xF0, 0xFF,
0xFF, 0xFF, 0xFC, 0x0E, 0x07, 0xFB, 0xFD, 0xFE, 0xE0, 0x70, 0x38, 0x1F,
0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xFE, 0xFE, 0xFE, 0xE0,
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x0F, 0xC7, 0xFD, 0xFF, 0xBC, 0x2F, 0x01,
0xC0, 0x38, 0x07, 0x07, 0xE0, 0xFE, 0x1D, 0xE3, 0xBF, 0xF3, 0xFE, 0x1F,
0x80, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xC0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xC0, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07,
0x03, 0x81, 0xD1, 0xEF, 0xFF, 0xF3, 0xF0, 0xE0, 0xFE, 0x1E, 0xE3, 0xCE,
0x78, 0xEF, 0x0F, 0xE0, 0xFC, 0x0F, 0xC0, 0xEE, 0x0E, 0x70, 0xE7, 0x8E,
0x3C, 0xE1, 0xEE, 0x0F, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81,
0xC0, 0xE0, 0x70, 0x38, 0x1F, 0xFF, 0xFF, 0xFC, 0x70, 0x1C, 0xF0, 0x79,
0xE0, 0xF3, 0xE3, 0xE7, 0xC7, 0xDD, 0x8D, 0xFB, 0xBB, 0xF3, 0x67, 0xE7,
0xCF, 0xCF, 0x9F, 0x8E, 0x3F, 0x1C, 0x7E, 0x00, 0xFC, 0x01, 0xC0, 0xE0,
0xFE, 0x1F, 0xC3, 0xFC, 0x7F, 0xCF, 0xD9, 0xFB, 0xBF, 0x3F, 0xE7, 0xFC,
0x7F, 0x87, 0xF0, 0xFE, 0x0F, 0xC1, 0xC0, 0x0F, 0xC0, 0xFF, 0xC7, 0xFF,
0x9E, 0x1E, 0xF0, 0x3F, 0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0,
0xF7, 0x87, 0x9F, 0xFE, 0x3F, 0xF0, 0x3F, 0x00, 0xFE, 0x3F, 0xEF, 0xFF,
0x87, 0xE1, 0xF8, 0x7F, 0xFF, 0xFE, 0xFE, 0x38, 0x0E, 0x03, 0x80, 0xE0,
0x38, 0x00, 0x0F, 0xC0, 0xFF, 0xC7, 0xFF, 0x9E, 0x1E, 0xF0, 0x3F, 0x80,
0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE, 0x3F,
0xF0, 0x3F, 0x00, 0x3C, 0x00, 0x7E, 0x00, 0x78, 0xFE, 0x1F, 0xF3, 0xFF,
0x70, 0xEE, 0x1D, 0xC3, 0xBF, 0xF7, 0xFC, 0xFF, 0x1C, 0xF3, 0x8E, 0x70,
0xEE, 0x1D, 0xC1, 0xC0, 0x3F, 0x1F, 0xEF, 0xFB, 0x80, 0xE0, 0x3E, 0x07,
0xF0, 0x7E, 0x03, 0xC0, 0x74, 0x1F, 0xFF, 0xFF, 0x9F, 0xC0, 0xFF, 0xFF,
0xFF, 0xFF, 0x87, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0,
0x38, 0x07, 0x00, 0xE0, 0x1C, 0x00, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E,
0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0xC7, 0xBF, 0xE7, 0xFC,
0x3E, 0x00, 0xE0, 0x0E, 0xE0, 0x39, 0xC0, 0x71, 0xC1, 0xC3, 0x83, 0x87,
0x07, 0x07, 0x1C, 0x0E, 0x38, 0x0E, 0xE0, 0x1D, 0xC0, 0x1F, 0x00, 0x3E,
0x00, 0x7C, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xFC, 0x1C, 0x1D, 0xC3, 0x87,
0x38, 0x78, 0xE7, 0x1F, 0x1C, 0xE3, 0x63, 0x8E, 0x6C, 0xE1, 0xDD, 0xDC,
0x3B, 0xBB, 0x83, 0x63, 0x60, 0x7C, 0x7C, 0x0F, 0x8F, 0x81, 0xE0, 0xF0,
0x1C, 0x1C, 0x00, 0xF0, 0x3D, 0xE1, 0xE3, 0x87, 0x07, 0x38, 0x1F, 0xE0,
0x3F, 0x00, 0x78, 0x01, 0xE0, 0x0F, 0xC0, 0x7F, 0x81, 0xCE, 0x0E, 0x1C,
0x78, 0x7B, 0xC0, 0xF0, 0xE0, 0x3B, 0x83, 0x9C, 0x1C, 0x71, 0xC3, 0xDE,
0x0E, 0xE0, 0x3E, 0x01, 0xF0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00,
0x70, 0x03, 0x80, 0xFF, 0xFF, 0xFF, 0xFC, 0x0E, 0x07, 0x03, 0x80, 0xE0,
0x70, 0x38, 0x1E, 0x07, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xCE,
0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0xFF, 0xF0, 0xE0, 0x1C,
0x07, 0x01, 0xC0, 0x38, 0x0E, 0x03, 0x80, 0x70, 0x1C, 0x07, 0x00, 0xE0,
0x38, 0x0E, 0x01, 0xC0, 0x70, 0x1C, 0x03, 0x80, 0xE0, 0x38, 0x07, 0xFF,
0xFE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x3F, 0xFF, 0xF0,
0x0E, 0x03, 0xE0, 0x7C, 0x1D, 0xC7, 0xBC, 0xE3, 0xB8, 0x3B, 0x06, 0xFF,
0xFF, 0xF0, 0x47, 0x1E, 0x20, 0x7E, 0x3F, 0x9F, 0xE0, 0x73, 0xFB, 0xFF,
0x8F, 0xC7, 0xFF, 0xBF, 0xCF, 0xE0, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0,
0x3F, 0xCF, 0xFB, 0xFE, 0xE3, 0xF8, 0x7E, 0x1F, 0x87, 0xE3, 0xFF, 0xEF,
0xFB, 0xF8, 0x1F, 0x3F, 0x7F, 0xF0, 0xE0, 0xE0, 0xE0, 0xF0, 0x7F, 0x7F,
0x1F, 0x01, 0xC0, 0x70, 0x1C, 0x07, 0x01, 0xC7, 0xF7, 0xFD, 0xFF, 0xF1,
0xF8, 0x7E, 0x1F, 0x87, 0xF1, 0xDF, 0xF7, 0xFC, 0x7F, 0x1F, 0x1F, 0xE7,
0xFF, 0x87, 0xFF, 0xFF, 0xFE, 0x03, 0xC0, 0x7F, 0x9F, 0xE1, 0xF8, 0x3F,
0x7E, 0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xFE, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0xE0, 0xE0, 0x1F, 0xDF, 0xF7, 0xFF, 0xC7, 0xE1, 0xF8, 0x7F, 0x1F,
0xFF, 0x7F, 0xCF, 0xF0, 0x1C, 0x0F, 0x7F, 0x9F, 0xE7, 0xE0, 0xE0, 0x38,
0x0E, 0x03, 0x80, 0xE0, 0x3F, 0xCF, 0xFB, 0xFF, 0xE3, 0xF8, 0x7E, 0x1F,
0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF,
0x1C, 0x71, 0xC7, 0x00, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7,
0x1F, 0xFF, 0xBC, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC3, 0xB8,
0xE7, 0x38, 0xEE, 0x1F, 0x83, 0xF8, 0x77, 0x8E, 0x79, 0xC7, 0x38, 0x77,
0x07, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x7F, 0xE7, 0xFE,
0xF9, 0xFF, 0xFB, 0xFF, 0xFF, 0x1C, 0x7E, 0x38, 0xFC, 0x71, 0xF8, 0xE3,
0xF1, 0xC7, 0xE3, 0x8F, 0xC7, 0x1F, 0x8E, 0x38, 0xFF, 0x3F, 0xEF, 0xFF,
0x8F, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1C, 0x1E, 0x1F,
0xE7, 0xFB, 0xCF, 0xE1, 0xF8, 0x7E, 0x1F, 0xCF, 0x7F, 0x9F, 0xE1, 0xE0,
0xFE, 0x3F, 0xEF, 0xFB, 0x8F, 0xE1, 0xF8, 0x7E, 0x1F, 0x8F, 0xFF, 0xBF,
0xEF, 0xF3, 0x80, 0xE0, 0x38, 0x0E, 0x00, 0x1F, 0xDF, 0xF7, 0xFF, 0xC7,
0xE1, 0xF8, 0x7E, 0x1F, 0xC7, 0x7F, 0xDF, 0xF3, 0xFC, 0x07, 0x01, 0xC0,
0x70, 0x1C, 0x7F, 0xFF, 0xFF, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x80,
0x3E, 0xFE, 0xE0, 0xE0, 0xF8, 0x7E, 0x1F, 0x07, 0x87, 0xFF, 0xFC, 0xE1,
0xC3, 0x87, 0xFF, 0xFF, 0xF8, 0x70, 0xE1, 0xC3, 0x87, 0xF7, 0xE7, 0xC0,
0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0xC7, 0xFF, 0xDF,
0xF3, 0xFC, 0xE0, 0xFE, 0x1D, 0xC7, 0x38, 0xE7, 0xBC, 0x77, 0x0E, 0xE1,
0xFC, 0x1F, 0x03, 0xE0, 0x38, 0x00, 0xE3, 0x8F, 0xC7, 0x1D, 0x8E, 0x33,
0x9E, 0xE7, 0x7D, 0xCE, 0xDB, 0x8D, 0xB6, 0x1F, 0x7C, 0x3C, 0x78, 0x38,
0xE0, 0x71, 0xC0, 0xF1, 0xEF, 0x78, 0xEE, 0x1F, 0xC1, 0xF0, 0x1C, 0x07,
0xC1, 0xFC, 0x3B, 0x8F, 0x7B, 0xC7, 0x80, 0xE0, 0xFC, 0x1D, 0xC7, 0x38,
0xE7, 0x1C, 0x77, 0x0E, 0xE1, 0xFC, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x0F,
0xE1, 0xF8, 0x3E, 0x00, 0xFF, 0xFF, 0xFF, 0x0E, 0x1C, 0x38, 0x38, 0x70,
0xFF, 0xFF, 0xFF, 0x0E, 0x3C, 0xF9, 0xC3, 0x87, 0x0E, 0x1C, 0x79, 0xE3,
0xC7, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x7C, 0xF8, 0x70, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xE1, 0xE3, 0xE1, 0xC3, 0x87, 0x0E, 0x1C,
0x3C, 0x3C, 0x79, 0xF3, 0x87, 0x0E, 0x1C, 0x39, 0xF3, 0xE7, 0x00, 0x30,
0x9F, 0x3F, 0xFF, 0x3E, 0x43, 0x00, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x00, 0xFF, 0xF1,
0xFF, 0xFF, 0xFF, 0xF8, 0x1C, 0x1C, 0x1C, 0x3F, 0x7F, 0x7F, 0xF0, 0xE0,
0xE0, 0xF0, 0xFF, 0x7F, 0x3F, 0x1C, 0x1C, 0x1C, 0x0F, 0x87, 0xF3, 0xFC,
0xF0, 0x38, 0x0E, 0x0F, 0xF3, 0xFC, 0xFF, 0x0E, 0x03, 0x80, 0xFF, 0x3F,
0xDF, 0xF0, 0x40, 0xBF, 0xF7, 0xF9, 0xCE, 0x61, 0x98, 0x67, 0x39, 0xFE,
0xFF, 0xD0, 0x20, 0xE0, 0xEE, 0x39, 0xC7, 0x1D, 0xC3, 0xB8, 0x3E, 0x1F,
0xF3, 0xFE, 0x0E, 0x01, 0xC1, 0xFF, 0x3F, 0xE0, 0xE0, 0x1C, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x3E, 0x7F, 0xFF, 0xE0, 0xE0,
0x7C, 0xFE, 0xEF, 0xE7, 0xE7, 0xF7, 0x7E, 0x1E, 0x07, 0x07, 0xFF, 0xFF,
0x7C, 0xEF, 0xDF, 0xB8, 0x0F, 0xC0, 0x7F, 0x83, 0x87, 0x18, 0x06, 0xE7,
0xDF, 0x3F, 0x3C, 0xC0, 0xF3, 0x03, 0xCF, 0xCF, 0x9F, 0x76, 0x01, 0x8E,
0x1C, 0x1F, 0xE0, 0x3F, 0x00, 0x7C, 0xFC, 0x19, 0xFF, 0xF8, 0xFF, 0xBF,
0x10, 0x8E, 0x77, 0xBD, 0xCE, 0xF7, 0x9C, 0xE7, 0xBC, 0xE7, 0x10, 0x80,
0xFF, 0xFF, 0xFF, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0xFF, 0xFF, 0xC0,
0x0F, 0xC0, 0x7F, 0x83, 0x87, 0x18, 0x06, 0xEF, 0x9F, 0x33, 0x3C, 0xFC,
0xF3, 0xE3, 0xCD, 0xCF, 0xB3, 0x76, 0x01, 0x8E, 0x1C, 0x1F, 0xE0, 0x3F,
0x00, 0xFF, 0xF0, 0x7B, 0xFC, 0xF3, 0xFD, 0xE0, 0x0E, 0x01, 0xC0, 0x38,
0x07, 0x0F, 0xFF, 0xFF, 0xFF, 0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00,
0x0F, 0xFF, 0xFF, 0xFF, 0xF8, 0x7B, 0xF0, 0xC7, 0x31, 0x8F, 0xFF, 0x7B,
0xF0, 0xCF, 0x3C, 0x3F, 0xFE, 0x11, 0xFC, 0x80, 0xE1, 0xF8, 0x7E, 0x1F,
0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xE0,
0x38, 0x0E, 0x00, 0x1F, 0xF7, 0xFF, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7,
0xFE, 0x77, 0xE7, 0x1E, 0x70, 0xE7, 0x0E, 0x70, 0xE7, 0x0E, 0x70, 0xE7,
0x0E, 0x70, 0xE7, 0x0E, 0x70, 0xE7, 0x6F, 0xF6, 0x63, 0xBF, 0x37, 0xFB,
0x33, 0x33, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C, 0x42, 0x39,
0xCF, 0x79, 0xCE, 0x7B, 0xDC, 0xEF, 0x7B, 0x9C, 0x42, 0x00, 0x30, 0x30,
0x70, 0x70, 0xF0, 0x60, 0xB0, 0xE0, 0x31, 0xC0, 0x31, 0xC0, 0x33, 0x8E,
0x33, 0x9E, 0x07, 0x36, 0x07, 0x26, 0x0E, 0x7F, 0x0E, 0x7F, 0x1C, 0x06,
0x1C, 0x06, 0x30, 0x30, 0xE0, 0xE3, 0xC1, 0x85, 0x87, 0x03, 0x1C, 0x06,
0x38, 0x0C, 0xEF, 0x19, 0xFF, 0x07, 0x06, 0x0E, 0x1C, 0x38, 0x60, 0x71,
0x81, 0xC7, 0xE3, 0x8F, 0xC0, 0x78, 0x0C, 0x7E, 0x0E, 0x03, 0x06, 0x07,
0x87, 0x03, 0xC7, 0x00, 0x63, 0x83, 0xF3, 0x9D, 0xF1, 0xDE, 0x01, 0xDB,
0x00, 0xE9, 0x80, 0xEF, 0xE0, 0x77, 0xF0, 0x70, 0x30, 0x38, 0x18, 0x0C,
0x1E, 0x1E, 0x0C, 0x00, 0x1C, 0x1C, 0x3C, 0x78, 0x70, 0xE0, 0xE0, 0xFF,
0x7F, 0x3E, 0x02, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x04, 0x00, 0x00, 0x00,
0x70, 0x01, 0xF0, 0x03, 0xE0, 0x0E, 0xE0, 0x1D, 0xC0, 0x7B, 0xC0, 0xE3,
0x83, 0xC7, 0x87, 0xFF, 0x0F, 0xFE, 0x3F, 0xFE, 0x70, 0x1C, 0xE0, 0x3B,
0x80, 0x38, 0x00, 0x80, 0x03, 0x80, 0x1E, 0x00, 0x10, 0x00, 0x00, 0x00,
0x70, 0x01, 0xF0, 0x03, 0xE0, 0x0E, 0xE0, 0x1D, 0xC0, 0x7B, 0xC0, 0xE3,
0x83, 0xC7, 0x87, 0xFF, 0x0F, 0xFE, 0x3F, 0xFE, 0x70, 0x1C, 0xE0, 0x3B,
0x80, 0x38, 0x01, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x77, 0x00, 0x44, 0x00,
0x00, 0x00, 0xE0, 0x03, 0xE0, 0x07, 0xC0, 0x1D, 0xC0, 0x3B, 0x80, 0xF7,
0x81, 0xC7, 0x07, 0x8F, 0x0F, 0xFE, 0x1F, 0xFC, 0x7F, 0xFC, 0xE0, 0x39,
0xC0, 0x77, 0x00, 0x70, 0x06, 0x40, 0x1F, 0xC0, 0x13, 0x00, 0x00, 0x00,
0x38, 0x00, 0xF8, 0x01, 0xF0, 0x07, 0x70, 0x0E, 0xE0, 0x3D, 0xE0, 0x71,
0xC1, 0xE3, 0xC3, 0xFF, 0x87, 0xFF, 0x1F, 0xFF, 0x38, 0x0E, 0x70, 0x1D,
0xC0, 0x1C, 0x0E, 0xE0, 0x1D, 0xC0, 0x3B, 0x80, 0x00, 0x00, 0x38, 0x00,
0xF8, 0x01, 0xF0, 0x07, 0x70, 0x0E, 0xE0, 0x3D, 0xE0, 0x71, 0xC1, 0xE3,
0xC3, 0xFF, 0x87, 0xFF, 0x1F, 0xFF, 0x38, 0x0E, 0x70, 0x1D, 0xC0, 0x1C,
0x03, 0x80, 0x0D, 0x80, 0x1B, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x03,
0xF8, 0x07, 0x70, 0x0E, 0xE0, 0x38, 0xE0, 0x71, 0xC1, 0xE3, 0xC3, 0xFF,
0x87, 0xFF, 0x1F, 0xFF, 0x38, 0x0E, 0x70, 0x1D, 0xC0, 0x1C, 0x00, 0x7F,
0xE0, 0x1F, 0xFC, 0x07, 0xFF, 0x80, 0xFC, 0x00, 0x3B, 0x80, 0x0E, 0x7F,
0x81, 0xCF, 0xF0, 0x71, 0xFE, 0x1F, 0xF8, 0x03, 0xFF, 0x00, 0xFF, 0xE0,
0x1C, 0x1F, 0xF7, 0x03, 0xFF, 0xC0, 0x7F, 0xC0, 0x0F, 0xC7, 0xFD, 0xFF,
0xBC, 0x2F, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1E, 0x01, 0xE0, 0x3F,
0xF3, 0xFE, 0x1F, 0x81, 0x80, 0x18, 0x0F, 0x01, 0xC0, 0x10, 0x1C, 0x07,
0x80, 0x80, 0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0x70, 0x3F, 0xDF, 0xEF, 0xF7,
0x03, 0x81, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0x04, 0x07, 0x0F, 0x02, 0x00,
0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0x70, 0x3F, 0xDF, 0xEF, 0xF7, 0x03, 0x81,
0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0x08, 0x0E, 0x0F, 0x8E, 0xE2, 0x20, 0x03,
0xFF, 0xFF, 0xFF, 0xF0, 0x38, 0x1F, 0xEF, 0xF7, 0xFB, 0x81, 0xC0, 0xE0,
0x7F, 0xFF, 0xFF, 0xF0, 0x77, 0x3B, 0x9D, 0xC0, 0x0F, 0xFF, 0xFF, 0xFF,
0xC0, 0xE0, 0x7F, 0xBF, 0xDF, 0xEE, 0x07, 0x03, 0x81, 0xFF, 0xFF, 0xFF,
0xC0, 0x47, 0x1E, 0x20, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73,
0x9C, 0x11, 0xFC, 0x80, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73,
0x9C, 0x10, 0x71, 0xF7, 0x74, 0x40, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3,
0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC0, 0xEF, 0xDF, 0xB8, 0x03, 0x87,
0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0x3F,
0xC0, 0xFF, 0xC3, 0xFF, 0x8E, 0x1E, 0x38, 0x3C, 0xE0, 0x7F, 0xF1, 0xFF,
0xC7, 0x38, 0x1C, 0xE0, 0xF3, 0x87, 0x8F, 0xFE, 0x3F, 0xF0, 0xFF, 0x00,
0x19, 0x07, 0xF0, 0x4C, 0x00, 0x0E, 0x0F, 0xE1, 0xFC, 0x3F, 0xC7, 0xFC,
0xFD, 0x9F, 0xBB, 0xF3, 0xFE, 0x7F, 0xC7, 0xF8, 0x7F, 0x0F, 0xE0, 0xFC,
0x1C, 0x04, 0x00, 0x38, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x3F, 0x03,
0xFF, 0x1F, 0xFE, 0x78, 0x7B, 0xC0, 0xFE, 0x01, 0xF8, 0x07, 0xE0, 0x1F,
0x80, 0x7F, 0x03, 0xDE, 0x1E, 0x7F, 0xF8, 0xFF, 0xC0, 0xFC, 0x00, 0x00,
0x80, 0x07, 0x00, 0x78, 0x00, 0x80, 0x00, 0x00, 0x3F, 0x03, 0xFF, 0x1F,
0xFE, 0x78, 0x7B, 0xC0, 0xFE, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7F,
0x03, 0xDE, 0x1E, 0x7F, 0xF8, 0xFF, 0xC0, 0xFC, 0x00, 0x01, 0x00, 0x0E,
0x00, 0x7C, 0x03, 0xB8, 0x04, 0x40, 0x00, 0x00, 0xFC, 0x0F, 0xFC, 0x7F,
0xF9, 0xE1, 0xEF, 0x03, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7E, 0x01, 0xFC,
0x0F, 0x78, 0x79, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0x06, 0x40, 0x3F, 0x80,
0x4C, 0x00, 0x00, 0x0F, 0xC0, 0xFF, 0xC7, 0xFF, 0x9E, 0x1E, 0xF0, 0x3F,
0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE,
0x3F, 0xF0, 0x3F, 0x00, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x00, 0x00, 0x0F,
0xC0, 0xFF, 0xC7, 0xFF, 0x9E, 0x1E, 0xF0, 0x3F, 0x80, 0x7E, 0x01, 0xF8,
0x07, 0xE0, 0x1F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE, 0x3F, 0xF0, 0x3F, 0x00,
0x41, 0x71, 0xDD, 0xC7, 0xC1, 0xC1, 0xF1, 0xDD, 0xC7, 0x41, 0x00, 0x00,
0x00, 0x3F, 0x63, 0xFF, 0x9F, 0xFE, 0x78, 0xFB, 0xC3, 0xFE, 0x1D, 0xF8,
0xE7, 0xE7, 0x1F, 0xB8, 0x7F, 0xC3, 0xDE, 0x1E, 0x7F, 0xF9, 0xFF, 0xC6,
0xFC, 0x00, 0x00, 0x10, 0x07, 0x00, 0x78, 0x02, 0x00, 0x01, 0xC1, 0xF8,
0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F,
0x8F, 0x7F, 0xCF, 0xF8, 0x7C, 0x00, 0x02, 0x00, 0xE0, 0x78, 0x04, 0x00,
0x01, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F,
0xC1, 0xF8, 0x3F, 0x8F, 0x7F, 0xCF, 0xF8, 0x7C, 0x00, 0x04, 0x01, 0xC0,
0x7C, 0x1D, 0xC1, 0x10, 0x00, 0x38, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83,
0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xF1, 0xEF, 0xF9, 0xFF, 0x0F,
0x80, 0x3B, 0x87, 0x70, 0xEE, 0x00, 0x0E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07,
0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xFC, 0x7B, 0xFE, 0x7F,
0xC3, 0xE0, 0x01, 0x00, 0x1C, 0x03, 0xC0, 0x08, 0x00, 0x00, 0x70, 0x1D,
0xC1, 0xCE, 0x0E, 0x38, 0xE1, 0xEF, 0x07, 0x70, 0x1F, 0x00, 0xF8, 0x03,
0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0xE0, 0x38, 0x0F,
0xE3, 0xFE, 0xFF, 0xF8, 0x7E, 0x1F, 0x87, 0xFF, 0xFF, 0xEF, 0xE3, 0x80,
0xE0, 0x38, 0x00, 0x3E, 0x0F, 0xE3, 0xFE, 0x71, 0xCE, 0x39, 0xCF, 0x39,
0xC7, 0x70, 0xEF, 0x1D, 0xF3, 0x8F, 0x70, 0x7E, 0x0F, 0xDF, 0xFB, 0xF7,
0x7C, 0x10, 0x1C, 0x07, 0x80, 0x80, 0x03, 0xF1, 0xFC, 0xFF, 0x03, 0x9F,
0xDF, 0xFC, 0x7E, 0x3F, 0xFD, 0xFE, 0x7F, 0x04, 0x07, 0x0F, 0x02, 0x00,
0x03, 0xF1, 0xFC, 0xFF, 0x03, 0x9F, 0xDF, 0xFC, 0x7E, 0x3F, 0xFD, 0xFE,
0x7F, 0x08, 0x0E, 0x0F, 0x8E, 0xE2, 0x20, 0x01, 0xF8, 0xFE, 0x7F, 0x81,
0xCF, 0xEF, 0xFE, 0x3F, 0x1F, 0xFE, 0xFF, 0x3F, 0x80, 0x32, 0x3F, 0x89,
0x80, 0x07, 0xE3, 0xF9, 0xFE, 0x07, 0x3F, 0xBF, 0xF8, 0xFC, 0x7F, 0xFB,
0xFC, 0xFE, 0x77, 0x3B, 0x9D, 0xC0, 0x07, 0xE3, 0xF9, 0xFE, 0x07, 0x3F,
0xBF, 0xF8, 0xFC, 0x7F, 0xFB, 0xFC, 0xFE, 0x1E, 0x1F, 0x8C, 0xC6, 0x63,
0xF0, 0xF1, 0xF8, 0xFE, 0x7F, 0x81, 0xCF, 0xEF, 0xFE, 0x3F, 0x1F, 0xFE,
0xFF, 0x3F, 0x80, 0x7E, 0x78, 0xFF, 0xF9, 0xFF, 0xF8, 0x1C, 0x73, 0xFF,
0xEF, 0xFF, 0xF8, 0xE0, 0x71, 0xE0, 0xFF, 0xFC, 0xFF, 0xF8, 0xF9, 0xF0,
0x1E, 0x7F, 0x7E, 0xF0, 0xE0, 0xE0, 0xE0, 0xF0, 0x7F, 0x3F, 0x0F, 0x0C,
0x0C, 0x3C, 0x38, 0x10, 0x0E, 0x01, 0xE0, 0x10, 0x00, 0x07, 0xC7, 0xF9,
0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0x80, 0xF0, 0x1F, 0xE7, 0xF8, 0x7E, 0x02,
0x01, 0xC1, 0xE0, 0x20, 0x00, 0x07, 0xC7, 0xF9, 0xFF, 0xE1, 0xFF, 0xFF,
0xFF, 0x80, 0xF0, 0x1F, 0xE7, 0xF8, 0x7E, 0x08, 0x07, 0x03, 0xE1, 0xDC,
0x22, 0x00, 0x01, 0xF1, 0xFE, 0x7F, 0xF8, 0x7F, 0xFF, 0xFF, 0xE0, 0x3C,
0x07, 0xF9, 0xFE, 0x1F, 0x80, 0x3B, 0x8E, 0xE3, 0xB8, 0x00, 0x1F, 0x1F,
0xE7, 0xFF, 0x87, 0xFF, 0xFF, 0xFE, 0x03, 0xC0, 0x7F, 0x9F, 0xE1, 0xF8,
0x47, 0x1E, 0x20, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x11, 0xFC,
0x80, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x10, 0x71, 0xF7, 0x74,
0x40, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0xEF,
0xDF, 0xB8, 0x03, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E,
0x00, 0x0C, 0x07, 0xB0, 0x7C, 0x7E, 0x0B, 0x80, 0x73, 0xFD, 0xFF, 0xFF,
0xFC, 0x7E, 0x1F, 0x87, 0xE3, 0x9F, 0xE7, 0xF0, 0x78, 0x19, 0x0F, 0xE1,
0x30, 0x00, 0xFF, 0x3F, 0xEF, 0xFF, 0x8F, 0xE1, 0xF8, 0x7E, 0x1F, 0x87,
0xE1, 0xF8, 0x7E, 0x1C, 0x10, 0x0E, 0x01, 0xE0, 0x10, 0x00, 0x07, 0x87,
0xF9, 0xFE, 0xF3, 0xF8, 0x7E, 0x1F, 0x87, 0xF3, 0xDF, 0xE7, 0xF8, 0x78,
0x02, 0x01, 0xC1, 0xE0, 0x20, 0x00, 0x07, 0x87, 0xF9, 0xFE, 0xF3, 0xF8,
0x7E, 0x1F, 0x87, 0xF3, 0xDF, 0xE7, 0xF8, 0x78, 0x08, 0x07, 0x03, 0xE1,
0xDC, 0x22, 0x00, 0x01, 0xE1, 0xFE, 0x7F, 0xBC, 0xFE, 0x1F, 0x87, 0xE1,
0xFC, 0xF7, 0xF9, 0xFE, 0x1E, 0x00, 0x19, 0x0F, 0xE1, 0x30, 0x00, 0x1E,
0x1F, 0xE7, 0xFB, 0xCF, 0xE1, 0xF8, 0x7E, 0x1F, 0xCF, 0x7F, 0x9F, 0xE1,
0xE0, 0x77, 0x1D, 0xC7, 0x70, 0x00, 0x1E, 0x1F, 0xE7, 0xFB, 0xCF, 0xE1,
0xF8, 0x7E, 0x1F, 0xCF, 0x7F, 0x9F, 0xE1, 0xE0, 0x1C, 0x0E, 0x07, 0x00,
0x0F, 0xFF, 0xFF, 0xFE, 0x00, 0x1C, 0x0E, 0x07, 0x00, 0x00, 0x07, 0xB7,
0xF9, 0xFE, 0xF7, 0xF9, 0xFE, 0xDF, 0xE7, 0xFB, 0xDF, 0xE7, 0xFB, 0x78,
0x00, 0x00, 0x10, 0x0E, 0x01, 0xE0, 0x10, 0x00, 0x38, 0x7E, 0x1F, 0x87,
0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xF1, 0xFF, 0xF7, 0xFC, 0xFF, 0x02, 0x01,
0xC1, 0xE0, 0x20, 0x00, 0x38, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F,
0x87, 0xF1, 0xFF, 0xF7, 0xFC, 0xFF, 0x04, 0x03, 0x81, 0xF0, 0xEE, 0x11,
0x00, 0x0E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xFC, 0x7F,
0xFD, 0xFF, 0x3F, 0xC0, 0x77, 0x1D, 0xC7, 0x70, 0x00, 0xE1, 0xF8, 0x7E,
0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0xC7, 0xFF, 0xDF, 0xF3, 0xFC, 0x01,
0x00, 0x70, 0x3C, 0x02, 0x00, 0x01, 0xC1, 0xF8, 0x3B, 0x8E, 0x71, 0xCE,
0x38, 0xEE, 0x1D, 0xC3, 0xF8, 0x3E, 0x07, 0xC0, 0xF8, 0x1E, 0x1F, 0xC3,
0xF0, 0x7C, 0x00, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x3F, 0x8F, 0xFB,
0xFE, 0xE3, 0xF8, 0x7E, 0x1F, 0x87, 0xE3, 0xFF, 0xEF, 0xFB, 0xFC, 0xE0,
0x38, 0x0E, 0x03, 0x80, 0x3B, 0x87, 0x70, 0xEE, 0x00, 0x0E, 0x0F, 0xC1,
0xDC, 0x73, 0x8E, 0x71, 0xC7, 0x70, 0xEE, 0x1F, 0xC1, 0xF0, 0x3E, 0x07,
0xC0, 0xF0, 0xFE, 0x1F, 0x83, 0xE0, 0x00 };
const GFXglyph Ubuntu_Bold10pt8bGlyphs[] PROGMEM = {
{ 0, 1, 1, 5, 0, 0 }, // 0x20 ' ' U+0020
{ 1, 3, 14, 5, 1, -13 }, // 0x21 '!' U+0021
{ 7, 7, 6, 9, 1, -14 }, // 0x22 '"' U+0022
{ 13, 12, 14, 14, 1, -13 }, // 0x23 '#' U+0023
{ 34, 9, 17, 11, 1, -14 }, // 0x24 '$' U+0024
{ 54, 16, 14, 18, 1, -13 }, // 0x25 '%' U+0025
{ 82, 13, 14, 14, 1, -13 }, // 0x26 '&' U+0026
{ 105, 3, 6, 5, 1, -14 }, // 0x27 ''' U+0027
{ 108, 6, 20, 7, 1, -15 }, // 0x28 '(' U+0028
{ 123, 6, 20, 7, 0, -15 }, // 0x29 ')' U+0029
{ 138, 9, 8, 10, 1, -13 }, // 0x2a '*' U+002A
{ 147, 11, 11, 13, 1, -11 }, // 0x2b '+' U+002B
{ 163, 4, 6, 5, 0, -2 }, // 0x2c ',' U+002C
{ 166, 6, 3, 8, 1, -7 }, // 0x2d '-' U+002D
{ 169, 4, 4, 6, 1, -3 }, // 0x2e '.' U+002E
{ 171, 10, 20, 9, -1, -15 }, // 0x2f '/' U+002F
{ 196, 9, 14, 11, 1, -13 }, // 0x30 '0' U+0030
{ 212, 7, 14, 11, 1, -13 }, // 0x31 '1' U+0031
{ 225, 9, 14, 11, 1, -13 }, // 0x32 '2' U+0032
{ 241, 9, 14, 11, 1, -13 }, // 0x33 '3' U+0033
{ 257, 9, 14, 11, 1, -13 }, // 0x34 '4' U+0034
{ 273, 9, 14, 11, 1, -13 }, // 0x35 '5' U+0035
{ 289, 9, 14, 11, 1, -13 }, // 0x36 '6' U+0036
{ 305, 9, 14, 11, 1, -13 }, // 0x37 '7' U+0037
{ 321, 9, 14, 11, 1, -13 }, // 0x38 '8' U+0038
{ 337, 9, 14, 11, 1, -13 }, // 0x39 '9' U+0039
{ 353, 4, 11, 6, 1, -10 }, // 0x3a ':' U+003A
{ 359, 5, 14, 6, 0, -10 }, // 0x3b ';' U+003B
{ 368, 10, 9, 11, 1, -9 }, // 0x3c '<' U+003C
{ 380, 9, 8, 11, 1, -9 }, // 0x3d '=' U+003D
{ 389, 9, 9, 11, 1, -9 }, // 0x3e '>' U+003E
{ 400, 8, 16, 9, 0, -15 }, // 0x3f '?' U+003F
{ 416, 17, 17, 19, 1, -13 }, // 0x40 '@' U+0040
{ 453, 15, 14, 15, 0, -13 }, // 0x41 'A' U+0041
{ 480, 10, 14, 13, 2, -13 }, // 0x42 'B' U+0042
{ 498, 11, 14, 13, 1, -13 }, // 0x43 'C' U+0043
{ 518, 12, 14, 15, 2, -13 }, // 0x44 'D' U+0044
{ 539, 9, 14, 12, 2, -13 }, // 0x45 'E' U+0045
{ 555, 8, 14, 11, 2, -13 }, // 0x46 'F' U+0046
{ 569, 11, 14, 14, 1, -13 }, // 0x47 'G' U+0047
{ 589, 11, 14, 15, 2, -13 }, // 0x48 'H' U+0048
{ 609, 3, 14, 7, 2, -13 }, // 0x49 'I' U+0049
{ 615, 9, 14, 11, 0, -13 }, // 0x4a 'J' U+004A
{ 631, 12, 14, 14, 2, -13 }, // 0x4b 'K' U+004B
{ 652, 9, 14, 11, 2, -13 }, // 0x4c 'L' U+004C
{ 668, 15, 14, 17, 1, -13 }, // 0x4d 'M' U+004D
{ 695, 11, 14, 15, 2, -13 }, // 0x4e 'N' U+004E
{ 715, 14, 14, 16, 1, -13 }, // 0x4f 'O' U+004F
{ 740, 10, 14, 13, 2, -13 }, // 0x50 'P' U+0050
{ 758, 14, 17, 16, 1, -13 }, // 0x51 'Q' U+0051
{ 788, 11, 14, 13, 2, -13 }, // 0x52 'R' U+0052
{ 808, 10, 14, 12, 1, -13 }, // 0x53 'S' U+0053
{ 826, 11, 14, 11, 0, -13 }, // 0x54 'T' U+0054
{ 846, 11, 14, 15, 2, -13 }, // 0x55 'U' U+0055
{ 866, 15, 14, 15, 0, -13 }, // 0x56 'V' U+0056
{ 893, 19, 14, 19, 0, -13 }, // 0x57 'W' U+0057
{ 927, 14, 14, 14, 0, -13 }, // 0x58 'X' U+0058
{ 952, 13, 14, 13, 0, -13 }, // 0x59 'Y' U+0059
{ 975, 10, 14, 12, 1, -13 }, // 0x5a 'Z' U+005A
{ 993, 5, 20, 7, 2, -15 }, // 0x5b '[' U+005B
{ 1006, 10, 20, 9, -1, -15 }, // 0x5c '\' U+005C
{ 1031, 5, 20, 7, 0, -15 }, // 0x5d ']' U+005D
{ 1044, 11, 8, 11, 0, -13 }, // 0x5e '^' U+005E
{ 1055, 10, 2, 10, 0, 3 }, // 0x5f '_' U+005F
{ 1058, 5, 4, 6, 1, -15 }, // 0x60 '`' U+0060
{ 1061, 9, 11, 11, 1, -10 }, // 0x61 'a' U+0061
{ 1074, 10, 16, 12, 1, -15 }, // 0x62 'b' U+0062
{ 1094, 8, 11, 10, 1, -10 }, // 0x63 'c' U+0063
{ 1105, 10, 16, 12, 1, -15 }, // 0x64 'd' U+0064
{ 1125, 10, 11, 12, 1, -10 }, // 0x65 'e' U+0065
{ 1139, 8, 16, 8, 1, -15 }, // 0x66 'f' U+0066
{ 1155, 10, 15, 12, 1, -10 }, // 0x67 'g' U+0067
{ 1174, 10, 16, 12, 1, -15 }, // 0x68 'h' U+0068
{ 1194, 3, 16, 5, 1, -15 }, // 0x69 'i' U+0069
{ 1200, 6, 20, 5, -2, -15 }, // 0x6a 'j' U+006A
{ 1215, 11, 16, 12, 1, -15 }, // 0x6b 'k' U+006B
{ 1237, 5, 16, 6, 1, -15 }, // 0x6c 'l' U+006C
{ 1247, 15, 11, 17, 1, -10 }, // 0x6d 'm' U+006D
{ 1268, 10, 11, 12, 1, -10 }, // 0x6e 'n' U+006E
{ 1282, 10, 11, 12, 1, -10 }, // 0x6f 'o' U+006F
{ 1296, 10, 15, 12, 1, -10 }, // 0x70 'p' U+0070
{ 1315, 10, 15, 12, 1, -10 }, // 0x71 'q' U+0071
{ 1334, 7, 11, 8, 1, -10 }, // 0x72 'r' U+0072
{ 1344, 8, 11, 10, 1, -10 }, // 0x73 's' U+0073
{ 1355, 7, 14, 9, 1, -13 }, // 0x74 't' U+0074
{ 1368, 10, 11, 12, 1, -10 }, // 0x75 'u' U+0075
{ 1382, 11, 11, 11, 0, -10 }, // 0x76 'v' U+0076
{ 1398, 15, 11, 15, 0, -10 }, // 0x77 'w' U+0077
{ 1419, 11, 11, 11, 0, -10 }, // 0x78 'x' U+0078
{ 1435, 11, 15, 11, 0, -10 }, // 0x79 'y' U+0079
{ 1456, 8, 11, 10, 1, -10 }, // 0x7a 'z' U+007A
{ 1467, 7, 20, 8, 1, -15 }, // 0x7b '{' U+007B
{ 1485, 3, 20, 7, 2, -15 }, // 0x7c '|' U+007C
{ 1493, 7, 20, 8, 0, -15 }, // 0x7d '}' U+007D
{ 1511, 10, 5, 11, 1, -8 }, // 0x7e '~' U+007E
{ 1518, 8, 15, 10, 1, -14 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
{ 1533, 1, 1, 5, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
{ 1534, 3, 15, 5, 1, -10 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
{ 1540, 8, 16, 11, 1, -13 }, // 0x82 'CENT SIGN' U+00A2
{ 1556, 10, 14, 11, 0, -13 }, // 0x83 'POUND SIGN' U+00A3
{ 1574, 10, 10, 11, 1, -11 }, // 0x84 'CURRENCY SIGN' U+00A4
{ 1587, 11, 14, 11, 0, -13 }, // 0x85 'YEN SIGN' U+00A5
{ 1607, 3, 20, 6, 2, -15 }, // 0x86 'BROKEN BAR' U+00A6
{ 1615, 8, 18, 10, 1, -13 }, // 0x87 'SECTION SIGN' U+00A7
{ 1633, 7, 3, 11, 2, -14 }, // 0x88 'DIAERESIS' U+00A8
{ 1636, 14, 14, 16, 1, -13 }, // 0x89 'COPYRIGHT SIGN' U+00A9
{ 1661, 7, 8, 8, 0, -13 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
{ 1668, 10, 9, 12, 0, -9 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
{ 1680, 9, 8, 11, 1, -8 }, // 0x8c 'NOT SIGN' U+00AC
{ 1689, 6, 3, 8, 1, -7 }, // 0x8d 'SOFT HYPHEN' U+00AD
{ 1692, 14, 14, 16, 1, -13 }, // 0x8e 'REGISTERED SIGN' U+00AE
{ 1717, 6, 2, 8, 1, -13 }, // 0x8f 'MACRON' U+00AF
{ 1719, 6, 6, 6, 0, -15 }, // 0x90 'DEGREE SIGN' U+00B0
{ 1724, 11, 15, 13, 1, -14 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
{ 1745, 6, 8, 7, 0, -13 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
{ 1751, 6, 8, 7, 0, -13 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
{ 1757, 5, 4, 6, 0, -15 }, // 0x94 'ACUTE ACCENT' U+00B4
{ 1760, 10, 15, 12, 1, -10 }, // 0x95 'MICRO SIGN' U+00B5
{ 1779, 12, 18, 14, 1, -13 }, // 0x96 'PILCROW SIGN' U+00B6
{ 1806, 4, 4, 6, 1, -7 }, // 0x97 'MIDDLE DOT' U+00B7
{ 1808, 4, 4, 7, 1, 1 }, // 0x98 'CEDILLA' U+00B8
{ 1810, 4, 8, 7, 1, -13 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
{ 1814, 8, 8, 10, 1, -13 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
{ 1822, 10, 9, 12, 2, -9 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
{ 1834, 16, 14, 18, 1, -13 }, // 0x9c 'VULGAR FRACTION ONE QUARTER' U+00BC
{ 1862, 15, 14, 18, 1, -13 }, // 0x9d 'VULGAR FRACTION ONE HALF' U+00BD
{ 1889, 17, 14, 18, 0, -13 }, // 0x9e 'VULGAR FRACTION THREE QUARTERS' U+00BE
{ 1919, 8, 15, 9, 1, -10 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
{ 1934, 15, 19, 15, 0, -18 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
{ 1970, 15, 19, 15, 0, -18 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
{ 2006, 15, 20, 15, 0, -19 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
{ 2044, 15, 18, 15, 0, -17 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
{ 2078, 15, 18, 15, 0, -17 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
{ 2112, 15, 18, 15, 0, -17 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
{ 2146, 19, 14, 20, 0, -13 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
{ 2180, 11, 18, 13, 1, -13 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
{ 2205, 9, 19, 12, 2, -18 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
{ 2227, 9, 19, 12, 2, -18 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
{ 2249, 9, 20, 12, 2, -19 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
{ 2272, 9, 18, 12, 2, -17 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
{ 2293, 5, 19, 7, 1, -18 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
{ 2305, 5, 19, 7, 1, -18 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
{ 2317, 7, 20, 7, 0, -19 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
{ 2335, 7, 18, 7, 0, -17 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
{ 2351, 14, 14, 15, 0, -13 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
{ 2376, 11, 18, 15, 2, -17 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
{ 2401, 14, 19, 16, 1, -18 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
{ 2435, 14, 19, 16, 1, -18 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
{ 2469, 14, 20, 16, 1, -19 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
{ 2504, 14, 18, 16, 1, -17 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
{ 2536, 14, 18, 16, 1, -17 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
{ 2568, 9, 9, 11, 1, -10 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
{ 2579, 14, 16, 16, 1, -14 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
{ 2607, 11, 19, 15, 2, -18 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
{ 2634, 11, 19, 15, 2, -18 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
{ 2661, 11, 20, 15, 2, -19 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
{ 2689, 11, 18, 15, 2, -17 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
{ 2714, 13, 19, 13, 0, -18 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
{ 2745, 10, 14, 13, 2, -13 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
{ 2763, 11, 16, 13, 1, -15 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
{ 2785, 9, 16, 11, 1, -15 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
{ 2803, 9, 16, 11, 1, -15 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
{ 2821, 9, 17, 11, 1, -16 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
{ 2841, 9, 15, 11, 1, -14 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
{ 2858, 9, 15, 11, 1, -14 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
{ 2875, 9, 17, 11, 1, -16 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
{ 2895, 15, 11, 17, 1, -10 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
{ 2916, 8, 15, 10, 1, -10 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
{ 2931, 10, 16, 12, 1, -15 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
{ 2951, 10, 16, 12, 1, -15 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
{ 2971, 10, 17, 12, 1, -16 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
{ 2993, 10, 15, 12, 1, -14 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
{ 3012, 5, 16, 5, 0, -15 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
{ 3022, 5, 16, 5, 0, -15 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
{ 3032, 7, 17, 5, -1, -16 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
{ 3047, 7, 15, 5, -1, -14 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
{ 3061, 10, 16, 12, 1, -15 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
{ 3081, 10, 15, 12, 1, -14 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
{ 3100, 10, 16, 12, 1, -15 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
{ 3120, 10, 16, 12, 1, -15 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
{ 3140, 10, 17, 12, 1, -16 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
{ 3162, 10, 15, 12, 1, -14 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
{ 3181, 10, 15, 12, 1, -14 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
{ 3200, 9, 11, 11, 1, -10 }, // 0xd7 'DIVISION SIGN' U+00F7
{ 3213, 10, 13, 12, 1, -11 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
{ 3230, 10, 16, 12, 1, -15 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
{ 3250, 10, 16, 12, 1, -15 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
{ 3270, 10, 17, 12, 1, -16 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
{ 3292, 10, 15, 12, 1, -14 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
{ 3311, 11, 20, 11, 0, -15 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
{ 3339, 10, 20, 12, 1, -15 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
{ 3364, 11, 19, 11, 0, -14 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
const GFXfont Ubuntu_Bold10pt8b PROGMEM = {
(uint8_t *)Ubuntu_Bold10pt8bBitmaps,
(GFXglyph *)Ubuntu_Bold10pt8bGlyphs,
0x20, 0xDF, 23 };
// Approx. 4742 bytes

View File

@@ -1,611 +0,0 @@
const uint8_t Ubuntu_Bold12pt8bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0xFF, 0x60, 0xF7, 0xFB,
0xFD, 0xFE, 0xFF, 0x7F, 0xBF, 0xDE, 0x0F, 0x3C, 0x1E, 0x78, 0x3C, 0xF0,
0xF3, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x3C, 0x3E, 0xF8, 0x79,
0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x9E, 0x1E, 0x78, 0x3C, 0xF0,
0x79, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x01, 0xFC, 0x7F, 0xE7, 0xFE, 0xF0,
0x4F, 0x00, 0xF0, 0x0F, 0xF0, 0x7F, 0xC3, 0xFE, 0x07, 0xF0, 0x1F, 0x00,
0xF6, 0x0F, 0xFF, 0xEF, 0xFC, 0x7F, 0x80, 0xE0, 0x0E, 0x00, 0xE0, 0x3E,
0x0F, 0x07, 0xF0, 0xE0, 0xF7, 0x9E, 0x0E, 0x39, 0xC0, 0xE3, 0xBC, 0x0E,
0x3B, 0x80, 0xF7, 0xF8, 0x07, 0xF7, 0x00, 0x3E, 0xF7, 0xC0, 0x0E, 0xFE,
0x01, 0xFE, 0xF0, 0x1D, 0xC7, 0x03, 0xDC, 0x70, 0x39, 0xC7, 0x07, 0x9E,
0xF0, 0x70, 0xFE, 0x0F, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0xC0, 0x3F, 0xE0,
0x38, 0xE0, 0x38, 0xE0, 0x3D, 0xE0, 0x1F, 0xC0, 0x1F, 0x80, 0x3F, 0x9E,
0x7F, 0x9E, 0xF3, 0xDC, 0xF1, 0xFC, 0xF0, 0xF8, 0xF8, 0xF8, 0xFF, 0xFC,
0x7F, 0xFE, 0x1F, 0x9F, 0xFF, 0xFF, 0xFF, 0xF0, 0x08, 0x3C, 0xF1, 0xE7,
0x8F, 0x1E, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0x78, 0xF1,
0xE1, 0xE3, 0xC3, 0xC2, 0x00, 0x21, 0xE1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F,
0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x3C, 0x78, 0xF3, 0xC7, 0x9E,
0x08, 0x00, 0x0E, 0x01, 0xC1, 0x39, 0x7A, 0xFF, 0xFE, 0x1C, 0x06, 0xC1,
0xDC, 0x7B, 0xC2, 0x20, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F, 0xFF, 0xFF,
0xFF, 0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0x7B, 0xDE, 0xF7, 0xFB,
0xCC, 0xFF, 0xFF, 0xF8, 0x6F, 0xF6, 0x00, 0xF0, 0x1F, 0x01, 0xE0, 0x1E,
0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x78, 0x07, 0x80, 0x78, 0x0F, 0x00, 0xF0,
0x0F, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x3C, 0x03, 0xC0, 0x3C, 0x07, 0x80,
0x78, 0x0F, 0x80, 0xF0, 0x00, 0x0F, 0x03, 0xFC, 0x7F, 0xE7, 0x9E, 0x70,
0xEF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0,
0xE7, 0x9E, 0x7F, 0xE3, 0xFC, 0x0F, 0x00, 0x07, 0x1F, 0x7F, 0xFF, 0xEF,
0x4F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x1F, 0x07, 0xFC, 0xFF, 0xE6, 0x3E, 0x01, 0xE0, 0x1E, 0x03, 0xE0, 0x3C,
0x07, 0x80, 0xF8, 0x3F, 0x03, 0xE0, 0x7C, 0x0F, 0x80, 0xFF, 0xFF, 0xFF,
0xFF, 0xF0, 0x3E, 0x1F, 0xF3, 0xFF, 0x21, 0xE0, 0x3C, 0x07, 0x87, 0xE0,
0xF8, 0x1F, 0xC0, 0x78, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0xFF, 0xF7, 0xFC,
0x7F, 0x00, 0x03, 0xC0, 0x7C, 0x0F, 0xC0, 0xFC, 0x1F, 0xC3, 0xBC, 0x3B,
0xC7, 0x3C, 0x73, 0xCF, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x03,
0xC0, 0x3C, 0x03, 0xC0, 0x3F, 0xE3, 0xFE, 0x3F, 0xE3, 0x80, 0x38, 0x07,
0x80, 0x7F, 0x07, 0xFC, 0x7F, 0xE0, 0x3F, 0x00, 0xF0, 0x0F, 0x00, 0xF0,
0x1F, 0xFF, 0xEF, 0xFC, 0x7F, 0x00, 0x01, 0xE0, 0xFE, 0x1F, 0xE3, 0xF0,
0x7C, 0x07, 0x80, 0xFF, 0x8F, 0xFE, 0xFF, 0xEF, 0x1F, 0xF0, 0xFF, 0x0F,
0xF0, 0xF7, 0x9F, 0x7F, 0xE3, 0xFC, 0x1F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0x1E, 0x03, 0xE0, 0x7C, 0x07, 0x80, 0x78, 0x0F, 0x00, 0xF0, 0x1F,
0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x1F, 0x83,
0xFE, 0x7F, 0xEF, 0x9F, 0xF0, 0xFF, 0x0F, 0xF9, 0xF7, 0xFE, 0x3F, 0xC7,
0xFE, 0xF9, 0xFF, 0x0F, 0xF0, 0xFF, 0x8F, 0xFF, 0xE7, 0xFE, 0x1F, 0x80,
0x1F, 0x83, 0xFC, 0x7F, 0xEF, 0x9E, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x8F,
0x7F, 0xF7, 0xFF, 0x1F, 0xF0, 0x1E, 0x03, 0xE0, 0x7C, 0x7F, 0x87, 0xF0,
0x78, 0x00, 0x6F, 0xF6, 0x00, 0x00, 0x06, 0xFF, 0x60, 0x33, 0xDE, 0x60,
0x00, 0x00, 0x03, 0xDE, 0xF7, 0xBF, 0xDE, 0x60, 0x00, 0x60, 0x3E, 0x1F,
0xFF, 0xFF, 0xFF, 0x8F, 0x00, 0xFF, 0x8F, 0xFF, 0x1F, 0xF0, 0x3E, 0x00,
0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF,
0x60, 0x07, 0xC0, 0xFF, 0x8F, 0xFF, 0x1F, 0xF0, 0x0F, 0x1F, 0xFF, 0xFF,
0xFF, 0x87, 0xC0, 0x60, 0x00, 0x3E, 0x3F, 0xEF, 0xF9, 0x0F, 0x03, 0xC0,
0xF0, 0x7C, 0x1E, 0x0F, 0x83, 0xC1, 0xE0, 0x78, 0x1C, 0x07, 0x00, 0x00,
0x30, 0x1E, 0x07, 0x80, 0xC0, 0x01, 0xFC, 0x00, 0x3F, 0xFC, 0x03, 0xFF,
0xF0, 0x7E, 0x07, 0xC3, 0xC0, 0x0F, 0x3C, 0x7E, 0x39, 0xC7, 0xF8, 0xFE,
0x7F, 0xC7, 0xE7, 0x8E, 0x3F, 0x38, 0x71, 0xF9, 0xC3, 0x8F, 0xCE, 0x1C,
0x7E, 0x78, 0xE7, 0x71, 0xFF, 0xF9, 0xCF, 0xFF, 0x8F, 0x1F, 0xF8, 0x3C,
0x00, 0x01, 0xF8, 0x00, 0x07, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x1F, 0xE0,
0x00, 0x03, 0xE0, 0x01, 0xF0, 0x01, 0xFC, 0x00, 0xFE, 0x00, 0x77, 0x00,
0x7B, 0xC0, 0x3D, 0xE0, 0x3C, 0x78, 0x1E, 0x3C, 0x0F, 0x1E, 0x0F, 0xFF,
0x87, 0xFF, 0xC3, 0xFF, 0xE3, 0xC0, 0x79, 0xE0, 0x3D, 0xF0, 0x1E, 0xF0,
0x07, 0x80, 0xFF, 0x87, 0xFF, 0x3F, 0xF9, 0xE3, 0xEF, 0x0F, 0x78, 0x7B,
0xC7, 0xDF, 0xFC, 0xFF, 0xE7, 0xFF, 0xBC, 0x3F, 0xE0, 0xFF, 0x07, 0xF8,
0x7F, 0xFF, 0xDF, 0xFC, 0xFF, 0xC0, 0x07, 0xF0, 0x7F, 0xF3, 0xFF, 0xDF,
0x82, 0x78, 0x03, 0xE0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F,
0x00, 0x3E, 0x00, 0x78, 0x01, 0xF0, 0x23, 0xFF, 0xC7, 0xFF, 0x07, 0xF0,
0xFF, 0x81, 0xFF, 0xE3, 0xFF, 0xE7, 0x87, 0xEF, 0x03, 0xDE, 0x07, 0xFC,
0x07, 0xF8, 0x0F, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x81, 0xFF, 0x03,
0xDE, 0x1F, 0xBF, 0xFE, 0x7F, 0xF0, 0xFF, 0x80, 0xFF, 0xEF, 0xFE, 0xFF,
0xEF, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0,
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF,
0xFF, 0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xFE, 0xFF, 0xDF, 0xFB,
0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x00, 0x07, 0xF0,
0x7F, 0xF3, 0xFF, 0xDF, 0x02, 0x78, 0x03, 0xE0, 0x0F, 0x00, 0x3C, 0x00,
0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFE, 0x0F, 0x78, 0x3D, 0xF0, 0xF3, 0xFF,
0xC7, 0xFF, 0x07, 0xF8, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0,
0x3F, 0xC0, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFC,
0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3C, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xE0, 0x3C, 0x07, 0x80,
0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0,
0x1E, 0x87, 0xDF, 0xF7, 0xFE, 0x3F, 0x00, 0xF0, 0xFF, 0xC7, 0xEF, 0x1F,
0x3C, 0xF8, 0xF7, 0xC3, 0xFE, 0x0F, 0xF0, 0x3F, 0x80, 0xFF, 0x03, 0xFC,
0x0F, 0x78, 0x3D, 0xF0, 0xF3, 0xE3, 0xC7, 0x8F, 0x1F, 0x3C, 0x3E, 0xF0,
0x7C, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xF0, 0x7C, 0x03, 0xCF, 0x80, 0xF9, 0xF0, 0x1F, 0x3F, 0x07,
0xE7, 0xE0, 0xFC, 0xFE, 0x3F, 0xBD, 0xC7, 0x7F, 0xBD, 0xEF, 0xF3, 0xB9,
0xFE, 0x77, 0x3F, 0xCF, 0xE7, 0xF8, 0xF8, 0xFF, 0x1F, 0x1F, 0xE1, 0xC3,
0xFC, 0x38, 0x7F, 0x80, 0x0F, 0xF0, 0x01, 0xE0, 0xF0, 0x3F, 0xE0, 0xFF,
0x83, 0xFF, 0x0F, 0xFE, 0x3F, 0xF8, 0xFF, 0x73, 0xFD, 0xCF, 0xF3, 0xBF,
0xCF, 0xFF, 0x1F, 0xFC, 0x3F, 0xF0, 0xFF, 0xC1, 0xFF, 0x07, 0xFC, 0x0F,
0xF0, 0x3C, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x8F, 0x83, 0xE7, 0x80,
0xF7, 0xC0, 0x7F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC,
0x01, 0xFF, 0x01, 0xF7, 0x80, 0xF3, 0xE0, 0xF8, 0xFF, 0xF8, 0x3F, 0xF8,
0x07, 0xF0, 0x00, 0xFF, 0x0F, 0xFC, 0xFF, 0xEF, 0x1F, 0xF0, 0xFF, 0x0F,
0xF0, 0xFF, 0x1F, 0xFF, 0xEF, 0xFC, 0xFF, 0x8F, 0x00, 0xF0, 0x0F, 0x00,
0xF0, 0x0F, 0x00, 0xF0, 0x00, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x8F,
0x83, 0xE7, 0x80, 0xF7, 0xC0, 0x7F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07,
0xF8, 0x03, 0xFC, 0x01, 0xFF, 0x01, 0xF7, 0x80, 0xF3, 0xE0, 0xF8, 0xFF,
0xF8, 0x3F, 0xF8, 0x07, 0xF0, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x1F, 0xE0,
0x07, 0xF0, 0x00, 0xF0, 0xFF, 0x83, 0xFF, 0x8F, 0xFF, 0x3C, 0x3E, 0xF0,
0x7B, 0xC1, 0xEF, 0x07, 0xBC, 0x3E, 0xFF, 0xF3, 0xFF, 0x8F, 0xFC, 0x3C,
0xF8, 0xF1, 0xF3, 0xC3, 0xCF, 0x0F, 0xBC, 0x1E, 0xF0, 0x7C, 0x1F, 0x87,
0xFE, 0x7F, 0xCF, 0x04, 0xF0, 0x0F, 0x00, 0xFC, 0x07, 0xF8, 0x3F, 0xC0,
0xFE, 0x01, 0xF0, 0x0F, 0x00, 0xF4, 0x1F, 0xFF, 0xEF, 0xFE, 0x3F, 0x80,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78,
0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E,
0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0,
0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F,
0xE0, 0xFF, 0x07, 0xBC, 0x79, 0xFF, 0xC7, 0xFC, 0x0F, 0x80, 0xF0, 0x07,
0xFC, 0x07, 0x9E, 0x03, 0xCF, 0x01, 0xE3, 0xC1, 0xE1, 0xE0, 0xF0, 0xF0,
0x78, 0x3C, 0x78, 0x1E, 0x3C, 0x0F, 0x1E, 0x03, 0xDE, 0x01, 0xEF, 0x00,
0xF7, 0x80, 0x3F, 0x80, 0x1F, 0xC0, 0x0F, 0xE0, 0x03, 0xE0, 0x00, 0xF0,
0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xE0, 0xE0, 0xFB, 0xC3, 0xE1, 0xE7, 0x87,
0xC3, 0xCF, 0x0F, 0x87, 0x9E, 0x1F, 0x8F, 0x3C, 0x77, 0x3E, 0x7C, 0xEE,
0x7C, 0x7B, 0xDE, 0xF0, 0xF7, 0x1D, 0xE1, 0xEE, 0x3B, 0xC3, 0xFC, 0x7F,
0x83, 0xF0, 0x7E, 0x07, 0xE0, 0xFC, 0x0F, 0xC1, 0xF8, 0x1F, 0x01, 0xF0,
0xF8, 0x1F, 0x7C, 0x3E, 0x3C, 0x3C, 0x3E, 0x7C, 0x1F, 0xF8, 0x0F, 0xF0,
0x0F, 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x07, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0,
0x1F, 0xF8, 0x3E, 0x7C, 0x3C, 0x3C, 0x7C, 0x3E, 0xF8, 0x1F, 0xF8, 0x1F,
0x78, 0x1E, 0x7C, 0x3E, 0x3C, 0x3C, 0x3E, 0x7C, 0x1F, 0xF8, 0x0F, 0xF0,
0x0F, 0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
0xFE, 0x03, 0xE0, 0x1E, 0x01, 0xF0, 0x1F, 0x00, 0xF0, 0x0F, 0x80, 0xF8,
0x07, 0x80, 0x7C, 0x07, 0xC0, 0x3E, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
0xFF, 0xFF, 0xFF, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E,
0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0xFF, 0xFF, 0x80, 0xF0, 0x07, 0x80,
0x78, 0x07, 0x80, 0x3C, 0x03, 0xC0, 0x3C, 0x01, 0xE0, 0x1E, 0x01, 0xE0,
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0x78, 0x07, 0x80, 0x78, 0x03, 0xC0, 0x3C,
0x03, 0xC0, 0x1E, 0x01, 0xE0, 0x1E, 0x00, 0xF0, 0xFF, 0xFF, 0xF8, 0xF1,
0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C,
0x78, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0x00, 0x7C, 0x03, 0xE0, 0x3F, 0x83,
0xDE, 0x1E, 0xF1, 0xE3, 0xCE, 0x0E, 0xF0, 0x79, 0x01, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xF0, 0x23, 0xC7, 0x8F, 0x08, 0x7F, 0x1F, 0xE7, 0xFC, 0x0F,
0x03, 0xCF, 0xF7, 0xFF, 0xCF, 0xF3, 0xFC, 0xFF, 0xFD, 0xFF, 0x3F, 0x80,
0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0x8F, 0xFC,
0xFF, 0xEF, 0x1F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x1E,
0xFF, 0xEF, 0xFC, 0x7F, 0x00, 0x0F, 0xCF, 0xF7, 0xFD, 0xE0, 0xF0, 0x3C,
0x0F, 0x03, 0xC0, 0xF0, 0x1E, 0x17, 0xFC, 0xFF, 0x1F, 0x80, 0x00, 0xF0,
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x1F, 0xF3, 0xFF, 0x7F, 0xFF,
0x8F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xF7, 0x8F, 0x7F, 0xF3,
0xFF, 0x0F, 0xE0, 0x0F, 0x83, 0xFC, 0x7F, 0xE7, 0x9E, 0xF0, 0xFF, 0x0F,
0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x82, 0x7F, 0xE3, 0xFE, 0x0F, 0xC0, 0x1F,
0x3F, 0x9F, 0xDF, 0x0F, 0x07, 0x83, 0xFD, 0xFE, 0xFF, 0x78, 0x3C, 0x1E,
0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x00, 0x1F, 0xC7, 0xFD,
0xFF, 0xFC, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF9, 0xEF, 0xFD, 0xFF,
0x8F, 0xF0, 0x1E, 0x87, 0xDF, 0xF3, 0xFE, 0x7F, 0x00, 0xF0, 0x1E, 0x03,
0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3F, 0xE7, 0xFE, 0xFF, 0xDE, 0x7F, 0xC7,
0xF8, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7, 0x80,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1E, 0x3C,
0x78, 0xF0, 0x00, 0x07, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F,
0x1E, 0x3C, 0x78, 0xFF, 0xFF, 0xBE, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
0x00, 0xF0, 0x0F, 0x00, 0xF1, 0xFF, 0x3E, 0xF7, 0xCF, 0xF8, 0xFF, 0x0F,
0xE0, 0xFF, 0x0F, 0xF8, 0xF7, 0x8F, 0x7C, 0xF3, 0xEF, 0x1E, 0xF1, 0xF0,
0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3E,
0xFD, 0xF3, 0xC0, 0x7F, 0x3F, 0x3F, 0xFF, 0xEF, 0xFF, 0xFB, 0xCF, 0x9F,
0xF1, 0xE3, 0xFC, 0x78, 0xFF, 0x1E, 0x3F, 0xC7, 0x8F, 0xF1, 0xE3, 0xFC,
0x78, 0xFF, 0x1E, 0x3F, 0xC7, 0x8F, 0xF1, 0xE3, 0xC0, 0x7F, 0x1F, 0xFB,
0xFF, 0x79, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7,
0xF8, 0xFF, 0x1E, 0x0F, 0x81, 0xFF, 0x1F, 0xFC, 0xF1, 0xEF, 0x07, 0xF8,
0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7B, 0xC7, 0x9F, 0xFC, 0x7F, 0xC0, 0xF8,
0x00, 0x7F, 0x0F, 0xFC, 0xFF, 0xEF, 0x1E, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF,
0x0F, 0xF0, 0xFF, 0x1F, 0xFF, 0xEF, 0xFC, 0xFF, 0x8F, 0x00, 0xF0, 0x0F,
0x00, 0xF0, 0x00, 0x0F, 0xF1, 0xFF, 0xDF, 0xFE, 0xF0, 0xFF, 0x87, 0xF8,
0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC3, 0xDF, 0xFE, 0x7F, 0xF1, 0xFF,
0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x3F, 0xFF, 0xFF, 0xFE, 0x0F,
0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x00, 0x1F, 0x9F,
0xEF, 0xFB, 0xC0, 0xF0, 0x3F, 0xE7, 0xFC, 0xFF, 0x03, 0xE0, 0xFF, 0xFF,
0xFE, 0xFE, 0x00, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0xF7, 0xFB, 0xFD, 0xE0,
0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xC3, 0xFC, 0xFE, 0x3F, 0x00, 0xF1,
0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xFF,
0x3D, 0xFF, 0xBF, 0xF1, 0xFC, 0xF0, 0x7F, 0xC7, 0xDE, 0x3C, 0xF1, 0xE7,
0x8F, 0x1E, 0xF0, 0xF7, 0x87, 0xBC, 0x1D, 0xC0, 0xFE, 0x07, 0xF0, 0x1F,
0x00, 0xF8, 0x00, 0xF0, 0xE1, 0xFE, 0x1C, 0x3D, 0xC7, 0xC7, 0x3C, 0xF9,
0xE7, 0x9F, 0x3C, 0xF7, 0xE7, 0x0E, 0xEE, 0xE1, 0xDD, 0xDC, 0x3F, 0x3F,
0x83, 0xE3, 0xE0, 0x7C, 0x7C, 0x0F, 0x07, 0x80, 0xE0, 0xE0, 0xF8, 0xFB,
0xC7, 0x8F, 0x78, 0x7B, 0xC1, 0xFC, 0x07, 0xC0, 0x1C, 0x01, 0xF0, 0x1F,
0xC1, 0xEF, 0x0F, 0x78, 0xFB, 0xEF, 0x8F, 0x80, 0xF0, 0x7F, 0xC7, 0xDE,
0x3C, 0xF1, 0xE7, 0x8F, 0x1E, 0xF0, 0xF7, 0x87, 0xBC, 0x1D, 0xC0, 0xFE,
0x07, 0xF0, 0x1F, 0x00, 0xF8, 0x0F, 0x83, 0xFC, 0x1F, 0xC0, 0xFC, 0x00,
0xFF, 0xFF, 0xFF, 0xFC, 0x3E, 0x0F, 0x87, 0xC3, 0xE0, 0xF8, 0x7C, 0x1F,
0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x0F, 0x1F, 0x3F, 0x3C, 0x3C, 0x3C, 0x3C,
0x3C, 0x3C, 0x7C, 0xF8, 0xF0, 0xF8, 0x7C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
0x3C, 0x3F, 0x1F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF8, 0xF0, 0xF8, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3E, 0x1F,
0x0F, 0x1F, 0x3E, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xF8, 0xF0,
0x38, 0x27, 0xE7, 0xFF, 0xEE, 0x7E, 0x41, 0xC0, 0xFF, 0xE0, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0x00, 0x6F, 0xF6, 0x0F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x00, 0xE0, 0x1C, 0x07, 0xF3, 0xFE,
0xFF, 0x9E, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x3C, 0x17, 0xFE, 0x7F,
0xC3, 0xF8, 0x38, 0x07, 0x00, 0xE0, 0x07, 0xC3, 0xFC, 0x7F, 0x1F, 0x03,
0xC0, 0x78, 0x0F, 0x07, 0xFC, 0xFF, 0x9F, 0xF0, 0xF0, 0x1E, 0x03, 0xC0,
0x78, 0x0F, 0xFB, 0xFF, 0x7F, 0xE0, 0x60, 0xDF, 0xFF, 0xFF, 0xBF, 0xE7,
0x1C, 0xE3, 0x9C, 0x73, 0xFE, 0xFF, 0xEF, 0xF9, 0x83, 0x00, 0xF8, 0x7D,
0xE1, 0xE7, 0x87, 0x8F, 0x3C, 0x3C, 0xF0, 0x7F, 0x81, 0xFE, 0x03, 0xF0,
0x7F, 0xF9, 0xFF, 0xE0, 0x78, 0x01, 0xE0, 0x7F, 0xF9, 0xFF, 0xE0, 0x78,
0x01, 0xE0, 0x07, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF,
0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0x9F, 0xFF, 0xFF, 0xC2, 0xF0, 0x3F, 0x07,
0xF1, 0xFE, 0xF7, 0xFC, 0xFF, 0x3F, 0xCF, 0xFB, 0xDF, 0xE3, 0xF8, 0x3F,
0x03, 0xD0, 0xFF, 0xFF, 0xFE, 0x7F, 0x00, 0x61, 0xBC, 0xFF, 0x3D, 0x86,
0x07, 0xF0, 0x0F, 0xFC, 0x0F, 0x07, 0x8E, 0x00, 0xE6, 0x3E, 0x37, 0x3F,
0x9F, 0x3C, 0x07, 0x9C, 0x03, 0xCE, 0x01, 0xE7, 0x00, 0xF3, 0xC0, 0x7C,
0xFE, 0x76, 0x3E, 0x33, 0x80, 0x38, 0xF0, 0x78, 0x3F, 0xF0, 0x03, 0xF0,
0x00, 0x7E, 0x7F, 0x07, 0x1F, 0x7F, 0xF7, 0xE7, 0xFF, 0x7F, 0x18, 0x61,
0xC7, 0x38, 0xE7, 0x9E, 0x71, 0xCF, 0x3C, 0x71, 0xC7, 0x9E, 0x38, 0xE1,
0xC7, 0x18, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x00, 0x70, 0x07,
0x00, 0x70, 0x07, 0x00, 0x70, 0xFF, 0xFF, 0xF8, 0x07, 0xF0, 0x0F, 0xFC,
0x0F, 0x07, 0x8E, 0x00, 0xE6, 0x7E, 0x37, 0x3F, 0xDF, 0x18, 0x67, 0x8C,
0x33, 0xC7, 0xF9, 0xE3, 0xF8, 0xF1, 0x8C, 0x7C, 0xC3, 0x76, 0x61, 0xB3,
0x80, 0x38, 0xF0, 0x78, 0x3F, 0xF0, 0x03, 0xF0, 0x00, 0xFF, 0xFF, 0x38,
0xFB, 0x1E, 0x3C, 0x6F, 0x8E, 0x00, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F,
0xFF, 0xFF, 0xFF, 0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0x0F, 0xFF,
0xFF, 0xFF, 0xF8, 0x3E, 0xFF, 0x47, 0x07, 0x0F, 0x3E, 0x78, 0xF0, 0xFF,
0xFF, 0x7C, 0xFE, 0x0E, 0x0E, 0x3C, 0x3F, 0x07, 0x07, 0xFF, 0xFC, 0x10,
0xF7, 0xBC, 0x40, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1F, 0xE3, 0xFC,
0x7F, 0x8F, 0xF1, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFD, 0xE0, 0x3C, 0x07,
0x80, 0xF0, 0x00, 0x07, 0xF0, 0xFF, 0xF7, 0xFF, 0xFF, 0xE7, 0xFF, 0x9F,
0xFE, 0x7F, 0xF9, 0xFF, 0xE7, 0x7F, 0x9C, 0xFE, 0x70, 0xF9, 0xC1, 0xE7,
0x07, 0x9C, 0x1E, 0x70, 0x79, 0xC1, 0xE7, 0x07, 0x9C, 0x1E, 0x70, 0x79,
0xC1, 0xE7, 0x07, 0x9C, 0x6F, 0xF6, 0x30, 0xE1, 0xBE, 0xF8, 0x1D, 0xFF,
0xD7, 0x1C, 0x71, 0xC7, 0x1C, 0x70, 0x3E, 0x3F, 0xBD, 0xDC, 0x7E, 0x3F,
0x1F, 0x8F, 0xEF, 0x7F, 0x1F, 0x00, 0x61, 0x8F, 0x3C, 0x71, 0xC7, 0x9E,
0x38, 0xE3, 0xCF, 0x38, 0xE7, 0x9E, 0x71, 0xCF, 0x3C, 0x61, 0x80, 0x1C,
0x0F, 0x07, 0xC0, 0xE0, 0xFC, 0x1E, 0x05, 0xC1, 0xC0, 0x1C, 0x3C, 0x01,
0xC3, 0x80, 0x1C, 0x78, 0x01, 0xC7, 0x1E, 0x1C, 0xF3, 0xE1, 0xCE, 0x3E,
0x01, 0xE7, 0xE0, 0x1C, 0xEE, 0x03, 0xDC, 0xE0, 0x39, 0xFF, 0x07, 0x9F,
0xF0, 0x70, 0x0E, 0x0F, 0x00, 0xE0, 0x1C, 0x1E, 0x0F, 0x83, 0x83, 0xF0,
0xF0, 0x2E, 0x1C, 0x01, 0xC7, 0x80, 0x38, 0xE0, 0x07, 0x3C, 0x00, 0xE7,
0x3E, 0x1D, 0xFF, 0xE3, 0xB9, 0x1C, 0x0F, 0x03, 0x81, 0xC0, 0xF0, 0x78,
0x7C, 0x0E, 0x1E, 0x03, 0xC7, 0x80, 0x70, 0xFF, 0x1E, 0x1F, 0xE0, 0x7C,
0x07, 0x87, 0xF0, 0x38, 0x03, 0x83, 0xC0, 0x1C, 0x1C, 0x03, 0xC1, 0xE0,
0x1F, 0x8E, 0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x1E, 0xFF, 0x79, 0xF7, 0xE3,
0x8F, 0x80, 0x3C, 0xFC, 0x01, 0xCE, 0xE0, 0x1E, 0xE7, 0x00, 0xE7, 0xFC,
0x0F, 0x3F, 0xE0, 0x70, 0x0E, 0x07, 0x80, 0x70, 0x0C, 0x07, 0x81, 0xE0,
0x30, 0x00, 0x03, 0x80, 0xE0, 0x78, 0x3C, 0x1F, 0x07, 0x83, 0xC0, 0xF0,
0x3C, 0x2F, 0xFD, 0xFF, 0x3F, 0x00, 0x01, 0x00, 0x03, 0xC0, 0x00, 0xF0,
0x00, 0x3C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x07,
0xF0, 0x03, 0xF8, 0x01, 0xDC, 0x01, 0xEF, 0x00, 0xF7, 0x80, 0xF1, 0xE0,
0x78, 0xF0, 0x3C, 0x78, 0x3F, 0xFE, 0x1F, 0xFF, 0x0F, 0xFF, 0x8F, 0x01,
0xE7, 0x80, 0xF7, 0xC0, 0x7B, 0xC0, 0x1E, 0x00, 0x80, 0x00, 0xF0, 0x00,
0xF0, 0x00, 0xF0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x07, 0xC0,
0x07, 0xF0, 0x03, 0xF8, 0x01, 0xDC, 0x01, 0xEF, 0x00, 0xF7, 0x80, 0xF1,
0xE0, 0x78, 0xF0, 0x3C, 0x78, 0x3F, 0xFE, 0x1F, 0xFF, 0x0F, 0xFF, 0x8F,
0x01, 0xE7, 0x80, 0xF7, 0xC0, 0x7B, 0xC0, 0x1E, 0x00, 0x80, 0x00, 0xE0,
0x00, 0xF8, 0x00, 0xEE, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x07,
0xC0, 0x07, 0xF0, 0x03, 0xF8, 0x01, 0xDC, 0x01, 0xEF, 0x00, 0xF7, 0x80,
0xF1, 0xE0, 0x78, 0xF0, 0x3C, 0x78, 0x3F, 0xFE, 0x1F, 0xFF, 0x0F, 0xFF,
0x8F, 0x01, 0xE7, 0x80, 0xF7, 0xC0, 0x7B, 0xC0, 0x1E, 0x03, 0x10, 0x03,
0xFC, 0x03, 0xFC, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80,
0x07, 0xC0, 0x07, 0xF0, 0x03, 0xF8, 0x01, 0xDC, 0x01, 0xEF, 0x00, 0xF7,
0x80, 0xF1, 0xE0, 0x78, 0xF0, 0x3C, 0x78, 0x3F, 0xFE, 0x1F, 0xFF, 0x0F,
0xFF, 0x8F, 0x01, 0xE7, 0x80, 0xF7, 0xC0, 0x7B, 0xC0, 0x1E, 0x0C, 0x30,
0x0F, 0x3C, 0x07, 0x9E, 0x01, 0x86, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x0F,
0x80, 0x0F, 0xE0, 0x07, 0xF0, 0x03, 0xB8, 0x03, 0xDE, 0x01, 0xEF, 0x01,
0xE3, 0xC0, 0xF1, 0xE0, 0x78, 0xF0, 0x7F, 0xFC, 0x3F, 0xFE, 0x1F, 0xFF,
0x1E, 0x03, 0xCF, 0x01, 0xEF, 0x80, 0xF7, 0x80, 0x3C, 0x03, 0xE0, 0x03,
0xF8, 0x01, 0x8C, 0x00, 0xC6, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80,
0x0F, 0xE0, 0x07, 0x70, 0x07, 0xB8, 0x03, 0xDE, 0x01, 0xEF, 0x01, 0xE3,
0xC0, 0xF1, 0xE0, 0x78, 0xF0, 0x7F, 0xFC, 0x3F, 0xFE, 0x3F, 0xFF, 0x1E,
0x03, 0xCF, 0x01, 0xEF, 0x80, 0xF7, 0x80, 0x3C, 0x00, 0x7F, 0xFC, 0x01,
0xFF, 0xF8, 0x03, 0xFF, 0xF0, 0x0F, 0xF8, 0x00, 0x1E, 0xF0, 0x00, 0x7D,
0xE0, 0x00, 0xF3, 0xC0, 0x03, 0xE7, 0xFE, 0x07, 0x8F, 0xFC, 0x1F, 0x1F,
0xF8, 0x7F, 0xFC, 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0xF0, 0x07, 0x81, 0xE0,
0x1F, 0x03, 0xFF, 0xBC, 0x07, 0xFF, 0xF8, 0x0F, 0xFE, 0x07, 0xF0, 0x7F,
0xF3, 0xFF, 0xDF, 0x82, 0x78, 0x03, 0xE0, 0x0F, 0x00, 0x3C, 0x00, 0xF0,
0x03, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0x78, 0x01, 0xF0, 0x23, 0xFF, 0xC7,
0xFF, 0x03, 0xF8, 0x07, 0x00, 0x1E, 0x00, 0x38, 0x03, 0xE0, 0x0F, 0x00,
0x04, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x01, 0x00, 0x00, 0xFF, 0xEF, 0xFE,
0xFF, 0xEF, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE,
0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x02,
0x00, 0x78, 0x0F, 0x01, 0xE0, 0x08, 0x00, 0x00, 0xFF, 0xEF, 0xFE, 0xFF,
0xEF, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0,
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x04, 0x00,
0xE0, 0x1F, 0x03, 0xB8, 0x11, 0x00, 0x00, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF,
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F,
0x00, 0xF0, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x30, 0xC7, 0x9E,
0x79, 0xE3, 0x0C, 0x00, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F, 0x00,
0xF0, 0x0F, 0x00, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF, 0x00, 0xF0, 0x0F, 0x00,
0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x23, 0xC7, 0x8F, 0x08, 0x07, 0x9E,
0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x80,
0x10, 0xF7, 0xBC, 0x40, 0x07, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E,
0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x80, 0x10, 0x71, 0xF7, 0x74, 0x40, 0x1E,
0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7,
0x8F, 0x1E, 0x00, 0x61, 0xBC, 0xFF, 0x3D, 0x86, 0x00, 0x07, 0x81, 0xE0,
0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E,
0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x80, 0x3F, 0xE0, 0x1F, 0xFE, 0x0F,
0xFF, 0x87, 0x87, 0xE3, 0xC0, 0xF1, 0xE0, 0x7C, 0xF0, 0x1F, 0xFF, 0x0F,
0xFF, 0x87, 0xFF, 0xC3, 0xCF, 0x01, 0xE7, 0x81, 0xF3, 0xC0, 0xF1, 0xE1,
0xF8, 0xFF, 0xF8, 0x7F, 0xF0, 0x3F, 0xE0, 0x00, 0x06, 0x20, 0x3F, 0xC1,
0xFE, 0x02, 0x30, 0x00, 0x00, 0x00, 0x0F, 0x03, 0xFE, 0x0F, 0xF8, 0x3F,
0xF0, 0xFF, 0xE3, 0xFF, 0x8F, 0xF7, 0x3F, 0xDC, 0xFF, 0x3B, 0xFC, 0xFF,
0xF1, 0xFF, 0xC3, 0xFF, 0x0F, 0xFC, 0x1F, 0xF0, 0x7F, 0xC0, 0xFF, 0x03,
0xC0, 0x01, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x04, 0x00,
0x00, 0x00, 0x1F, 0xC0, 0x3F, 0xF8, 0x3F, 0xFE, 0x3E, 0x0F, 0x9E, 0x03,
0xDF, 0x01, 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0,
0x07, 0xFC, 0x07, 0xDE, 0x03, 0xCF, 0x83, 0xE3, 0xFF, 0xE0, 0xFF, 0xE0,
0x1F, 0xC0, 0x00, 0x40, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x10,
0x00, 0x00, 0x00, 0x1F, 0xC0, 0x3F, 0xF8, 0x3F, 0xFE, 0x3E, 0x0F, 0x9E,
0x03, 0xDF, 0x01, 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F,
0xF0, 0x07, 0xFC, 0x07, 0xDE, 0x03, 0xCF, 0x83, 0xE3, 0xFF, 0xE0, 0xFF,
0xE0, 0x1F, 0xC0, 0x00, 0x80, 0x00, 0xE0, 0x00, 0xF8, 0x00, 0xEE, 0x00,
0x22, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x3F, 0xF8, 0x3F, 0xFE, 0x3E, 0x0F,
0x9E, 0x03, 0xDF, 0x01, 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0,
0x0F, 0xF0, 0x07, 0xFC, 0x07, 0xDE, 0x03, 0xCF, 0x83, 0xE3, 0xFF, 0xE0,
0xFF, 0xE0, 0x1F, 0xC0, 0x03, 0x10, 0x03, 0xFC, 0x03, 0xFC, 0x00, 0x8C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x3F, 0xF8, 0x3F, 0xFE, 0x3E,
0x0F, 0x9E, 0x03, 0xDF, 0x01, 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F,
0xE0, 0x0F, 0xF0, 0x07, 0xFC, 0x07, 0xDE, 0x03, 0xCF, 0x83, 0xE3, 0xFF,
0xE0, 0xFF, 0xE0, 0x1F, 0xC0, 0x0C, 0x30, 0x0F, 0x3C, 0x07, 0x9E, 0x01,
0x86, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x7F, 0xF0, 0x7F, 0xFC, 0x7C, 0x1F,
0x3C, 0x07, 0xBE, 0x03, 0xFE, 0x00, 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0,
0x1F, 0xE0, 0x0F, 0xF8, 0x0F, 0xBC, 0x07, 0x9F, 0x07, 0xC7, 0xFF, 0xC1,
0xFF, 0xC0, 0x3F, 0x80, 0x20, 0x47, 0x0E, 0xF9, 0xF7, 0xFE, 0x1F, 0x80,
0xF0, 0x1F, 0x83, 0xFC, 0xF9, 0xF7, 0x0E, 0x20, 0x40, 0x00, 0x02, 0x03,
0xFB, 0x87, 0xFF, 0xC7, 0xFF, 0xC7, 0xC3, 0xF3, 0xC1, 0xFB, 0xE1, 0xFF,
0xE1, 0xEF, 0xF0, 0xE7, 0xF8, 0xE3, 0xFC, 0xE1, 0xFE, 0xF0, 0xFF, 0xF0,
0xFB, 0xF0, 0x79, 0xF8, 0x7C, 0x7F, 0xFC, 0x7F, 0xFC, 0x3B, 0xF8, 0x08,
0x00, 0x00, 0x04, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10, 0x00, 0x03,
0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8,
0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1E, 0xF1, 0xE7, 0xFF,
0x1F, 0xF0, 0x3E, 0x00, 0x01, 0x00, 0x1E, 0x01, 0xE0, 0x1E, 0x00, 0x40,
0x00, 0x03, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF,
0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1E, 0xF1,
0xE7, 0xFF, 0x1F, 0xF0, 0x3E, 0x00, 0x02, 0x00, 0x38, 0x03, 0xE0, 0x3B,
0x80, 0x88, 0x00, 0x03, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F,
0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC,
0x1E, 0xF1, 0xE7, 0xFF, 0x1F, 0xF0, 0x3E, 0x00, 0x30, 0xC3, 0xCF, 0x1E,
0x78, 0x61, 0x80, 0x00, 0x78, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83,
0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F,
0x83, 0xDE, 0x3C, 0xFF, 0xE3, 0xFE, 0x07, 0xC0, 0x00, 0x40, 0x00, 0xF0,
0x01, 0xE0, 0x03, 0xC0, 0x01, 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x78, 0x1E,
0x7C, 0x3E, 0x3C, 0x3C, 0x3E, 0x7C, 0x1F, 0xF8, 0x0F, 0xF0, 0x0F, 0xF0,
0x07, 0xE0, 0x07, 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xF0, 0x0F, 0x00, 0xFF, 0x8F, 0xFC,
0xFF, 0xEF, 0x1F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF1, 0xFF, 0xFE,
0xFF, 0xCF, 0xF0, 0xF0, 0x0F, 0x00, 0xF0, 0x00, 0x1F, 0x03, 0xFC, 0x1F,
0xF1, 0xE7, 0x8F, 0x3C, 0x79, 0xE3, 0xCF, 0x1E, 0xF0, 0xF7, 0x87, 0xBC,
0x3D, 0xF1, 0xEF, 0xCF, 0x1F, 0x78, 0x7F, 0xC1, 0xFE, 0x8F, 0xF7, 0xFF,
0xBF, 0xBD, 0xF8, 0x08, 0x0F, 0x01, 0xE0, 0x3C, 0x02, 0x00, 0x07, 0xF1,
0xFE, 0x7F, 0xC0, 0xF0, 0x3C, 0xFF, 0x7F, 0xFC, 0xFF, 0x3F, 0xCF, 0xFF,
0xDF, 0xF3, 0xF8, 0x04, 0x03, 0xC1, 0xE0, 0xF0, 0x10, 0x00, 0x07, 0xF1,
0xFE, 0x7F, 0xC0, 0xF0, 0x3C, 0xFF, 0x7F, 0xFC, 0xFF, 0x3F, 0xCF, 0xFF,
0xDF, 0xF3, 0xF8, 0x08, 0x07, 0x03, 0xE1, 0xDC, 0x22, 0x00, 0x07, 0xF1,
0xFE, 0x7F, 0xC0, 0xF0, 0x3C, 0xFF, 0x7F, 0xFC, 0xFF, 0x3F, 0xCF, 0xFF,
0xDF, 0xF3, 0xF8, 0x18, 0x8F, 0xF7, 0xF8, 0x8C, 0x00, 0x00, 0x07, 0xF1,
0xFE, 0x7F, 0xC0, 0xF0, 0x3C, 0xFF, 0x7F, 0xFC, 0xFF, 0x3F, 0xCF, 0xFF,
0xDF, 0xF3, 0xF8, 0x61, 0xBC, 0xFF, 0x3D, 0x86, 0x00, 0x1F, 0xC7, 0xF9,
0xFF, 0x03, 0xC0, 0xF3, 0xFD, 0xFF, 0xF3, 0xFC, 0xFF, 0x3F, 0xFF, 0x7F,
0xCF, 0xE0, 0x1E, 0x0F, 0xC3, 0x30, 0xCC, 0x3F, 0x07, 0x80, 0x01, 0xFC,
0x7F, 0x9F, 0xF0, 0x3C, 0x0F, 0x3F, 0xDF, 0xFF, 0x3F, 0xCF, 0xF3, 0xFF,
0xF7, 0xFC, 0xFE, 0x3F, 0x8F, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x00, 0xFD,
0xF0, 0x0F, 0x1E, 0x3F, 0xE3, 0xDF, 0xFF, 0xFF, 0xC7, 0xFF, 0xF0, 0xF0,
0x1E, 0x0F, 0x0B, 0xFF, 0xFF, 0x3F, 0xFF, 0xE3, 0xF9, 0xF8, 0x0F, 0x8F,
0xF7, 0xF9, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x1E, 0x17, 0xFC,
0xFF, 0x07, 0xC1, 0x80, 0x70, 0x1C, 0x1F, 0x07, 0x80, 0x04, 0x01, 0xE0,
0x0F, 0x00, 0x78, 0x01, 0x00, 0x00, 0x0F, 0x83, 0xFC, 0x7F, 0xE7, 0x9E,
0xF0, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x82, 0x7F, 0xE3, 0xFE,
0x0F, 0xC0, 0x02, 0x00, 0x78, 0x0F, 0x01, 0xE0, 0x08, 0x00, 0x00, 0x0F,
0x83, 0xFC, 0x7F, 0xE7, 0x9E, 0xF0, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0,
0x07, 0x82, 0x7F, 0xE3, 0xFE, 0x0F, 0xC0, 0x04, 0x00, 0xE0, 0x1F, 0x03,
0xB8, 0x11, 0x00, 0x00, 0x0F, 0x83, 0xFC, 0x7F, 0xE7, 0x9E, 0xF0, 0xFF,
0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x82, 0x7F, 0xE3, 0xFE, 0x0F, 0xC0,
0x30, 0xC7, 0x9E, 0x79, 0xE3, 0x0C, 0x00, 0x00, 0xF8, 0x3F, 0xC7, 0xFE,
0x79, 0xEF, 0x0F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x78, 0x27, 0xFE,
0x3F, 0xE0, 0xFC, 0x23, 0xC7, 0x8F, 0x08, 0x07, 0x9E, 0x79, 0xE7, 0x9E,
0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x80, 0x10, 0xF7, 0xBC, 0x40, 0x07, 0x9E,
0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x80, 0x10, 0x71, 0xF7,
0x74, 0x40, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78,
0xF1, 0xE0, 0x61, 0xBC, 0xFF, 0x3D, 0x86, 0x00, 0x07, 0x81, 0xE0, 0x78,
0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07,
0x80, 0x02, 0x00, 0xF1, 0x07, 0xF0, 0x7F, 0x0F, 0xE0, 0x5E, 0x00, 0xE1,
0xFF, 0x3F, 0xF7, 0xFF, 0xF8, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF,
0x9E, 0x7F, 0xE3, 0xFC, 0x1F, 0x00, 0x18, 0x87, 0xF9, 0xFE, 0x11, 0x80,
0x00, 0x00, 0x1F, 0xC7, 0xFE, 0xFF, 0xDE, 0x7F, 0xC7, 0xF8, 0xFF, 0x1F,
0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7, 0x80, 0x04, 0x00, 0xF0,
0x03, 0xC0, 0x0F, 0x00, 0x10, 0x00, 0x00, 0x3E, 0x07, 0xFC, 0x7F, 0xF3,
0xC7, 0xBC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xEF, 0x1E, 0x7F,
0xF1, 0xFF, 0x03, 0xE0, 0x01, 0x00, 0x1E, 0x01, 0xE0, 0x1E, 0x00, 0x40,
0x00, 0x00, 0x3E, 0x07, 0xFC, 0x7F, 0xF3, 0xC7, 0xBC, 0x1F, 0xE0, 0xFF,
0x07, 0xF8, 0x3F, 0xC1, 0xEF, 0x1E, 0x7F, 0xF1, 0xFF, 0x03, 0xE0, 0x02,
0x00, 0x38, 0x03, 0xE0, 0x3B, 0x80, 0x88, 0x00, 0x00, 0x3E, 0x07, 0xFC,
0x7F, 0xF3, 0xC7, 0xBC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xEF,
0x1E, 0x7F, 0xF1, 0xFF, 0x03, 0xE0, 0x0C, 0x40, 0xFF, 0x0F, 0xF0, 0x23,
0x00, 0x00, 0x00, 0x00, 0x3E, 0x07, 0xFC, 0x7F, 0xF3, 0xC7, 0xBC, 0x1F,
0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xEF, 0x1E, 0x7F, 0xF1, 0xFF, 0x03,
0xE0, 0x30, 0xC3, 0xCF, 0x1E, 0x78, 0x61, 0x80, 0x00, 0x07, 0xC0, 0xFF,
0x8F, 0xFE, 0x78, 0xF7, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3D,
0xE3, 0xCF, 0xFE, 0x3F, 0xE0, 0x7C, 0x00, 0x06, 0x00, 0xF0, 0x0F, 0x00,
0x60, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x60, 0x0F, 0x00,
0xF0, 0x06, 0x00, 0x00, 0x00, 0x7D, 0xCF, 0xFC, 0xFF, 0xE7, 0x8F, 0x78,
0xFF, 0xCF, 0xFE, 0xEF, 0xFE, 0x7F, 0xE3, 0xDE, 0x3C, 0xFF, 0xE7, 0xFE,
0x77, 0xC0, 0x00, 0x00, 0x08, 0x07, 0x80, 0x78, 0x07, 0x80, 0x20, 0x00,
0x3C, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1F, 0xE3, 0xFC,
0x7F, 0xCF, 0x7F, 0xEF, 0xFC, 0x7F, 0x00, 0x02, 0x00, 0xF0, 0x3C, 0x0F,
0x00, 0x80, 0x00, 0x3C, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF,
0x1F, 0xE3, 0xFC, 0x7F, 0xCF, 0x7F, 0xEF, 0xFC, 0x7F, 0x00, 0x04, 0x01,
0xC0, 0x7C, 0x1D, 0xC1, 0x10, 0x00, 0x3C, 0x7F, 0x8F, 0xF1, 0xFE, 0x3F,
0xC7, 0xF8, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0xCF, 0x7F, 0xEF, 0xFC, 0x7F,
0x00, 0x61, 0x9E, 0x7B, 0xCF, 0x30, 0xC0, 0x01, 0xE3, 0xFC, 0x7F, 0x8F,
0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1F, 0xE3, 0xFE, 0x7B, 0xFF, 0x7F,
0xE3, 0xF8, 0x00, 0x80, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0x20, 0x00, 0x03,
0xC1, 0xFF, 0x1F, 0x78, 0xF3, 0xC7, 0x9E, 0x3C, 0x7B, 0xC3, 0xDE, 0x1E,
0xF0, 0x77, 0x03, 0xF8, 0x1F, 0xC0, 0x7C, 0x03, 0xE0, 0x3E, 0x0F, 0xF0,
0x7F, 0x03, 0xF0, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
0x00, 0xFF, 0x0F, 0xFC, 0xFF, 0xEF, 0x1E, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF,
0x0F, 0xF0, 0xFF, 0x1F, 0xFF, 0xEF, 0xFC, 0xFF, 0x8F, 0x00, 0xF0, 0x0F,
0x00, 0xF0, 0x00, 0x18, 0x61, 0xE7, 0x8F, 0x3C, 0x30, 0xC0, 0x00, 0x78,
0x3F, 0xE3, 0xEF, 0x1E, 0x78, 0xF3, 0xC7, 0x8F, 0x78, 0x7B, 0xC3, 0xDE,
0x0E, 0xE0, 0x7F, 0x03, 0xF8, 0x0F, 0x80, 0x7C, 0x07, 0xC1, 0xFE, 0x0F,
0xE0, 0x7E, 0x00 };
const GFXglyph Ubuntu_Bold12pt8bGlyphs[] PROGMEM = {
{ 0, 1, 1, 6, 0, 0 }, // 0x20 ' ' U+0020
{ 1, 4, 17, 8, 2, -16 }, // 0x21 '!' U+0021
{ 10, 9, 7, 11, 1, -17 }, // 0x22 '"' U+0022
{ 18, 15, 17, 17, 1, -16 }, // 0x23 '#' U+0023
{ 50, 12, 22, 14, 1, -18 }, // 0x24 '$' U+0024
{ 83, 20, 17, 22, 1, -16 }, // 0x25 '%' U+0025
{ 126, 16, 17, 17, 1, -16 }, // 0x26 '&' U+0026
{ 160, 4, 7, 6, 1, -17 }, // 0x27 ''' U+0027
{ 164, 7, 23, 9, 2, -18 }, // 0x28 '(' U+0028
{ 185, 7, 23, 9, 0, -18 }, // 0x29 ')' U+0029
{ 206, 11, 10, 12, 1, -16 }, // 0x2a '*' U+002A
{ 220, 11, 11, 13, 1, -12 }, // 0x2b '+' U+002B
{ 236, 5, 8, 6, 0, -3 }, // 0x2c ',' U+002C
{ 241, 7, 3, 9, 1, -8 }, // 0x2d '-' U+002D
{ 244, 4, 4, 6, 1, -3 }, // 0x2e '.' U+002E
{ 246, 12, 23, 10, -1, -18 }, // 0x2f '/' U+002F
{ 281, 12, 17, 14, 1, -16 }, // 0x30 '0' U+0030
{ 307, 8, 17, 14, 2, -16 }, // 0x31 '1' U+0031
{ 324, 12, 17, 14, 1, -16 }, // 0x32 '2' U+0032
{ 350, 11, 17, 14, 1, -16 }, // 0x33 '3' U+0033
{ 374, 12, 17, 14, 1, -16 }, // 0x34 '4' U+0034
{ 400, 12, 17, 14, 1, -16 }, // 0x35 '5' U+0035
{ 426, 12, 17, 14, 1, -16 }, // 0x36 '6' U+0036
{ 452, 12, 17, 14, 1, -16 }, // 0x37 '7' U+0037
{ 478, 12, 17, 14, 1, -16 }, // 0x38 '8' U+0038
{ 504, 12, 17, 14, 1, -16 }, // 0x39 '9' U+0039
{ 530, 4, 13, 6, 1, -12 }, // 0x3a ':' U+003A
{ 537, 5, 17, 6, 0, -12 }, // 0x3b ';' U+003B
{ 548, 12, 11, 14, 1, -12 }, // 0x3c '<' U+003C
{ 565, 11, 8, 14, 2, -10 }, // 0x3d '=' U+003D
{ 576, 12, 11, 14, 1, -12 }, // 0x3e '>' U+003E
{ 593, 10, 19, 11, 0, -18 }, // 0x3f '?' U+003F
{ 617, 21, 21, 23, 1, -16 }, // 0x40 '@' U+0040
{ 673, 17, 17, 17, 0, -16 }, // 0x41 'A' U+0041
{ 710, 13, 17, 16, 2, -16 }, // 0x42 'B' U+0042
{ 738, 14, 17, 16, 1, -16 }, // 0x43 'C' U+0043
{ 768, 15, 17, 18, 2, -16 }, // 0x44 'D' U+0044
{ 800, 12, 17, 15, 2, -16 }, // 0x45 'E' U+0045
{ 826, 11, 17, 14, 2, -16 }, // 0x46 'F' U+0046
{ 850, 14, 17, 17, 1, -16 }, // 0x47 'G' U+0047
{ 880, 14, 17, 18, 2, -16 }, // 0x48 'H' U+0048
{ 910, 4, 17, 8, 2, -16 }, // 0x49 'I' U+0049
{ 919, 11, 17, 13, 0, -16 }, // 0x4a 'J' U+004A
{ 943, 14, 17, 16, 2, -16 }, // 0x4b 'K' U+004B
{ 973, 12, 17, 14, 2, -16 }, // 0x4c 'L' U+004C
{ 999, 19, 17, 21, 1, -16 }, // 0x4d 'M' U+004D
{ 1040, 14, 17, 18, 2, -16 }, // 0x4e 'N' U+004E
{ 1070, 17, 17, 19, 1, -16 }, // 0x4f 'O' U+004F
{ 1107, 12, 17, 15, 2, -16 }, // 0x50 'P' U+0050
{ 1133, 17, 22, 19, 1, -16 }, // 0x51 'Q' U+0051
{ 1180, 14, 17, 16, 2, -16 }, // 0x52 'R' U+0052
{ 1210, 12, 17, 14, 1, -16 }, // 0x53 'S' U+0053
{ 1236, 14, 17, 14, 0, -16 }, // 0x54 'T' U+0054
{ 1266, 13, 17, 17, 2, -16 }, // 0x55 'U' U+0055
{ 1294, 17, 17, 17, 0, -16 }, // 0x56 'V' U+0056
{ 1331, 23, 17, 23, 0, -16 }, // 0x57 'W' U+0057
{ 1380, 16, 17, 16, 0, -16 }, // 0x58 'X' U+0058
{ 1414, 16, 17, 16, 0, -16 }, // 0x59 'Y' U+0059
{ 1448, 13, 17, 15, 1, -16 }, // 0x5a 'Z' U+005A
{ 1476, 7, 23, 9, 2, -18 }, // 0x5b '[' U+005B
{ 1497, 12, 23, 10, -1, -18 }, // 0x5c '\' U+005C
{ 1532, 7, 23, 9, 0, -18 }, // 0x5d ']' U+005D
{ 1553, 13, 10, 13, 0, -16 }, // 0x5e '^' U+005E
{ 1570, 12, 3, 12, 0, 2 }, // 0x5f '_' U+005F
{ 1575, 6, 5, 7, 1, -18 }, // 0x60 '`' U+0060
{ 1579, 10, 13, 13, 1, -12 }, // 0x61 'a' U+0061
{ 1596, 12, 19, 15, 2, -18 }, // 0x62 'b' U+0062
{ 1625, 10, 13, 12, 1, -12 }, // 0x63 'c' U+0063
{ 1642, 12, 19, 15, 1, -18 }, // 0x64 'd' U+0064
{ 1671, 12, 13, 14, 1, -12 }, // 0x65 'e' U+0065
{ 1691, 9, 19, 10, 2, -18 }, // 0x66 'f' U+0066
{ 1713, 11, 17, 14, 1, -12 }, // 0x67 'g' U+0067
{ 1737, 11, 19, 15, 2, -18 }, // 0x68 'h' U+0068
{ 1764, 4, 19, 8, 2, -18 }, // 0x69 'i' U+0069
{ 1774, 7, 23, 6, -2, -18 }, // 0x6a 'j' U+006A
{ 1795, 12, 19, 14, 2, -18 }, // 0x6b 'k' U+006B
{ 1824, 6, 19, 8, 2, -18 }, // 0x6c 'l' U+006C
{ 1839, 18, 13, 22, 2, -12 }, // 0x6d 'm' U+006D
{ 1869, 11, 13, 15, 2, -12 }, // 0x6e 'n' U+006E
{ 1887, 13, 13, 15, 1, -12 }, // 0x6f 'o' U+006F
{ 1909, 12, 17, 15, 2, -12 }, // 0x70 'p' U+0070
{ 1935, 13, 17, 15, 1, -12 }, // 0x71 'q' U+0071
{ 1963, 9, 13, 11, 2, -12 }, // 0x72 'r' U+0072
{ 1978, 10, 13, 12, 1, -12 }, // 0x73 's' U+0073
{ 1995, 9, 17, 11, 2, -16 }, // 0x74 't' U+0074
{ 2015, 11, 13, 15, 2, -12 }, // 0x75 'u' U+0075
{ 2033, 13, 13, 13, 0, -12 }, // 0x76 'v' U+0076
{ 2055, 19, 13, 19, 0, -12 }, // 0x77 'w' U+0077
{ 2086, 13, 13, 13, 0, -12 }, // 0x78 'x' U+0078
{ 2108, 13, 17, 13, 0, -12 }, // 0x79 'y' U+0079
{ 2136, 10, 13, 12, 1, -12 }, // 0x7a 'z' U+007A
{ 2153, 8, 23, 9, 1, -18 }, // 0x7b '{' U+007B
{ 2176, 3, 23, 7, 2, -18 }, // 0x7c '|' U+007C
{ 2185, 8, 23, 9, 0, -18 }, // 0x7d '}' U+007D
{ 2208, 12, 5, 14, 1, -9 }, // 0x7e '~' U+007E
{ 2216, 10, 18, 12, 1, -17 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
{ 2239, 1, 1, 6, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
{ 2240, 4, 17, 8, 2, -12 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
{ 2249, 11, 18, 14, 1, -15 }, // 0x82 'CENT SIGN' U+00A2
{ 2274, 11, 17, 14, 1, -16 }, // 0x83 'POUND SIGN' U+00A3
{ 2298, 11, 11, 14, 1, -13 }, // 0x84 'CURRENCY SIGN' U+00A4
{ 2314, 14, 17, 14, 0, -16 }, // 0x85 'YEN SIGN' U+00A5
{ 2344, 4, 23, 7, 2, -18 }, // 0x86 'BROKEN BAR' U+00A6
{ 2356, 10, 21, 12, 1, -16 }, // 0x87 'SECTION SIGN' U+00A7
{ 2383, 10, 4, 13, 2, -17 }, // 0x88 'DIAERESIS' U+00A8
{ 2388, 17, 17, 19, 1, -16 }, // 0x89 'COPYRIGHT SIGN' U+00A9
{ 2425, 8, 9, 10, 1, -16 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
{ 2434, 12, 11, 14, 1, -11 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
{ 2451, 12, 9, 14, 1, -9 }, // 0x8c 'NOT SIGN' U+00AC
{ 2465, 7, 3, 9, 1, -8 }, // 0x8d 'SOFT HYPHEN' U+00AD
{ 2468, 17, 17, 19, 1, -16 }, // 0x8e 'REGISTERED SIGN' U+00AE
{ 2505, 8, 2, 9, 1, -16 }, // 0x8f 'MACRON' U+00AF
{ 2507, 7, 7, 8, 0, -17 }, // 0x90 'DEGREE SIGN' U+00B0
{ 2514, 11, 15, 13, 1, -14 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
{ 2535, 8, 10, 9, 0, -16 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
{ 2545, 8, 10, 9, 0, -16 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
{ 2555, 6, 5, 7, 0, -18 }, // 0x94 'ACUTE ACCENT' U+00B4
{ 2559, 11, 17, 15, 2, -12 }, // 0x95 'MICRO SIGN' U+00B5
{ 2583, 14, 21, 17, 1, -16 }, // 0x96 'PILCROW SIGN' U+00B6
{ 2620, 4, 4, 6, 1, -8 }, // 0x97 'MIDDLE DOT' U+00B7
{ 2622, 6, 5, 8, 1, 1 }, // 0x98 'CEDILLA' U+00B8
{ 2626, 6, 10, 9, 1, -16 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
{ 2634, 9, 10, 11, 1, -16 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
{ 2646, 12, 11, 14, 1, -11 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
{ 2663, 20, 17, 21, 1, -16 }, // 0x9c 'VULGAR FRACTION ONE QUARTER' U+00BC
{ 2706, 19, 17, 21, 1, -16 }, // 0x9d 'VULGAR FRACTION ONE HALF' U+00BD
{ 2747, 21, 17, 21, 0, -16 }, // 0x9e 'VULGAR FRACTION THREE QUARTERS' U+00BE
{ 2792, 10, 17, 11, 1, -12 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
{ 2814, 17, 23, 17, 0, -22 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
{ 2863, 17, 23, 17, 0, -22 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
{ 2912, 17, 23, 17, 0, -22 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
{ 2961, 17, 23, 17, 0, -22 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
{ 3010, 17, 22, 17, 0, -21 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
{ 3057, 17, 22, 17, 0, -21 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
{ 3104, 23, 17, 24, 0, -16 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
{ 3153, 14, 22, 16, 1, -16 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
{ 3192, 12, 23, 15, 2, -22 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
{ 3227, 12, 23, 15, 2, -22 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
{ 3262, 12, 23, 15, 2, -22 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
{ 3297, 12, 22, 15, 2, -21 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
{ 3330, 6, 23, 8, 1, -22 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
{ 3348, 6, 23, 8, 1, -22 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
{ 3366, 7, 23, 8, 1, -22 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
{ 3387, 10, 22, 8, -1, -21 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
{ 3415, 17, 17, 18, 0, -16 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
{ 3452, 14, 23, 18, 2, -22 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
{ 3493, 17, 23, 19, 1, -22 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
{ 3542, 17, 23, 19, 1, -22 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
{ 3591, 17, 23, 19, 1, -22 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
{ 3640, 17, 23, 19, 1, -22 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
{ 3689, 17, 22, 19, 1, -21 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
{ 3736, 12, 11, 14, 1, -12 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
{ 3753, 17, 19, 19, 1, -17 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
{ 3794, 13, 23, 17, 2, -22 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
{ 3832, 13, 23, 17, 2, -22 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
{ 3870, 13, 23, 17, 2, -22 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
{ 3908, 13, 22, 17, 2, -21 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
{ 3944, 16, 23, 16, 0, -22 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
{ 3990, 12, 17, 15, 2, -16 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
{ 4016, 13, 19, 16, 2, -18 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
{ 4047, 10, 19, 13, 1, -18 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
{ 4071, 10, 19, 13, 1, -18 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
{ 4095, 10, 19, 13, 1, -18 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
{ 4119, 10, 19, 13, 1, -18 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
{ 4143, 10, 18, 13, 1, -17 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
{ 4166, 10, 20, 13, 1, -19 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
{ 4191, 19, 13, 21, 1, -12 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
{ 4222, 10, 18, 12, 1, -12 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
{ 4245, 12, 19, 14, 1, -18 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
{ 4274, 12, 19, 14, 1, -18 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
{ 4303, 12, 19, 14, 1, -18 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
{ 4332, 12, 18, 14, 1, -17 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
{ 4359, 6, 19, 8, 1, -18 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
{ 4374, 6, 19, 8, 1, -18 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
{ 4389, 7, 19, 8, 1, -18 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
{ 4406, 10, 18, 8, -1, -17 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
{ 4429, 12, 19, 14, 1, -18 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
{ 4458, 11, 19, 15, 2, -18 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
{ 4485, 13, 19, 15, 1, -18 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
{ 4516, 13, 19, 15, 1, -18 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
{ 4547, 13, 19, 15, 1, -18 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
{ 4578, 13, 19, 15, 1, -18 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
{ 4609, 13, 18, 15, 1, -17 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
{ 4639, 12, 13, 14, 1, -12 }, // 0xd7 'DIVISION SIGN' U+00F7
{ 4659, 13, 15, 15, 1, -13 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
{ 4684, 11, 19, 15, 2, -18 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
{ 4711, 11, 19, 15, 2, -18 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
{ 4738, 11, 19, 15, 2, -18 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
{ 4765, 11, 18, 15, 2, -17 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
{ 4790, 13, 23, 13, 0, -18 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
{ 4828, 12, 23, 15, 2, -18 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
{ 4863, 13, 22, 13, 0, -17 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
const GFXfont Ubuntu_Bold12pt8b PROGMEM = {
(uint8_t *)Ubuntu_Bold12pt8bBitmaps,
(GFXglyph *)Ubuntu_Bold12pt8bGlyphs,
0x20, 0xDF, 27 };
// Approx. 6250 bytes

View File

@@ -1,866 +0,0 @@
const uint8_t Ubuntu_Bold16pt8bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x00, 0x0E, 0xFF,
0xFF, 0xF7, 0x00, 0xF9, 0xFF, 0x9F, 0xF9, 0xFF, 0x9F, 0xF9, 0xFF, 0x9F,
0xF9, 0xFF, 0x1E, 0x70, 0xE0, 0x07, 0xCF, 0x81, 0xF3, 0xE0, 0x7D, 0xF8,
0x3E, 0x7C, 0x0F, 0x9F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xC7, 0xCF, 0x81, 0xF3, 0xE0, 0x7C, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x7C, 0x0F, 0x9F, 0x07, 0xEF, 0x81,
0xF3, 0xE0, 0x7C, 0xF8, 0x00, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x07,
0xF8, 0x1F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFC, 0x7E, 0x0C, 0x7C, 0x00, 0x7C,
0x00, 0x7E, 0x00, 0x7F, 0xE0, 0x3F, 0xF8, 0x1F, 0xFC, 0x0F, 0xFE, 0x01,
0xFF, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x1F, 0x70, 0x3F, 0x7F, 0xFE, 0xFF,
0xFE, 0xFF, 0xFC, 0x1F, 0xF0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03,
0xC0, 0x1F, 0x80, 0xF8, 0x0F, 0xF0, 0x3C, 0x07, 0xFE, 0x1F, 0x03, 0xE7,
0xC7, 0x80, 0xF0, 0xF3, 0xE0, 0x3C, 0x3C, 0xF0, 0x0F, 0x0F, 0x78, 0x03,
0xC3, 0xFE, 0x00, 0xF9, 0xFF, 0x00, 0x1F, 0xFF, 0xDF, 0x83, 0xFD, 0xEF,
0xF0, 0x7E, 0xFF, 0xFE, 0x00, 0x3F, 0xE7, 0xC0, 0x1F, 0xF0, 0xF0, 0x07,
0xBC, 0x3C, 0x03, 0xCF, 0x0F, 0x01, 0xF3, 0xC3, 0xC0, 0x78, 0xF9, 0xF0,
0x3E, 0x1F, 0xF8, 0x0F, 0x03, 0xFC, 0x07, 0xC0, 0x7E, 0x00, 0x07, 0xF0,
0x00, 0x7F, 0xE0, 0x07, 0xFF, 0x80, 0x7F, 0xFC, 0x03, 0xE3, 0xE0, 0x1F,
0x1F, 0x00, 0xFD, 0xF0, 0x03, 0xFF, 0x80, 0x1F, 0xF8, 0x00, 0xFF, 0x00,
0x0F, 0xFC, 0xF8, 0xFF, 0xF7, 0xC7, 0xDF, 0xBE, 0x7C, 0x7F, 0xE3, 0xE1,
0xFF, 0x1F, 0x07, 0xF0, 0xFC, 0x1F, 0x87, 0xFF, 0xFE, 0x1F, 0xFF, 0xF8,
0x7F, 0xFF, 0xE0, 0xFE, 0x3F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x70,
0x04, 0x07, 0x87, 0xE3, 0xE3, 0xF1, 0xF1, 0xF8, 0xF8, 0x7C, 0x3E, 0x3E,
0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x07, 0xC3,
0xE1, 0xF0, 0xFC, 0x3E, 0x1F, 0x87, 0xC3, 0xF0, 0xF0, 0x20, 0x10, 0x3C,
0x3F, 0x0F, 0x87, 0xE1, 0xF0, 0xFC, 0x3E, 0x1F, 0x0F, 0x83, 0xE1, 0xF0,
0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF1, 0xF0, 0xF8, 0x7C,
0x7E, 0x3E, 0x3F, 0x1F, 0x1F, 0x87, 0x80, 0x80, 0x0F, 0x80, 0x7C, 0x1B,
0xCC, 0xEE, 0xEF, 0xFF, 0xFF, 0xFC, 0x1C, 0x03, 0xF8, 0x3D, 0xE3, 0xEF,
0x8E, 0x38, 0x11, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07,
0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1E, 0x00, 0x78, 0x01,
0xE0, 0x07, 0x80, 0x1E, 0x00, 0x7D, 0xF7, 0xDF, 0x7D, 0xE7, 0xBE, 0xF1,
0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7B, 0xFF, 0xFF, 0xFD, 0xE0, 0x00,
0x3E, 0x00, 0xFC, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E,
0x00, 0xFC, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E, 0x00,
0xFC, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E, 0x00, 0xFC,
0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x3E, 0x00, 0xFC, 0x01,
0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x00, 0x07, 0xE0, 0x1F, 0xF8,
0x3F, 0xFC, 0x3F, 0xFC, 0x7E, 0x7E, 0x7C, 0x3E, 0xF8, 0x1F, 0xF8, 0x1F,
0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
0xF8, 0x1F, 0x7C, 0x3E, 0x7E, 0x7E, 0x3F, 0xFC, 0x3F, 0xFC, 0x1F, 0xF8,
0x07, 0xE0, 0x03, 0xC1, 0xF1, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0x7D, 0x1F,
0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1,
0xF0, 0x7C, 0x1F, 0x07, 0xC0, 0x0F, 0xC0, 0x7F, 0xE3, 0xFF, 0xE7, 0xFF,
0xE7, 0x8F, 0xC4, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0xF8, 0x03, 0xF0,
0x0F, 0xC0, 0x3F, 0x00, 0xFE, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x3E,
0x00, 0xFF, 0xFD, 0xFF, 0xFB, 0xFF, 0xF7, 0xFF, 0xE0, 0x1F, 0xC0, 0xFF,
0xE3, 0xFF, 0xE3, 0xFF, 0xE6, 0x0F, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x7C,
0x1F, 0xF8, 0x3F, 0xC0, 0x7F, 0xE0, 0xFF, 0xE0, 0x0F, 0xE0, 0x07, 0xC0,
0x0F, 0x80, 0x1F, 0x60, 0x7F, 0xFF, 0xFB, 0xFF, 0xF7, 0xFF, 0xC3, 0xFC,
0x00, 0x00, 0x7C, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0xFC, 0x07, 0xFC, 0x0F,
0xFC, 0x0F, 0x7C, 0x1E, 0x7C, 0x3E, 0x7C, 0x3C, 0x7C, 0x78, 0x7C, 0xF8,
0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7C, 0x00,
0x7C, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x7C, 0x3F, 0xFC, 0x7F, 0xF8, 0xFF,
0xF1, 0xFF, 0xE3, 0xC0, 0x07, 0x80, 0x1F, 0x00, 0x3F, 0xC0, 0x7F, 0xF0,
0xFF, 0xF1, 0xFF, 0xF0, 0x0F, 0xF0, 0x07, 0xE0, 0x07, 0xC0, 0x0F, 0x80,
0x1F, 0x40, 0x7F, 0xFF, 0xFB, 0xFF, 0xE7, 0xFF, 0x83, 0xFC, 0x00, 0x00,
0x3E, 0x01, 0xFE, 0x07, 0xFE, 0x0F, 0xFE, 0x1F, 0xE0, 0x3F, 0x00, 0x7E,
0x00, 0x7C, 0x00, 0xFF, 0xF0, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0xFE, 0xF8,
0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0x7C, 0x3F, 0x7F, 0xFE, 0x3F,
0xFC, 0x1F, 0xF8, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xFC, 0x00, 0xF8, 0x01, 0xF8, 0x01,
0xF0, 0x01, 0xF0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x07, 0xC0, 0x07,
0xC0, 0x07, 0xC0, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x0F,
0xE0, 0x3F, 0xF8, 0x7F, 0xFC, 0xFF, 0xFE, 0xFC, 0x7E, 0xF8, 0x3E, 0xF8,
0x3E, 0xFC, 0x7C, 0x7F, 0xFC, 0x3F, 0xF0, 0x3F, 0xFC, 0x7F, 0xFE, 0xFC,
0x3E, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F, 0x7F, 0xFE, 0x7F,
0xFE, 0x3F, 0xFC, 0x07, 0xF0, 0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F,
0xFE, 0xFC, 0x3E, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x1F, 0x7F,
0xFF, 0x7F, 0xFF, 0x3F, 0xFF, 0x0F, 0xDF, 0x00, 0x3E, 0x00, 0x7E, 0x00,
0xFE, 0x03, 0xFC, 0x3F, 0xF8, 0x3F, 0xF0, 0x3F, 0xC0, 0x3E, 0x00, 0x7B,
0xFF, 0xFF, 0xFD, 0xE0, 0x00, 0x00, 0x00, 0x1E, 0xFF, 0xFF, 0xFF, 0x78,
0x7B, 0xFF, 0xFF, 0xFD, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xF7, 0xDF,
0x7D, 0xE7, 0xBE, 0xF1, 0xC0, 0x00, 0x0C, 0x01, 0xF8, 0x3F, 0xFB, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xE0, 0x7C, 0x00, 0xFF, 0x81, 0xFF, 0xF3,
0xFF, 0xFB, 0xFF, 0xF0, 0xFF, 0xE0, 0x1F, 0x80, 0x03, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x60, 0x01, 0xF0, 0x0F, 0xFC,
0x3F, 0xFE, 0xFF, 0xFC, 0xFF, 0xF0, 0x7F, 0xC0, 0x1F, 0x03, 0xFC, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xC1, 0xF0, 0x06, 0x00, 0x00, 0x3F, 0x8F,
0xFC, 0xFF, 0xE7, 0xFF, 0x63, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x03, 0xE0,
0x7E, 0x0F, 0xC0, 0xF8, 0x1F, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x00, 0x00,
0x00, 0x1E, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x01, 0xE0, 0x00, 0x7F,
0x80, 0x00, 0x7F, 0xFC, 0x00, 0x7F, 0xFF, 0xC0, 0x3F, 0x03, 0xF8, 0x1F,
0x00, 0x1F, 0x0F, 0x80, 0x03, 0xC3, 0xC1, 0xF8, 0x79, 0xE1, 0xFF, 0x1E,
0x78, 0xFF, 0xC7, 0xFE, 0x3C, 0xF0, 0xFF, 0x1E, 0x3C, 0x3F, 0xC7, 0x8F,
0x0F, 0xF1, 0xE3, 0xC3, 0xFC, 0x78, 0xF0, 0xFF, 0x1E, 0x3C, 0x3F, 0xC7,
0x8F, 0x0F, 0xF1, 0xE3, 0xC7, 0xBE, 0x3C, 0xF1, 0xE7, 0x8F, 0xFF, 0xF1,
0xE1, 0xFF, 0xF8, 0x3C, 0x3E, 0xF8, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00,
0x00, 0x3F, 0x80, 0x40, 0x07, 0xFF, 0xF0, 0x00, 0x7F, 0xFC, 0x00, 0x03,
0xFE, 0x00, 0x00, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0x80, 0x07, 0xFC,
0x00, 0x3F, 0xF0, 0x03, 0xEF, 0x80, 0x1F, 0x7E, 0x00, 0xFB, 0xF0, 0x0F,
0x8F, 0x80, 0x7C, 0x7E, 0x03, 0xE3, 0xF0, 0x3E, 0x0F, 0x81, 0xFF, 0xFC,
0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0x87, 0xFF, 0xFC, 0x7E, 0x03, 0xF3, 0xE0,
0x0F, 0x9F, 0x00, 0x7D, 0xF8, 0x03, 0xFF, 0x80, 0x0F, 0x80, 0xFF, 0xE0,
0x7F, 0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF, 0x83, 0xF7, 0xC0, 0xFB, 0xE0,
0x7D, 0xF0, 0x7E, 0xFF, 0xFE, 0x7F, 0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF,
0x81, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
0xBF, 0xFF, 0xDF, 0xFF, 0x87, 0xFF, 0x00, 0x01, 0xFC, 0x03, 0xFF, 0xC7,
0xFF, 0xE7, 0xFF, 0xE3, 0xF0, 0x33, 0xF0, 0x01, 0xF0, 0x01, 0xF0, 0x00,
0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0,
0x03, 0xF0, 0x00, 0xFC, 0x00, 0x7F, 0x03, 0x1F, 0xFF, 0x87, 0xFF, 0xE1,
0xFF, 0xF0, 0x3F, 0xC0, 0xFF, 0xE0, 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7F,
0xFF, 0xCF, 0x83, 0xF9, 0xF0, 0x1F, 0xBE, 0x01, 0xF7, 0xC0, 0x1F, 0xF8,
0x03, 0xFF, 0x00, 0x7F, 0xE0, 0x0F, 0xFC, 0x01, 0xFF, 0x80, 0x3F, 0xF0,
0x0F, 0xFE, 0x01, 0xF7, 0xC0, 0x7E, 0xF8, 0x3F, 0x9F, 0xFF, 0xF3, 0xFF,
0xFC, 0x7F, 0xFE, 0x0F, 0xFE, 0x00, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
0xFF, 0xFE, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFC,
0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00,
0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0x00, 0x3E,
0x00, 0x7C, 0x00, 0xFF, 0xFD, 0xFF, 0xFB, 0xFF, 0xF7, 0xFF, 0xEF, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07,
0xC0, 0x0F, 0x80, 0x00, 0x01, 0xFE, 0x01, 0xFF, 0xF1, 0xFF, 0xFC, 0xFF,
0xFE, 0x3F, 0x01, 0x9F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0xF8, 0x00,
0x3E, 0x00, 0x0F, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xF7,
0xC0, 0x7D, 0xF8, 0x1F, 0x7F, 0x07, 0xCF, 0xFF, 0xF1, 0xFF, 0xFC, 0x3F,
0xFF, 0x01, 0xFF, 0x00, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xE0, 0x0F, 0xFC,
0x01, 0xFF, 0x80, 0x3F, 0xF0, 0x07, 0xFE, 0x00, 0xFF, 0xC0, 0x1F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xF0,
0x07, 0xFE, 0x00, 0xFF, 0xC0, 0x1F, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xE0,
0x0F, 0xFC, 0x01, 0xFF, 0x80, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x7C, 0x01, 0xF0,
0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C,
0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F,
0x60, 0xFD, 0xFF, 0xEF, 0xFF, 0xBF, 0xFC, 0x3F, 0xC0, 0xF8, 0x1F, 0xDF,
0x07, 0xF3, 0xE1, 0xFC, 0x7C, 0x7F, 0x0F, 0x9F, 0xC1, 0xF7, 0xF0, 0x3F,
0xFC, 0x07, 0xFF, 0x00, 0xFF, 0xC0, 0x1F, 0xF0, 0x03, 0xFF, 0x00, 0x7F,
0xF0, 0x0F, 0xFF, 0x01, 0xF7, 0xE0, 0x3E, 0x7E, 0x07, 0xC7, 0xE0, 0xF8,
0x7E, 0x1F, 0x07, 0xE3, 0xE0, 0x7E, 0x7C, 0x0F, 0xEF, 0x80, 0xFE, 0xF8,
0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E,
0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F,
0x80, 0x3E, 0x00, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
0x3E, 0x00, 0x7C, 0x3E, 0x00, 0x7C, 0x3F, 0x00, 0xFC, 0x7F, 0x00, 0xFE,
0x7F, 0x80, 0xFE, 0x7F, 0x81, 0xFE, 0x7F, 0xC1, 0xFE, 0x7F, 0xC3, 0xFE,
0x7F, 0xE3, 0xFE, 0x7D, 0xE7, 0xBE, 0x79, 0xF7, 0x9E, 0x78, 0xF7, 0x9E,
0x78, 0xFF, 0x1E, 0xF8, 0x7F, 0x1E, 0xF8, 0x7E, 0x1F, 0xF8, 0x3E, 0x1F,
0xF8, 0x3E, 0x1F, 0xF8, 0x3C, 0x1F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x1F,
0xF8, 0x00, 0x1F, 0xF8, 0x03, 0xFF, 0x80, 0x7F, 0xF8, 0x0F, 0xFF, 0x01,
0xFF, 0xF0, 0x3F, 0xFF, 0x07, 0xFF, 0xF0, 0xFF, 0xFF, 0x1F, 0xFB, 0xE3,
0xFF, 0x3E, 0x7F, 0xE3, 0xEF, 0xFC, 0x7F, 0xFF, 0x87, 0xFF, 0xF0, 0x7F,
0xFE, 0x07, 0xFF, 0xC0, 0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0xFF, 0xE0, 0x1F,
0xFC, 0x01, 0xFF, 0x80, 0x3E, 0x01, 0xF8, 0x00, 0xFF, 0xF0, 0x1F, 0xFF,
0x83, 0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xE0, 0x7E, 0x7C, 0x03, 0xEF, 0x80,
0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8,
0x01, 0xFF, 0x80, 0x1F, 0x7C, 0x03, 0xE7, 0xE0, 0x7E, 0x7F, 0x0F, 0xE3,
0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x01, 0xFC, 0x00, 0xFF, 0xE0,
0x7F, 0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF, 0x83, 0xFF, 0xC0, 0x7F, 0xE0,
0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x1F, 0xFF, 0xFF, 0xDF, 0xFF, 0xCF,
0xFF, 0xC7, 0xFF, 0x83, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00,
0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF8, 0x00, 0xFF, 0xF0,
0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xE0, 0x7E, 0x7C, 0x03,
0xEF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80,
0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0x7C, 0x03, 0xF7, 0xE0, 0x7E, 0x3F,
0x0F, 0xE3, 0xFF, 0xFC, 0x1F, 0xFF, 0xC0, 0xFF, 0xF0, 0x01, 0xFE, 0x00,
0x07, 0xC0, 0x00, 0x7F, 0x00, 0x03, 0xFE, 0x00, 0x1F, 0xE0, 0x00, 0xFC,
0x00, 0x03, 0xC0, 0xFF, 0xE0, 0x3F, 0xFF, 0x0F, 0xFF, 0xE3, 0xFF, 0xFC,
0xF8, 0x3F, 0xBE, 0x03, 0xEF, 0x80, 0xFB, 0xE0, 0x3E, 0xF8, 0x0F, 0xBE,
0x0F, 0xEF, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0xFC, 0x3F, 0xFE, 0x0F, 0x9F,
0xC3, 0xE3, 0xF0, 0xF8, 0x7E, 0x3E, 0x0F, 0xCF, 0x83, 0xFB, 0xE0, 0x7E,
0xF8, 0x0F, 0xC0, 0x07, 0xF0, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0xFC,
0x0C, 0xF8, 0x00, 0xF8, 0x00, 0xFC, 0x00, 0x7F, 0x80, 0x7F, 0xF0, 0x1F,
0xFC, 0x07, 0xFE, 0x00, 0xFF, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x1F, 0x70,
0x3F, 0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0x1F, 0xE0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80,
0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E,
0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00,
0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80,
0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F,
0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE,
0x01, 0xFF, 0x80, 0x7F, 0xF0, 0x3F, 0x7E, 0x1F, 0x9F, 0xFF, 0xE3, 0xFF,
0xF0, 0x7F, 0xF8, 0x07, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xE0, 0x0F, 0x9F,
0x00, 0x7C, 0xFC, 0x03, 0xE3, 0xE0, 0x3E, 0x1F, 0x01, 0xF0, 0xFC, 0x1F,
0x83, 0xE0, 0xF8, 0x1F, 0x07, 0xC0, 0xFC, 0x7E, 0x07, 0xE3, 0xE0, 0x1F,
0x1F, 0x00, 0xFD, 0xF8, 0x07, 0xEF, 0x80, 0x1F, 0x7C, 0x00, 0xFF, 0xE0,
0x03, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0x1F,
0xC0, 0x00, 0xF8, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x0F, 0xDF, 0x03, 0xE0,
0x7C, 0xF8, 0x1F, 0x03, 0xE7, 0xC1, 0xFC, 0x1F, 0x3E, 0x0F, 0xE0, 0xF8,
0xF0, 0x7F, 0x0F, 0x87, 0xC3, 0xF8, 0x7C, 0x3E, 0x3D, 0xE3, 0xE1, 0xF1,
0xEF, 0x1F, 0x07, 0x8F, 0x78, 0xF0, 0x3E, 0xFB, 0xEF, 0x81, 0xF7, 0x8F,
0x7C, 0x0F, 0xBC, 0x7B, 0xE0, 0x3D, 0xE3, 0xFE, 0x01, 0xFF, 0x1F, 0xF0,
0x0F, 0xF0, 0x7F, 0x80, 0x3F, 0x83, 0xF8, 0x01, 0xFC, 0x1F, 0xC0, 0x0F,
0xC0, 0x7E, 0x00, 0x3E, 0x03, 0xE0, 0x00, 0xFC, 0x01, 0xFB, 0xF0, 0x1F,
0x8F, 0xC1, 0xF8, 0x3E, 0x0F, 0x81, 0xF8, 0xFC, 0x07, 0xEF, 0xC0, 0x1F,
0xFC, 0x00, 0xFF, 0xE0, 0x03, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0x3E, 0x00,
0x03, 0xF8, 0x00, 0x3F, 0xE0, 0x03, 0xFF, 0x80, 0x1F, 0xFC, 0x01, 0xFB,
0xF0, 0x1F, 0x8F, 0xC1, 0xF8, 0x3E, 0x0F, 0xC1, 0xF8, 0xFC, 0x07, 0xEF,
0xC0, 0x1F, 0x80, 0xFC, 0x01, 0xFB, 0xE0, 0x1F, 0x9F, 0x80, 0xFC, 0x7E,
0x0F, 0xC1, 0xF0, 0x7C, 0x0F, 0xC7, 0xE0, 0x3F, 0x7E, 0x01, 0xFB, 0xF0,
0x07, 0xFF, 0x00, 0x1F, 0xF0, 0x00, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0x0F,
0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00,
0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7F,
0xFF, 0xBF, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xF0, 0x03, 0xF0, 0x03, 0xF0,
0x03, 0xF0, 0x03, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xFC,
0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8,
0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F,
0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x01,
0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F,
0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF8,
0x01, 0xF0, 0x03, 0xE0, 0x07, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF8, 0x01,
0xF0, 0x03, 0xE0, 0x07, 0xE0, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1,
0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C,
0x1F, 0x07, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xC0, 0x01,
0xF0, 0x01, 0xFC, 0x00, 0xFE, 0x00, 0xFF, 0x80, 0x7B, 0xC0, 0x7D, 0xF0,
0x7C, 0x7C, 0x3C, 0x1E, 0x3E, 0x0F, 0xBE, 0x03, 0xEF, 0x01, 0xE1, 0x00,
0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0xE3, 0xE3,
0xE3, 0xE3, 0x82, 0x00, 0x1F, 0xE0, 0xFF, 0xC3, 0xFF, 0x8F, 0xFF, 0x00,
0xFC, 0x01, 0xF1, 0xFF, 0xDF, 0xFF, 0x7F, 0xFF, 0xF1, 0xFF, 0x87, 0xFE,
0x1F, 0xFF, 0xFD, 0xFF, 0xF7, 0xFF, 0xC7, 0xFE, 0x38, 0x00, 0xF8, 0x00,
0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00,
0xFB, 0xE0, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xFE, 0xF8, 0x3E, 0xF8, 0x3F,
0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x3F, 0xF8, 0x7E,
0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8, 0x3F, 0xE0, 0x03, 0xF8, 0x3F, 0xF3,
0xFF, 0xDF, 0xFE, 0x7E, 0x03, 0xF0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03,
0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x7F, 0xFC, 0xFF, 0xF1, 0xFF, 0xC1, 0xFE,
0x00, 0x07, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F,
0x00, 0x1F, 0x00, 0x1F, 0x07, 0xFF, 0x1F, 0xFF, 0x3F, 0xFF, 0x7F, 0xFF,
0x7C, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
0xFC, 0x1F, 0x7E, 0x1F, 0x7F, 0xFF, 0x3F, 0xFF, 0x1F, 0xFF, 0x07, 0xFC,
0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0x7C, 0x3F, 0xF8, 0x1F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x04,
0x7F, 0xFE, 0x3F, 0xFE, 0x1F, 0xFE, 0x07, 0xF8, 0x0F, 0xE3, 0xFF, 0x7F,
0xE7, 0xFE, 0xFC, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xFF, 0xEF, 0xFE, 0xFF,
0xEF, 0xFE, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8,
0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x07, 0xF8, 0x3F, 0xFC,
0xFF, 0xFB, 0xFF, 0xF7, 0xC3, 0xFF, 0x87, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8,
0x3F, 0xF0, 0x7F, 0xF0, 0xFB, 0xFF, 0xF7, 0xFF, 0xE7, 0xFF, 0xC3, 0xFF,
0x80, 0x1F, 0x00, 0x3E, 0x40, 0xFD, 0xFF, 0xF3, 0xFF, 0xE7, 0xFF, 0x07,
0xF8, 0x00, 0x38, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0,
0x0F, 0x80, 0x3E, 0x00, 0xFF, 0xE3, 0xFF, 0xCF, 0xFF, 0xBF, 0xFE, 0xF8,
0xFF, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE,
0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0x77, 0xFF, 0xF7, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07,
0x07, 0xC3, 0xE1, 0xF0, 0x70, 0x00, 0x00, 0x00, 0x0F, 0x87, 0xC3, 0xE1,
0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C,
0x3E, 0x1F, 0x0F, 0x8F, 0xFF, 0xFF, 0xEF, 0xE7, 0xE0, 0x38, 0x01, 0xF0,
0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00,
0xF8, 0x7F, 0xF1, 0xFB, 0xE7, 0xE7, 0xDF, 0x8F, 0xFF, 0x1F, 0xFC, 0x3F,
0xF0, 0x7F, 0xC0, 0xFF, 0xC1, 0xFF, 0xC3, 0xFF, 0xC7, 0xDF, 0x8F, 0x9F,
0x9F, 0x1F, 0xBE, 0x3F, 0x7C, 0x3F, 0x38, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xFC, 0xFF, 0x7F, 0x7F, 0x1E, 0x3F, 0xC3, 0xF1, 0xFF, 0xFF, 0xF3,
0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0x8F, 0xC7, 0xFF, 0x0F, 0x87, 0xFE,
0x1F, 0x0F, 0xFC, 0x3E, 0x1F, 0xF8, 0x7C, 0x3F, 0xF0, 0xF8, 0x7F, 0xE1,
0xF0, 0xFF, 0xC3, 0xE1, 0xFF, 0x87, 0xC3, 0xFF, 0x0F, 0x87, 0xFE, 0x1F,
0x0F, 0xFC, 0x3E, 0x1F, 0x3F, 0xC3, 0xFF, 0xCF, 0xFF, 0xBF, 0xFE, 0xF8,
0xFF, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE,
0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0x07, 0xF0, 0x0F, 0xFE,
0x0F, 0xFF, 0x8F, 0xFF, 0xE7, 0xE3, 0xF7, 0xE0, 0xFF, 0xE0, 0x3F, 0xF0,
0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFF, 0x07, 0xEF, 0xC7, 0xE7, 0xFF, 0xF1,
0xFF, 0xF0, 0x7F, 0xF0, 0x0F, 0xE0, 0x3F, 0xE0, 0xFF, 0xF8, 0xFF, 0xFC,
0xFF, 0xFE, 0xF8, 0x7E, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
0xF8, 0x1F, 0xF8, 0x3F, 0xF8, 0x3E, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8,
0xFB, 0xF0, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00,
0xF8, 0x00, 0x03, 0xFE, 0x0F, 0xFF, 0xCF, 0xFF, 0xEF, 0xFF, 0xF7, 0xE0,
0xFF, 0xE0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFF,
0x03, 0xEF, 0xC1, 0xF7, 0xFF, 0xF9, 0xFF, 0xFC, 0x7F, 0xFE, 0x0F, 0xDF,
0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00,
0x7C, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x81, 0xF0, 0x3E, 0x07, 0xC0,
0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0x0F,
0xE1, 0xFF, 0x9F, 0xFD, 0xFF, 0xEF, 0x81, 0x7C, 0x03, 0xFF, 0xDF, 0xFE,
0x7F, 0xF9, 0xFF, 0xC0, 0x3F, 0x81, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0x8F,
0xF0, 0x38, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0xFE, 0xFF, 0xEF,
0xFE, 0xFF, 0xEF, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F,
0x80, 0xFC, 0x0F, 0xFE, 0x7F, 0xE3, 0xFF, 0x0F, 0xE0, 0xF8, 0x7F, 0xE1,
0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8,
0x7F, 0xE1, 0xFF, 0x87, 0xFF, 0x1F, 0x7F, 0xFD, 0xFF, 0xF3, 0xFF, 0xC3,
0xFC, 0xF8, 0x0F, 0xFE, 0x0F, 0xDF, 0x07, 0xCF, 0x83, 0xE7, 0xE3, 0xF1,
0xF1, 0xF0, 0xF8, 0xF8, 0x7E, 0xFC, 0x1F, 0x7C, 0x0F, 0xBE, 0x03, 0xFE,
0x01, 0xFF, 0x00, 0xFF, 0x00, 0x3F, 0x80, 0x1F, 0xC0, 0x07, 0xC0, 0xF8,
0x38, 0x1F, 0xF8, 0x3C, 0x1F, 0x7C, 0x7C, 0x3E, 0x7C, 0x7C, 0x3E, 0x7C,
0x7E, 0x3E, 0x3C, 0x7E, 0x3C, 0x3C, 0xFE, 0x3C, 0x3E, 0xEF, 0x7C, 0x1E,
0xEF, 0x78, 0x1E, 0xEF, 0x78, 0x1F, 0xE7, 0xF8, 0x0F, 0xC7, 0xF0, 0x0F,
0xC3, 0xF0, 0x0F, 0xC3, 0xF0, 0x07, 0x83, 0xE0, 0x07, 0x81, 0xE0, 0xFC,
0x1F, 0xBF, 0x1F, 0x8F, 0xDF, 0x87, 0xEF, 0xC1, 0xFF, 0xC0, 0x7F, 0xC0,
0x3F, 0xE0, 0x0F, 0xE0, 0x07, 0xF0, 0x07, 0xFC, 0x03, 0xFE, 0x03, 0xFF,
0x83, 0xF7, 0xE1, 0xFB, 0xF1, 0xF8, 0xFD, 0xF8, 0x3F, 0xF8, 0x0F, 0xFE,
0x0F, 0xDF, 0x07, 0xCF, 0x83, 0xE7, 0xE3, 0xF1, 0xF1, 0xF0, 0xF8, 0xF8,
0x7C, 0x78, 0x1F, 0x7C, 0x0F, 0xBE, 0x03, 0xDE, 0x01, 0xFF, 0x00, 0x7F,
0x00, 0x3F, 0x80, 0x0F, 0xC0, 0x07, 0xC0, 0x03, 0xE0, 0x03, 0xE0, 0x1F,
0xF0, 0x1F, 0xF0, 0x0F, 0xF0, 0x03, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x03, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF8, 0x1F, 0xC0,
0xFE, 0x03, 0xF0, 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x03, 0xE1, 0xFC, 0x3F, 0x8F, 0xF1, 0xF8, 0x3E, 0x07, 0xC0, 0xF8, 0x1F,
0x03, 0xE0, 0x7C, 0x0F, 0x83, 0xF1, 0xFC, 0x3F, 0x87, 0xF0, 0xFE, 0x07,
0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xF0,
0x7F, 0x87, 0xF0, 0xFE, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0x83,
0xF8, 0x7F, 0x83, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C,
0x0F, 0x81, 0xF8, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE3, 0xF0, 0x7C, 0x0F,
0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x07, 0xE3, 0xFC, 0x7F, 0x0F,
0xE1, 0xF0, 0x00, 0x1E, 0x06, 0x3F, 0x8F, 0x7F, 0xFF, 0xFF, 0xFE, 0xF1,
0xFC, 0x60, 0x78, 0xFF, 0xFF, 0xFF, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03,
0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03,
0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3F, 0xFF,
0xFF, 0xF0, 0x00, 0x77, 0xFF, 0xFF, 0xB8, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78,
0x03, 0xF8, 0x3F, 0xF3, 0xFF, 0xDF, 0xFE, 0x7E, 0x03, 0xF0, 0x0F, 0x80,
0x3E, 0x00, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x1F, 0xFF, 0x3F, 0xFC, 0x7F,
0xF0, 0x3F, 0x80, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x01, 0xFC,
0x0F, 0xFC, 0x3F, 0xF8, 0x7F, 0xE1, 0xF8, 0x43, 0xE0, 0x07, 0xC0, 0x0F,
0x80, 0x1F, 0x01, 0xFF, 0xE3, 0xFF, 0xC7, 0xFF, 0x8F, 0xFF, 0x03, 0xE0,
0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3F, 0xFC, 0xFF, 0xF9, 0xFF, 0xF3,
0xFF, 0xE0, 0x10, 0x04, 0x3C, 0x03, 0xBE, 0xFB, 0xEF, 0xFF, 0xE3, 0xFF,
0xE1, 0xF1, 0xF0, 0xF0, 0x78, 0x78, 0x3C, 0x3C, 0x1E, 0x1E, 0x0F, 0x0F,
0x8F, 0x87, 0xFF, 0xC7, 0xFF, 0xF7, 0xDF, 0x7D, 0xC0, 0x3C, 0x20, 0x08,
0xFC, 0x07, 0xEF, 0x80, 0xF9, 0xF8, 0x3F, 0x1F, 0x07, 0xC3, 0xF1, 0xF8,
0x3E, 0x7E, 0x07, 0xEF, 0x80, 0x7F, 0xF0, 0x07, 0xFC, 0x00, 0xFF, 0x80,
0xFF, 0xFE, 0x1F, 0xFF, 0xC3, 0xFF, 0xF8, 0x03, 0xE0, 0x00, 0x7C, 0x01,
0xFF, 0xFC, 0x3F, 0xFF, 0x87, 0xFF, 0xF0, 0x07, 0xC0, 0x00, 0xF8, 0x00,
0x1F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xF0, 0x7F, 0xF3, 0xFF, 0xDF, 0xFE,
0x7C, 0x09, 0xF0, 0x07, 0xE0, 0x0F, 0xE0, 0x3F, 0xE0, 0xFF, 0xE7, 0xFF,
0xBE, 0x7F, 0xF8, 0xFF, 0xE1, 0xFF, 0xC7, 0xFF, 0x9E, 0x7F, 0xF0, 0xFF,
0xC1, 0xFF, 0x01, 0xFE, 0x01, 0xF8, 0x03, 0xE6, 0x0F, 0x9F, 0xFE, 0xFF,
0xF3, 0xFF, 0xC3, 0xFC, 0x00, 0x70, 0xEF, 0x9F, 0xF9, 0xFF, 0x9F, 0x70,
0xE0, 0x01, 0xFC, 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xE0, 0x3E, 0x0F, 0x83,
0xC0, 0x1E, 0x3C, 0x7E, 0x79, 0xC7, 0xF9, 0xDE, 0x7F, 0x8F, 0xE7, 0xC0,
0x3F, 0x3C, 0x01, 0xF9, 0xE0, 0x0F, 0xCF, 0x00, 0x7E, 0x78, 0x03, 0xF3,
0xE0, 0x1F, 0xCF, 0xF1, 0xEE, 0x3F, 0xCE, 0x78, 0xFC, 0xF1, 0xE0, 0x0F,
0x07, 0xC1, 0xF0, 0x1F, 0xFF, 0x00, 0x7F, 0xF0, 0x00, 0xFE, 0x00, 0x7F,
0x1F, 0xE7, 0xFC, 0x0F, 0x01, 0xCF, 0xF7, 0xFF, 0xC7, 0xE1, 0xF8, 0x7F,
0xFD, 0xFF, 0x3F, 0x80, 0x00, 0x00, 0x0E, 0x0E, 0x1F, 0x1F, 0x1E, 0x1E,
0x3E, 0x3E, 0x7C, 0x7C, 0x7C, 0x7C, 0xF8, 0xF8, 0x7C, 0x7C, 0x7C, 0x7C,
0x3E, 0x3E, 0x1E, 0x1E, 0x1F, 0x1F, 0x0E, 0x0E, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80,
0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
0x01, 0xFC, 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xE0, 0x3E, 0x0F, 0x83, 0xC0,
0x1E, 0x3C, 0x00, 0x79, 0xC7, 0xE1, 0xDE, 0x3F, 0xCF, 0xE1, 0xCE, 0x3F,
0x0E, 0x71, 0xF8, 0x73, 0x8F, 0xC3, 0xF8, 0x7E, 0x1F, 0xC3, 0xF0, 0xEE,
0x1F, 0xC7, 0x39, 0xEE, 0x39, 0xCE, 0x78, 0x00, 0xF1, 0xE0, 0x0F, 0x07,
0xC1, 0xF0, 0x1F, 0xFF, 0x00, 0x7F, 0xF0, 0x00, 0xFE, 0x00, 0xFF, 0xFF,
0xFF, 0xFC, 0x3E, 0x3F, 0xBF, 0xFC, 0x7E, 0x3F, 0x1F, 0xFE, 0xFE, 0x3E,
0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x83, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80,
0x1E, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x3F,
0x3F, 0xEF, 0xFD, 0x87, 0x01, 0xC0, 0xF0, 0x78, 0x38, 0x1C, 0x0E, 0x07,
0xFD, 0xFF, 0x7F, 0xC0, 0x3C, 0x7F, 0x1F, 0xC8, 0xE0, 0x70, 0xF8, 0x7C,
0x3F, 0x03, 0x81, 0xFF, 0xFF, 0xE7, 0xE0, 0x08, 0x38, 0xFB, 0xEF, 0x8E,
0x08, 0x00, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1,
0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFF, 0x1F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E,
0x00, 0xF8, 0x03, 0xE0, 0x00, 0x00, 0xFE, 0x01, 0xFF, 0xFC, 0xFF, 0xFF,
0xBF, 0xFF, 0xF7, 0xFE, 0x3F, 0xFF, 0xC7, 0xFF, 0xF8, 0xFF, 0xFF, 0x1F,
0xFF, 0xE3, 0xFF, 0xFC, 0x7D, 0xFF, 0x8F, 0xBF, 0xF1, 0xF1, 0xFE, 0x3E,
0x0F, 0xC7, 0xC0, 0x78, 0xF8, 0x0F, 0x1F, 0x01, 0xE3, 0xE0, 0x3C, 0x7C,
0x07, 0x8F, 0x80, 0xF1, 0xF0, 0x1E, 0x3E, 0x03, 0xC7, 0xC0, 0x78, 0xF8,
0x0F, 0x1F, 0x01, 0xE3, 0xE0, 0x3C, 0x7C, 0x07, 0x8F, 0x80, 0xF1, 0xF0,
0x7B, 0xFF, 0xFF, 0xFD, 0xE0, 0x1E, 0x38, 0xF0, 0xF0, 0xEF, 0xDF, 0xBC,
0x0E, 0x3D, 0xFF, 0xF7, 0xE9, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE0,
0x1F, 0x83, 0xFC, 0x7F, 0xE7, 0x0E, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x07,
0xE0, 0x77, 0x0E, 0x7F, 0xE3, 0xFC, 0x1F, 0x80, 0x00, 0x00, 0x78, 0x78,
0xF8, 0xF8, 0x7C, 0x7C, 0x7C, 0x7C, 0x3E, 0x3E, 0x3E, 0x3E, 0x1F, 0x1F,
0x3E, 0x3E, 0x3E, 0x3E, 0x7C, 0x7C, 0x7C, 0x7C, 0xF8, 0xF8, 0x78, 0x78,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x07, 0x80, 0x3E, 0x07, 0xE0, 0x0F, 0x03,
0xF8, 0x07, 0xC0, 0x7E, 0x01, 0xE0, 0x13, 0x80, 0xF0, 0x00, 0xE0, 0x3C,
0x00, 0x38, 0x1E, 0x00, 0x0E, 0x07, 0x80, 0x03, 0x83, 0xC1, 0xE0, 0xE0,
0xF0, 0xF8, 0x38, 0x78, 0x3E, 0x0E, 0x1E, 0x1F, 0x80, 0x0F, 0x0E, 0xE0,
0x03, 0xC3, 0x38, 0x01, 0xE1, 0xFF, 0x00, 0x78, 0x7F, 0xC0, 0x3C, 0x1F,
0xF0, 0x0F, 0x00, 0x38, 0x07, 0x80, 0x0E, 0x03, 0xE0, 0x03, 0x80, 0xF0,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x07, 0x80, 0x7C, 0x07, 0xE0, 0x1E, 0x03,
0xF8, 0x0F, 0x80, 0x7E, 0x03, 0xC0, 0x13, 0x81, 0xE0, 0x00, 0xE0, 0x78,
0x00, 0x38, 0x3C, 0x00, 0x0E, 0x0F, 0x00, 0x03, 0x87, 0x8F, 0xC0, 0xE1,
0xEF, 0xF8, 0x38, 0xF3, 0xFF, 0x0E, 0x3C, 0x61, 0xC0, 0x1E, 0x00, 0x70,
0x07, 0x80, 0x3C, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x0E, 0x00, 0x78, 0x07,
0x00, 0x1E, 0x03, 0x80, 0x0F, 0x01, 0xFF, 0x07, 0xC0, 0x7F, 0xC1, 0xE0,
0x1F, 0xF0, 0x3C, 0x00, 0x00, 0x7F, 0x00, 0x7C, 0x1F, 0xC0, 0x3C, 0x08,
0xE0, 0x3E, 0x00, 0x70, 0x1E, 0x00, 0xF8, 0x1E, 0x00, 0x7C, 0x0F, 0x00,
0x3F, 0x0F, 0x00, 0x03, 0x87, 0x80, 0x01, 0xC7, 0x87, 0xBF, 0xE3, 0xC7,
0xDF, 0xE3, 0xC3, 0xE7, 0xE1, 0xE3, 0xF0, 0x01, 0xE3, 0xB8, 0x00, 0xF1,
0x9C, 0x00, 0xF1, 0xFF, 0x00, 0x78, 0xFF, 0x80, 0x78, 0x7F, 0xC0, 0x3C,
0x01, 0xC0, 0x3C, 0x00, 0xE0, 0x3E, 0x00, 0x70, 0x1E, 0x00, 0x00, 0x07,
0x80, 0xFC, 0x0F, 0xC0, 0xFC, 0x0F, 0xC0, 0x78, 0x00, 0x00, 0x00, 0x07,
0x80, 0x78, 0x0F, 0x81, 0xF0, 0x3F, 0x07, 0xE0, 0x7C, 0x0F, 0x80, 0xF8,
0x0F, 0x86, 0xFF, 0xE7, 0xFF, 0x7F, 0xF1, 0xFC, 0x00, 0x40, 0x00, 0x07,
0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x1C, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x7F,
0x80, 0x03, 0xFC, 0x00, 0x3F, 0xE0, 0x01, 0xFF, 0x80, 0x1F, 0x7C, 0x00,
0xFB, 0xF0, 0x07, 0xDF, 0x80, 0x7C, 0x7C, 0x03, 0xE3, 0xF0, 0x1F, 0x1F,
0x81, 0xF0, 0x7C, 0x0F, 0xFF, 0xE0, 0xFF, 0xFF, 0x87, 0xFF, 0xFC, 0x3F,
0xFF, 0xE3, 0xF0, 0x1F, 0x9F, 0x00, 0x7C, 0xF8, 0x03, 0xEF, 0xC0, 0x1F,
0xFC, 0x00, 0x7C, 0x00, 0x10, 0x00, 0x01, 0xC0, 0x00, 0x1F, 0x00, 0x01,
0xF0, 0x00, 0x1F, 0x00, 0x00, 0x70, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x7F, 0x80, 0x03, 0xFC, 0x00, 0x3F,
0xE0, 0x01, 0xFF, 0x80, 0x1F, 0x7C, 0x00, 0xFB, 0xF0, 0x07, 0xDF, 0x80,
0x7C, 0x7C, 0x03, 0xE3, 0xF0, 0x1F, 0x1F, 0x81, 0xF0, 0x7C, 0x0F, 0xFF,
0xE0, 0xFF, 0xFF, 0x87, 0xFF, 0xFC, 0x3F, 0xFF, 0xE3, 0xF0, 0x1F, 0x9F,
0x00, 0x7C, 0xF8, 0x03, 0xEF, 0xC0, 0x1F, 0xFC, 0x00, 0x7C, 0x00, 0x20,
0x00, 0x03, 0x80, 0x00, 0x3E, 0x00, 0x03, 0xF8, 0x00, 0x3D, 0xE0, 0x00,
0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x0F, 0xF0,
0x00, 0x7F, 0x80, 0x07, 0xFC, 0x00, 0x3F, 0xF0, 0x03, 0xEF, 0x80, 0x1F,
0x7E, 0x00, 0xFB, 0xF0, 0x0F, 0x8F, 0x80, 0x7C, 0x7E, 0x03, 0xE3, 0xF0,
0x3E, 0x0F, 0x81, 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0x87, 0xFF,
0xFC, 0x7E, 0x03, 0xF3, 0xE0, 0x0F, 0x9F, 0x00, 0x7D, 0xF8, 0x03, 0xFF,
0x80, 0x0F, 0x80, 0x01, 0xC6, 0x00, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x06,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80,
0x01, 0xFE, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x07, 0xFE, 0x00, 0x7D,
0xF0, 0x03, 0xEF, 0xC0, 0x1F, 0x7E, 0x01, 0xF1, 0xF0, 0x0F, 0x8F, 0xC0,
0x7C, 0x7E, 0x07, 0xC1, 0xF0, 0x3F, 0xFF, 0x83, 0xFF, 0xFE, 0x1F, 0xFF,
0xF0, 0xFF, 0xFF, 0x8F, 0xC0, 0x7E, 0x7C, 0x01, 0xF3, 0xE0, 0x0F, 0xBF,
0x00, 0x7F, 0xF0, 0x01, 0xF0, 0x07, 0x0E, 0x00, 0x7C, 0xF8, 0x03, 0xE7,
0xC0, 0x1F, 0x3E, 0x00, 0x70, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0x80, 0x07, 0xFC,
0x00, 0x3F, 0xF0, 0x03, 0xEF, 0x80, 0x1F, 0x7E, 0x00, 0xFB, 0xF0, 0x0F,
0x8F, 0x80, 0x7C, 0x7E, 0x03, 0xE3, 0xF0, 0x3E, 0x0F, 0x81, 0xFF, 0xFC,
0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0x87, 0xFF, 0xFC, 0x7E, 0x03, 0xF3, 0xE0,
0x0F, 0x9F, 0x00, 0x7D, 0xF8, 0x03, 0xFF, 0x80, 0x0F, 0x80, 0x00, 0x70,
0x00, 0x07, 0xC0, 0x00, 0x63, 0x00, 0x03, 0x18, 0x00, 0x18, 0xC0, 0x00,
0xFE, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0xC0, 0x01, 0xFE, 0x00, 0x1F, 0xF8,
0x00, 0xFF, 0xC0, 0x0F, 0xBE, 0x00, 0x7D, 0xF8, 0x03, 0xEF, 0xC0, 0x3E,
0x3E, 0x01, 0xF1, 0xF8, 0x1F, 0x8F, 0xC0, 0xF8, 0x3E, 0x07, 0xFF, 0xF8,
0x7F, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, 0xF1, 0xF8, 0x0F, 0xCF, 0x80,
0x3E, 0x7C, 0x01, 0xF7, 0xE0, 0x0F, 0xFE, 0x00, 0x3E, 0x00, 0x0F, 0xFF,
0xF8, 0x00, 0x7F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFE,
0x00, 0x3F, 0xF0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x0F, 0xDF, 0x00, 0x00,
0x3F, 0x7C, 0x00, 0x01, 0xF9, 0xFF, 0xF0, 0x07, 0xC7, 0xFF, 0xC0, 0x3F,
0x1F, 0xFF, 0x01, 0xF8, 0x7F, 0xFC, 0x07, 0xFF, 0xF0, 0x00, 0x3F, 0xFF,
0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x1F, 0x01, 0xF0,
0x00, 0xFC, 0x07, 0xFF, 0xF7, 0xE0, 0x1F, 0xFF, 0xDF, 0x80, 0x7F, 0xFF,
0xFC, 0x01, 0xFF, 0xFC, 0x01, 0xFC, 0x03, 0xFF, 0xC7, 0xFF, 0xE7, 0xFF,
0xE3, 0xF0, 0x33, 0xF0, 0x01, 0xF0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C,
0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xF0, 0x00,
0xFC, 0x00, 0x7F, 0x03, 0x1F, 0xFF, 0x87, 0xFF, 0xE1, 0xFF, 0xF0, 0x1F,
0xC0, 0x0F, 0x00, 0x07, 0x80, 0x00, 0xE0, 0x00, 0x70, 0x01, 0xF8, 0x00,
0xF8, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x07, 0x00, 0x0F, 0x80, 0x07, 0xC0,
0x03, 0xE0, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00,
0xF8, 0x00, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF8, 0x00,
0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0xC0,
0x0F, 0x80, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00,
0xF8, 0x00, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF8, 0x00,
0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x80, 0x07, 0xC0, 0x0F, 0xE0,
0x1E, 0xF0, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFE,
0xFF, 0xFE, 0xFF, 0xFE, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00,
0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF8, 0x00, 0xF8, 0x00,
0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x1C, 0x38, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x1C, 0x38,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
0xFF, 0xFE, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFC,
0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00,
0xF8, 0x00, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x20, 0xE3, 0xE3, 0xE3, 0xE3, 0x82, 0x00, 0x00, 0xF9, 0xF3, 0xE7, 0xCF,
0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3,
0xE7, 0xCF, 0x80, 0x08, 0x38, 0xFB, 0xEF, 0x8E, 0x08, 0x00, 0x00, 0xF9,
0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E,
0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x80, 0x08, 0x0E, 0x0F, 0x8F, 0xEF, 0x7A,
0x08, 0x00, 0x00, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C,
0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F,
0x87, 0xC3, 0xE0, 0x70, 0xEF, 0x9F, 0xF9, 0xFF, 0x9F, 0x70, 0xE0, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0,
0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0,
0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x00, 0x1F,
0xFC, 0x00, 0x7F, 0xFE, 0x01, 0xFF, 0xFE, 0x07, 0xFF, 0xFC, 0x1F, 0x07,
0xF0, 0x7C, 0x07, 0xE1, 0xF0, 0x0F, 0x87, 0xC0, 0x1F, 0xFF, 0xF0, 0x7F,
0xFF, 0xC1, 0xFF, 0xFF, 0x07, 0xFF, 0xFC, 0x1F, 0x1F, 0x00, 0x7C, 0x7C,
0x03, 0xF1, 0xF0, 0x0F, 0x87, 0xC0, 0x7E, 0x1F, 0x07, 0xF0, 0x7F, 0xFF,
0xC1, 0xFF, 0xFE, 0x07, 0xFF, 0xE0, 0x1F, 0xFC, 0x00, 0x03, 0x8C, 0x00,
0xFF, 0xC0, 0x3F, 0xF0, 0x03, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xC0, 0x1F, 0xFC, 0x03, 0xFF, 0xC0, 0x7F, 0xF8, 0x0F, 0xFF,
0x81, 0xFF, 0xF8, 0x3F, 0xFF, 0x87, 0xFF, 0xF8, 0xFF, 0xDF, 0x1F, 0xF9,
0xF3, 0xFF, 0x1F, 0x7F, 0xE3, 0xFF, 0xFC, 0x3F, 0xFF, 0x83, 0xFF, 0xF0,
0x3F, 0xFE, 0x07, 0xFF, 0xC0, 0x7F, 0xF8, 0x07, 0xFF, 0x00, 0xFF, 0xE0,
0x0F, 0xFC, 0x01, 0xF0, 0x00, 0x80, 0x00, 0x1C, 0x00, 0x03, 0xE0, 0x00,
0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x80, 0x0F, 0xFF, 0x01, 0xFF, 0xF8, 0x3F, 0xFF,
0xC3, 0xF0, 0xFC, 0x7E, 0x07, 0xE7, 0xC0, 0x3E, 0xF8, 0x01, 0xFF, 0x80,
0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8,
0x01, 0xF7, 0xC0, 0x3E, 0x7E, 0x07, 0xE7, 0xF0, 0xFE, 0x3F, 0xFF, 0xC1,
0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0x1F, 0xC0, 0x00, 0x10, 0x00, 0x03, 0x80,
0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x0F, 0xFF, 0x01, 0xFF,
0xF8, 0x3F, 0xFF, 0xC3, 0xF0, 0xFC, 0x7E, 0x07, 0xE7, 0xC0, 0x3E, 0xF8,
0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF,
0x80, 0x1F, 0xF8, 0x01, 0xF7, 0xC0, 0x3E, 0x7E, 0x07, 0xE7, 0xF0, 0xFE,
0x3F, 0xFF, 0xC1, 0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0x1F, 0xC0, 0x00, 0x40,
0x00, 0x0E, 0x00, 0x01, 0xF0, 0x00, 0x3F, 0x80, 0x07, 0xBC, 0x00, 0x20,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF8, 0x00, 0xFF, 0xF0, 0x1F,
0xFF, 0x83, 0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xE0, 0x7E, 0x7C, 0x03, 0xEF,
0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F,
0xF8, 0x01, 0xFF, 0x80, 0x1F, 0x7C, 0x03, 0xE7, 0xE0, 0x7E, 0x7F, 0x0F,
0xE3, 0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x01, 0xFC, 0x00, 0x01,
0xC6, 0x00, 0x3F, 0xF0, 0x07, 0xFE, 0x00, 0x31, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x0F, 0xFF, 0x01, 0xFF, 0xF8,
0x3F, 0xFF, 0xC3, 0xF0, 0xFC, 0x7E, 0x07, 0xE7, 0xC0, 0x3E, 0xF8, 0x01,
0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80,
0x1F, 0xF8, 0x01, 0xF7, 0xC0, 0x3E, 0x7E, 0x07, 0xE7, 0xF0, 0xFE, 0x3F,
0xFF, 0xC1, 0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0x1F, 0xC0, 0x07, 0x0E, 0x00,
0xF9, 0xF0, 0x0F, 0x9F, 0x00, 0xF9, 0xF0, 0x07, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF8, 0x00, 0xFF, 0xF0, 0x1F, 0xFF,
0x83, 0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xE0, 0x7E, 0x7C, 0x03, 0xEF, 0x80,
0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8,
0x01, 0xFF, 0x80, 0x1F, 0x7C, 0x03, 0xE7, 0xE0, 0x7E, 0x7F, 0x0F, 0xE3,
0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x01, 0xFC, 0x00, 0x20, 0x11,
0xC0, 0xEF, 0x87, 0xDF, 0x3E, 0x3F, 0xF0, 0x7F, 0x80, 0xFC, 0x03, 0xF0,
0x1F, 0xE0, 0xFF, 0xC7, 0xCF, 0xBE, 0x1F, 0x70, 0x38, 0x80, 0x40, 0x00,
0x00, 0x80, 0x1F, 0x8C, 0x0F, 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0xC3,
0xF0, 0xFC, 0x7E, 0x0F, 0xE7, 0xC1, 0xFE, 0xF8, 0x3D, 0xFF, 0x83, 0x9F,
0xF8, 0x79, 0xFF, 0x8F, 0x1F, 0xF9, 0xE1, 0xFF, 0xBC, 0x1F, 0xFB, 0xC1,
0xF7, 0xF8, 0x3E, 0x7F, 0x07, 0xE7, 0xF0, 0xFE, 0x3F, 0xFF, 0xC3, 0xFF,
0xF8, 0x7F, 0xFF, 0x07, 0x1F, 0xC0, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00,
0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x38, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F,
0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE,
0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80,
0x7F, 0xE0, 0x1F, 0xFC, 0x0F, 0xDF, 0x87, 0xE7, 0xFF, 0xF8, 0xFF, 0xFC,
0x1F, 0xFE, 0x01, 0xFE, 0x00, 0x00, 0x20, 0x00, 0x1C, 0x00, 0x0F, 0x80,
0x07, 0xC0, 0x03, 0xE0, 0x00, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01,
0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F,
0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xFC,
0x0F, 0xDF, 0x87, 0xE7, 0xFF, 0xF8, 0xFF, 0xFC, 0x1F, 0xFE, 0x01, 0xFE,
0x00, 0x00, 0x80, 0x00, 0x70, 0x00, 0x3E, 0x00, 0x1F, 0xC0, 0x0F, 0x78,
0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0xFE, 0x01, 0xFF,
0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0,
0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07,
0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xF0, 0x3F, 0x7E, 0x1F, 0x9F, 0xFF, 0xE3,
0xFF, 0xF0, 0x7F, 0xF8, 0x07, 0xF8, 0x00, 0x0E, 0x1C, 0x07, 0xCF, 0x81,
0xF3, 0xE0, 0x7C, 0xF8, 0x0E, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07,
0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF,
0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xF0,
0x3F, 0x7E, 0x1F, 0x9F, 0xFF, 0xE3, 0xFF, 0xF0, 0x7F, 0xF8, 0x07, 0xF8,
0x00, 0x00, 0x08, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00,
0x0F, 0x80, 0x00, 0x38, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0xE0, 0x0F, 0xDF, 0x00, 0xFC, 0xFC, 0x07, 0xE3, 0xF0, 0x7E, 0x0F,
0x83, 0xE0, 0x7E, 0x3F, 0x01, 0xFB, 0xF0, 0x0F, 0xDF, 0x80, 0x3F, 0xF8,
0x00, 0xFF, 0x80, 0x07, 0xFC, 0x00, 0x1F, 0xC0, 0x00, 0x7C, 0x00, 0x03,
0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00,
0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x7C, 0x00,
0x3E, 0x00, 0x1F, 0xFE, 0x0F, 0xFF, 0xC7, 0xFF, 0xF3, 0xFF, 0xFD, 0xF0,
0x7F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x83, 0xFF,
0xFF, 0xFB, 0xFF, 0xF9, 0xFF, 0xF8, 0xFF, 0xF0, 0x7C, 0x00, 0x3E, 0x00,
0x1F, 0x00, 0x0F, 0x80, 0x00, 0x0F, 0xE0, 0x1F, 0xF8, 0x1F, 0xFE, 0x0F,
0xFF, 0x8F, 0xC7, 0xC7, 0xC3, 0xE3, 0xE1, 0xF1, 0xF0, 0xF8, 0xF8, 0xF8,
0x7C, 0x7C, 0x3E, 0x7C, 0x1F, 0x3E, 0x0F, 0x9F, 0x07, 0xCF, 0xE3, 0xE3,
0xF9, 0xF0, 0xFE, 0xF8, 0x1F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x21, 0xFF,
0x9F, 0xFF, 0xCF, 0xFB, 0xE7, 0xFD, 0xF3, 0xF8, 0x04, 0x00, 0x38, 0x01,
0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x7F, 0x83, 0xFF, 0x0F, 0xFE, 0x3F, 0xFC, 0x03, 0xF0, 0x07, 0xC7, 0xFF,
0x7F, 0xFD, 0xFF, 0xFF, 0xC7, 0xFE, 0x1F, 0xF8, 0x7F, 0xFF, 0xF7, 0xFF,
0xDF, 0xFF, 0x1F, 0xF8, 0x00, 0x80, 0x07, 0x00, 0x3E, 0x01, 0xF0, 0x0F,
0x80, 0x1C, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x83, 0xFF, 0x0F,
0xFE, 0x3F, 0xFC, 0x03, 0xF0, 0x07, 0xC7, 0xFF, 0x7F, 0xFD, 0xFF, 0xFF,
0xC7, 0xFE, 0x1F, 0xF8, 0x7F, 0xFF, 0xF7, 0xFF, 0xDF, 0xFF, 0x1F, 0xF8,
0x02, 0x00, 0x1C, 0x00, 0xF8, 0x07, 0xF0, 0x3D, 0xE0, 0x41, 0x00, 0x00,
0x00, 0x00, 0x1F, 0xE0, 0xFF, 0xC3, 0xFF, 0x8F, 0xFF, 0x00, 0xFC, 0x01,
0xF1, 0xFF, 0xDF, 0xFF, 0x7F, 0xFF, 0xF1, 0xFF, 0x87, 0xFE, 0x1F, 0xFF,
0xFD, 0xFF, 0xF7, 0xFF, 0xC7, 0xFE, 0x0E, 0x30, 0x7F, 0xE3, 0xFF, 0x06,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x3F, 0xF0, 0xFF, 0xE3,
0xFF, 0xC0, 0x3F, 0x00, 0x7C, 0x7F, 0xF7, 0xFF, 0xDF, 0xFF, 0xFC, 0x7F,
0xE1, 0xFF, 0x87, 0xFF, 0xFF, 0x7F, 0xFD, 0xFF, 0xF1, 0xFF, 0x80, 0x38,
0x71, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1F, 0xE0, 0xFF, 0xC3, 0xFF, 0x8F, 0xFF, 0x00, 0xFC, 0x01, 0xF1,
0xFF, 0xDF, 0xFF, 0x7F, 0xFF, 0xF1, 0xFF, 0x87, 0xFE, 0x1F, 0xFF, 0xFD,
0xFF, 0xF7, 0xFF, 0xC7, 0xFE, 0x03, 0x80, 0x1F, 0x00, 0xC6, 0x03, 0x18,
0x0C, 0x60, 0x1F, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x83, 0xFF,
0x0F, 0xFE, 0x3F, 0xFC, 0x03, 0xF0, 0x07, 0xC7, 0xFF, 0x7F, 0xFD, 0xFF,
0xFF, 0xC7, 0xFE, 0x1F, 0xF8, 0x7F, 0xFF, 0xF7, 0xFF, 0xDF, 0xFF, 0x1F,
0xF8, 0x1F, 0xE1, 0xF8, 0x1F, 0xFB, 0xFF, 0x0F, 0xFF, 0xFF, 0xC7, 0xFF,
0xFF, 0xE2, 0x07, 0xF1, 0xF8, 0x01, 0xF0, 0x7C, 0x3F, 0xFF, 0xFE, 0x7F,
0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFE, 0x1F, 0x00, 0x3E, 0x0F, 0xC0, 0x1F,
0x83, 0xF0, 0x0F, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFC,
0x1F, 0xC3, 0xF8, 0x03, 0xF8, 0x7F, 0xF3, 0xFF, 0x9F, 0xFE, 0x7E, 0x0B,
0xF0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x80,
0x3F, 0xFC, 0x7F, 0xF0, 0xFF, 0xC0, 0x7E, 0x03, 0xC0, 0x03, 0x80, 0x0E,
0x03, 0xF8, 0x0F, 0xC0, 0x3E, 0x00, 0x02, 0x00, 0x07, 0x00, 0x0F, 0x80,
0x07, 0xC0, 0x03, 0xE0, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0x7C, 0x3F, 0xF8, 0x1F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x04,
0x7F, 0xFE, 0x3F, 0xFE, 0x1F, 0xFE, 0x07, 0xF8, 0x00, 0x40, 0x00, 0xE0,
0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0x7C, 0x3F,
0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFC, 0x00,
0x7E, 0x04, 0x7F, 0xFE, 0x3F, 0xFE, 0x1F, 0xFE, 0x07, 0xF8, 0x01, 0x00,
0x03, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x1E, 0xF0, 0x08, 0x20, 0x00, 0x00,
0x00, 0x00, 0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0x7C, 0x3F,
0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFC, 0x00,
0x7E, 0x04, 0x7F, 0xFE, 0x3F, 0xFE, 0x1F, 0xFE, 0x07, 0xF8, 0x1C, 0x38,
0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x1C, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0x7C, 0x3F,
0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFC, 0x00,
0x7E, 0x04, 0x7F, 0xFE, 0x3F, 0xFE, 0x1F, 0xFE, 0x07, 0xF8, 0x20, 0xE3,
0xE3, 0xE3, 0xE3, 0x82, 0x00, 0x00, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E,
0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0x08, 0x38, 0xFB, 0xEF,
0x8E, 0x08, 0x00, 0x00, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9,
0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0x08, 0x0E, 0x0F, 0x8F, 0xEF, 0x7A,
0x08, 0x00, 0x00, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C,
0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x70, 0xEF, 0x9F,
0xF9, 0xFF, 0x9F, 0x70, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0xF8,
0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8,
0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x00, 0x80, 0x00,
0xF0, 0x00, 0xFC, 0x60, 0x3F, 0xF0, 0x0F, 0xF8, 0x1F, 0xF0, 0x0F, 0xF8,
0x07, 0x3E, 0x00, 0x1F, 0x03, 0xF7, 0x87, 0xFF, 0xE7, 0xFF, 0xF7, 0xFF,
0xFF, 0xE0, 0xFF, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE,
0x07, 0xCF, 0x87, 0xE7, 0xFF, 0xE1, 0xFF, 0xF0, 0x7F, 0xF0, 0x0F, 0xE0,
0x0E, 0x30, 0x7F, 0xE3, 0xFF, 0x06, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0xF0, 0xFF, 0xF3, 0xFF, 0xEF, 0xFF, 0xBE, 0x3F, 0xF8, 0x7F, 0xE1,
0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8,
0x7F, 0xE1, 0xFF, 0x87, 0xC0, 0x01, 0x00, 0x01, 0xC0, 0x01, 0xF0, 0x00,
0x7C, 0x00, 0x1F, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xF8, 0x07, 0xFF, 0x07, 0xFF, 0xC7, 0xFF, 0xF3, 0xF1, 0xFB, 0xF0,
0x7F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x83, 0xF7,
0xE3, 0xF3, 0xFF, 0xF8, 0xFF, 0xF8, 0x3F, 0xF8, 0x07, 0xF0, 0x00, 0x00,
0x40, 0x00, 0x70, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x1C, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF8, 0x07, 0xFF, 0x07, 0xFF,
0xC7, 0xFF, 0xF3, 0xF1, 0xFB, 0xF0, 0x7F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC,
0x07, 0xFE, 0x03, 0xFF, 0x83, 0xF7, 0xE3, 0xF3, 0xFF, 0xF8, 0xFF, 0xF8,
0x3F, 0xF8, 0x07, 0xF0, 0x00, 0x00, 0x80, 0x00, 0xE0, 0x00, 0xF8, 0x00,
0xFE, 0x00, 0xF7, 0x80, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0,
0x0F, 0xFE, 0x0F, 0xFF, 0x8F, 0xFF, 0xE7, 0xE3, 0xF7, 0xE0, 0xFF, 0xE0,
0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFF, 0x07, 0xEF, 0xC7, 0xE7,
0xFF, 0xF1, 0xFF, 0xF0, 0x7F, 0xF0, 0x0F, 0xE0, 0x07, 0x18, 0x07, 0xFE,
0x07, 0xFE, 0x01, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
0xE0, 0x1F, 0xFC, 0x1F, 0xFF, 0x1F, 0xFF, 0xCF, 0xC7, 0xEF, 0xC1, 0xFF,
0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFE, 0x0F, 0xDF, 0x8F,
0xCF, 0xFF, 0xE3, 0xFF, 0xE0, 0xFF, 0xE0, 0x1F, 0xC0, 0x0E, 0x1C, 0x0F,
0x9F, 0x07, 0xCF, 0x83, 0xE7, 0xC0, 0xE1, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x8F, 0xFF, 0xE7, 0xE3,
0xF7, 0xE0, 0xFF, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFF,
0x07, 0xEF, 0xC7, 0xE7, 0xFF, 0xF1, 0xFF, 0xF0, 0x7F, 0xF0, 0x0F, 0xE0,
0x03, 0x80, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x38, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x70, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x07, 0x00, 0x00, 0x02,
0x03, 0xFB, 0x87, 0xFF, 0xC7, 0xFF, 0xC7, 0xFF, 0xF3, 0xF1, 0xFB, 0xF1,
0xFF, 0xF1, 0xFF, 0xF9, 0xEF, 0xFD, 0xE7, 0xFF, 0xE3, 0xFF, 0xE3, 0xF7,
0xE3, 0xF3, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF8, 0x77, 0xF0, 0x10, 0x00,
0x00, 0x04, 0x00, 0x38, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0E, 0x00,
0x10, 0x00, 0x00, 0x00, 0x03, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F,
0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F,
0xFC, 0x7D, 0xFF, 0xF7, 0xFF, 0xCF, 0xFF, 0x0F, 0xF0, 0x00, 0x80, 0x07,
0x00, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x1C, 0x00, 0x20, 0x00, 0x00, 0x00,
0x03, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE,
0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xFC, 0x7D, 0xFF, 0xF7,
0xFF, 0xCF, 0xFF, 0x0F, 0xF0, 0x01, 0x00, 0x0E, 0x00, 0x7C, 0x03, 0xF8,
0x1E, 0xF0, 0x20, 0x80, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0xE1, 0xFF, 0x87,
0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1,
0xFF, 0x87, 0xFF, 0x1F, 0x7F, 0xFD, 0xFF, 0xF3, 0xFF, 0xC3, 0xFC, 0x38,
0x71, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF,
0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFF, 0x1F, 0x7F, 0xFD,
0xFF, 0xF3, 0xFF, 0xC3, 0xFC, 0x00, 0x20, 0x00, 0x38, 0x00, 0x3E, 0x00,
0x3E, 0x00, 0x3E, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7C, 0x07, 0xFF, 0x07, 0xEF, 0x83, 0xE7, 0xC1, 0xF3, 0xF1, 0xF8, 0xF8,
0xF8, 0x7C, 0x7C, 0x3E, 0x3C, 0x0F, 0xBE, 0x07, 0xDF, 0x01, 0xEF, 0x00,
0xFF, 0x80, 0x3F, 0x80, 0x1F, 0xC0, 0x07, 0xE0, 0x03, 0xE0, 0x01, 0xF0,
0x01, 0xF0, 0x0F, 0xF8, 0x0F, 0xF8, 0x07, 0xF8, 0x01, 0xF0, 0x00, 0x38,
0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0xFF, 0xE0, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xFE, 0xF8,
0x7E, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
0x3F, 0xF8, 0x3E, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8, 0xFB, 0xF0, 0xF8,
0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x0E,
0x1C, 0x0F, 0x9F, 0x07, 0xCF, 0x83, 0xE7, 0xC0, 0xE1, 0xC0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0xFE, 0x0F, 0xDF, 0x07, 0xCF, 0x83,
0xE7, 0xE3, 0xF1, 0xF1, 0xF0, 0xF8, 0xF8, 0x7C, 0x78, 0x1F, 0x7C, 0x0F,
0xBE, 0x03, 0xDE, 0x01, 0xFF, 0x00, 0x7F, 0x00, 0x3F, 0x80, 0x0F, 0xC0,
0x07, 0xC0, 0x03, 0xE0, 0x03, 0xE0, 0x1F, 0xF0, 0x1F, 0xF0, 0x0F, 0xF0,
0x03, 0xE0, 0x00 };
const GFXglyph Ubuntu_Bold16pt8bGlyphs[] PROGMEM = {
{ 0, 1, 1, 7, 0, 0 }, // 0x20 ' ' U+0020
{ 1, 5, 21, 9, 2, -20 }, // 0x21 '!' U+0021
{ 15, 12, 9, 14, 2, -23 }, // 0x22 '"' U+0022
{ 29, 18, 21, 22, 2, -20 }, // 0x23 '#' U+0023
{ 77, 16, 28, 18, 1, -23 }, // 0x24 '$' U+0024
{ 133, 26, 21, 28, 1, -20 }, // 0x25 '%' U+0025
{ 202, 21, 21, 22, 1, -20 }, // 0x26 '&' U+0026
{ 258, 5, 9, 9, 2, -23 }, // 0x27 ''' U+0027
{ 264, 9, 30, 11, 2, -23 }, // 0x28 '(' U+0028
{ 298, 9, 30, 11, 0, -23 }, // 0x29 ')' U+0029
{ 332, 13, 12, 16, 2, -20 }, // 0x2a '*' U+002A
{ 352, 14, 14, 18, 2, -15 }, // 0x2b '+' U+002B
{ 377, 6, 10, 8, 1, -4 }, // 0x2c ',' U+002C
{ 385, 9, 4, 11, 1, -10 }, // 0x2d '-' U+002D
{ 390, 6, 6, 8, 1, -5 }, // 0x2e '.' U+002E
{ 395, 15, 30, 14, -1, -23 }, // 0x2f '/' U+002F
{ 452, 16, 21, 18, 1, -20 }, // 0x30 '0' U+0030
{ 494, 10, 21, 18, 3, -20 }, // 0x31 '1' U+0031
{ 521, 15, 21, 18, 1, -20 }, // 0x32 '2' U+0032
{ 561, 15, 21, 18, 1, -20 }, // 0x33 '3' U+0033
{ 601, 16, 21, 18, 1, -20 }, // 0x34 '4' U+0034
{ 643, 15, 21, 18, 1, -20 }, // 0x35 '5' U+0035
{ 683, 16, 21, 18, 1, -20 }, // 0x36 '6' U+0036
{ 725, 16, 21, 18, 1, -20 }, // 0x37 '7' U+0037
{ 767, 16, 21, 18, 1, -20 }, // 0x38 '8' U+0038
{ 809, 16, 21, 18, 1, -20 }, // 0x39 '9' U+0039
{ 851, 6, 17, 8, 1, -16 }, // 0x3a ':' U+003A
{ 864, 6, 22, 8, 1, -16 }, // 0x3b ';' U+003B
{ 881, 15, 15, 18, 1, -16 }, // 0x3c '<' U+003C
{ 910, 15, 11, 18, 1, -14 }, // 0x3d '=' U+003D
{ 931, 14, 15, 18, 2, -16 }, // 0x3e '>' U+003E
{ 958, 12, 24, 14, 1, -23 }, // 0x3f '?' U+003F
{ 994, 26, 27, 30, 2, -21 }, // 0x40 '@' U+0040
{ 1082, 21, 21, 21, 0, -20 }, // 0x41 'A' U+0041
{ 1138, 17, 21, 21, 2, -20 }, // 0x42 'B' U+0042
{ 1183, 17, 21, 20, 2, -20 }, // 0x43 'C' U+0043
{ 1228, 19, 21, 23, 2, -20 }, // 0x44 'D' U+0044
{ 1278, 16, 21, 19, 2, -20 }, // 0x45 'E' U+0045
{ 1320, 15, 21, 18, 2, -20 }, // 0x46 'F' U+0046
{ 1360, 18, 21, 22, 2, -20 }, // 0x47 'G' U+0047
{ 1408, 19, 21, 23, 2, -20 }, // 0x48 'H' U+0048
{ 1458, 5, 21, 9, 2, -20 }, // 0x49 'I' U+0049
{ 1472, 14, 21, 16, 0, -20 }, // 0x4a 'J' U+004A
{ 1509, 19, 21, 21, 2, -20 }, // 0x4b 'K' U+004B
{ 1559, 14, 21, 17, 2, -20 }, // 0x4c 'L' U+004C
{ 1596, 24, 21, 28, 2, -20 }, // 0x4d 'M' U+004D
{ 1659, 19, 21, 23, 2, -20 }, // 0x4e 'N' U+004E
{ 1709, 20, 21, 24, 2, -20 }, // 0x4f 'O' U+004F
{ 1762, 17, 21, 20, 2, -20 }, // 0x50 'P' U+0050
{ 1807, 20, 27, 24, 2, -20 }, // 0x51 'Q' U+0051
{ 1875, 18, 21, 21, 2, -20 }, // 0x52 'R' U+0052
{ 1923, 16, 21, 18, 1, -20 }, // 0x53 'S' U+0053
{ 1965, 17, 21, 19, 1, -20 }, // 0x54 'T' U+0054
{ 2010, 18, 21, 22, 2, -20 }, // 0x55 'U' U+0055
{ 2058, 21, 21, 21, 0, -20 }, // 0x56 'V' U+0056
{ 2114, 29, 21, 31, 1, -20 }, // 0x57 'W' U+0057
{ 2191, 21, 21, 21, 0, -20 }, // 0x58 'X' U+0058
{ 2247, 21, 21, 21, 0, -20 }, // 0x59 'Y' U+0059
{ 2303, 17, 21, 19, 1, -20 }, // 0x5a 'Z' U+005A
{ 2348, 10, 30, 12, 2, -23 }, // 0x5b '[' U+005B
{ 2386, 15, 30, 14, -1, -23 }, // 0x5c '\' U+005C
{ 2443, 10, 30, 12, 0, -23 }, // 0x5d ']' U+005D
{ 2481, 17, 13, 19, 1, -21 }, // 0x5e '^' U+005E
{ 2509, 16, 4, 16, 0, 3 }, // 0x5f '_' U+005F
{ 2517, 7, 7, 9, 1, -24 }, // 0x60 '`' U+0060
{ 2524, 14, 16, 17, 1, -15 }, // 0x61 'a' U+0061
{ 2552, 16, 24, 19, 2, -23 }, // 0x62 'b' U+0062
{ 2600, 14, 16, 16, 1, -15 }, // 0x63 'c' U+0063
{ 2628, 16, 24, 19, 1, -23 }, // 0x64 'd' U+0064
{ 2676, 16, 16, 18, 1, -15 }, // 0x65 'e' U+0065
{ 2708, 12, 24, 14, 2, -23 }, // 0x66 'f' U+0066
{ 2744, 15, 22, 18, 1, -15 }, // 0x67 'g' U+0067
{ 2786, 14, 24, 18, 2, -23 }, // 0x68 'h' U+0068
{ 2828, 5, 24, 9, 2, -23 }, // 0x69 'i' U+0069
{ 2843, 9, 30, 9, -2, -23 }, // 0x6a 'j' U+006A
{ 2877, 15, 24, 18, 2, -23 }, // 0x6b 'k' U+006B
{ 2922, 8, 24, 10, 2, -23 }, // 0x6c 'l' U+006C
{ 2946, 23, 16, 27, 2, -15 }, // 0x6d 'm' U+006D
{ 2992, 14, 16, 18, 2, -15 }, // 0x6e 'n' U+006E
{ 3020, 17, 16, 19, 1, -15 }, // 0x6f 'o' U+006F
{ 3054, 16, 22, 19, 2, -15 }, // 0x70 'p' U+0070
{ 3098, 17, 22, 19, 1, -15 }, // 0x71 'q' U+0071
{ 3145, 11, 16, 13, 2, -15 }, // 0x72 'r' U+0072
{ 3167, 13, 16, 15, 1, -15 }, // 0x73 's' U+0073
{ 3193, 12, 21, 15, 2, -20 }, // 0x74 't' U+0074
{ 3225, 14, 16, 18, 2, -15 }, // 0x75 'u' U+0075
{ 3253, 17, 16, 17, 0, -15 }, // 0x76 'v' U+0076
{ 3287, 24, 16, 24, 0, -15 }, // 0x77 'w' U+0077
{ 3335, 17, 16, 17, 0, -15 }, // 0x78 'x' U+0078
{ 3369, 17, 22, 17, 0, -15 }, // 0x79 'y' U+0079
{ 3416, 14, 16, 16, 1, -15 }, // 0x7a 'z' U+007A
{ 3444, 11, 30, 12, 1, -23 }, // 0x7b '{' U+007B
{ 3486, 4, 30, 10, 3, -23 }, // 0x7c '|' U+007C
{ 3501, 11, 30, 12, 0, -23 }, // 0x7d '}' U+007D
{ 3543, 16, 6, 18, 1, -11 }, // 0x7e '~' U+007E
{ 3555, 12, 23, 16, 2, -22 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
{ 3590, 1, 1, 7, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
{ 3591, 5, 22, 9, 2, -15 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
{ 3605, 14, 23, 18, 1, -19 }, // 0x82 'CENT SIGN' U+00A2
{ 3646, 15, 21, 18, 1, -20 }, // 0x83 'POUND SIGN' U+00A3
{ 3686, 17, 16, 18, 0, -18 }, // 0x84 'CURRENCY SIGN' U+00A4
{ 3720, 19, 21, 19, 0, -20 }, // 0x85 'YEN SIGN' U+00A5
{ 3770, 4, 30, 9, 2, -23 }, // 0x86 'BROKEN BAR' U+00A6
{ 3785, 14, 27, 16, 1, -20 }, // 0x87 'SECTION SIGN' U+00A7
{ 3833, 12, 5, 17, 2, -23 }, // 0x88 'DIAERESIS' U+00A8
{ 3841, 21, 22, 25, 2, -21 }, // 0x89 'COPYRIGHT SIGN' U+00A9
{ 3899, 10, 13, 12, 1, -21 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
{ 3916, 16, 15, 19, 1, -15 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
{ 3946, 15, 11, 18, 2, -12 }, // 0x8c 'NOT SIGN' U+00AC
{ 3967, 9, 4, 11, 1, -10 }, // 0x8d 'SOFT HYPHEN' U+00AD
{ 3972, 21, 22, 25, 2, -21 }, // 0x8e 'REGISTERED SIGN' U+00AE
{ 4030, 10, 3, 12, 1, -21 }, // 0x8f 'MACRON' U+00AF
{ 4034, 9, 9, 11, 1, -23 }, // 0x90 'DEGREE SIGN' U+00B0
{ 4045, 14, 19, 18, 2, -18 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
{ 4079, 10, 13, 11, 0, -21 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
{ 4096, 9, 13, 11, 1, -21 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
{ 4111, 7, 7, 9, 1, -24 }, // 0x94 'ACUTE ACCENT' U+00B4
{ 4118, 14, 22, 18, 2, -15 }, // 0x95 'MICRO SIGN' U+00B5
{ 4157, 19, 28, 22, 1, -21 }, // 0x96 'PILCROW SIGN' U+00B6
{ 4224, 6, 6, 8, 1, -12 }, // 0x97 'MIDDLE DOT' U+00B7
{ 4229, 7, 8, 10, 1, 0 }, // 0x98 'CEDILLA' U+00B8
{ 4236, 7, 13, 11, 1, -21 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
{ 4248, 12, 13, 14, 1, -21 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
{ 4268, 16, 15, 19, 1, -15 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
{ 4298, 26, 22, 27, 0, -21 }, // 0x9c 'VULGAR FRACTION ONE QUARTER' U+00BC
{ 4370, 26, 22, 27, 0, -21 }, // 0x9d 'VULGAR FRACTION ONE HALF' U+00BD
{ 4442, 25, 22, 27, 1, -21 }, // 0x9e 'VULGAR FRACTION THREE QUARTERS' U+00BE
{ 4511, 12, 22, 14, 1, -15 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
{ 4544, 21, 30, 21, 0, -29 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
{ 4623, 21, 30, 21, 0, -29 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
{ 4702, 21, 29, 21, 0, -28 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
{ 4779, 21, 28, 21, 0, -27 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
{ 4853, 21, 29, 21, 0, -28 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
{ 4930, 21, 27, 21, 0, -26 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
{ 5001, 30, 21, 31, 0, -20 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
{ 5080, 17, 28, 20, 2, -20 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
{ 5140, 16, 30, 19, 2, -29 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
{ 5200, 16, 30, 19, 2, -29 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
{ 5260, 16, 29, 19, 2, -28 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
{ 5318, 16, 29, 19, 2, -28 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
{ 5376, 7, 30, 9, 1, -29 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
{ 5403, 7, 30, 9, 1, -29 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
{ 5430, 9, 29, 9, 0, -28 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
{ 5463, 12, 29, 9, -1, -28 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
{ 5507, 22, 21, 23, -1, -20 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
{ 5565, 19, 28, 23, 2, -27 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
{ 5632, 20, 30, 24, 2, -29 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
{ 5707, 20, 30, 24, 2, -29 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
{ 5782, 20, 29, 24, 2, -28 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
{ 5855, 20, 28, 24, 2, -27 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
{ 5925, 20, 29, 24, 2, -28 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
{ 5998, 14, 14, 18, 2, -15 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
{ 6023, 20, 23, 24, 2, -21 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
{ 6081, 18, 30, 22, 2, -29 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
{ 6149, 18, 30, 22, 2, -29 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
{ 6217, 18, 29, 22, 2, -28 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
{ 6283, 18, 29, 22, 2, -28 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
{ 6349, 21, 30, 21, 0, -29 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
{ 6428, 17, 21, 20, 2, -20 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
{ 6473, 17, 24, 20, 2, -23 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
{ 6524, 14, 25, 17, 1, -24 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
{ 6568, 14, 25, 17, 1, -24 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
{ 6612, 14, 24, 17, 1, -23 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
{ 6654, 14, 23, 17, 1, -22 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
{ 6695, 14, 24, 17, 1, -23 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
{ 6737, 14, 25, 17, 1, -24 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
{ 6781, 25, 16, 27, 1, -15 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
{ 6831, 14, 22, 16, 1, -15 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
{ 6870, 16, 25, 18, 1, -24 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
{ 6920, 16, 25, 18, 1, -24 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
{ 6970, 16, 24, 18, 1, -23 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
{ 7018, 16, 24, 18, 1, -23 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
{ 7066, 7, 25, 9, 1, -24 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
{ 7088, 7, 25, 9, 1, -24 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
{ 7110, 9, 24, 9, 0, -23 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
{ 7137, 12, 24, 9, -2, -23 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
{ 7173, 17, 24, 19, 1, -23 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
{ 7224, 14, 23, 18, 2, -22 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
{ 7265, 17, 25, 19, 1, -24 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
{ 7319, 17, 25, 19, 1, -24 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
{ 7373, 17, 24, 19, 1, -23 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
{ 7424, 17, 23, 19, 1, -22 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
{ 7473, 17, 24, 19, 1, -23 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
{ 7524, 15, 18, 19, 2, -17 }, // 0xd7 'DIVISION SIGN' U+00F7
{ 7558, 17, 18, 19, 1, -16 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
{ 7597, 14, 25, 18, 2, -24 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
{ 7641, 14, 25, 18, 2, -24 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
{ 7685, 14, 24, 18, 2, -23 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
{ 7727, 14, 24, 18, 2, -23 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
{ 7769, 17, 31, 17, 0, -24 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
{ 7835, 16, 30, 19, 2, -23 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
{ 7895, 17, 30, 17, 0, -23 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
const GFXfont Ubuntu_Bold16pt8b PROGMEM = {
(uint8_t *)Ubuntu_Bold16pt8bBitmaps,
(GFXglyph *)Ubuntu_Bold16pt8bGlyphs,
0x20, 0xDF, 36 };
// Approx. 9310 bytes

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,377 +0,0 @@
const uint8_t Ubuntu_Bold8pt8bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFC, 0xFC, 0xDE, 0xF7, 0xBD, 0x80, 0x1B, 0x0D, 0x87, 0xDF,
0xFF, 0xF9, 0xB3, 0xFF, 0xFF, 0x6C, 0x36, 0x1B, 0x00, 0x18, 0x30, 0xFF,
0xFC, 0x38, 0x1C, 0x1E, 0x0E, 0x0C, 0x1F, 0xF7, 0xC3, 0x06, 0x00, 0x78,
0x63, 0xF3, 0x0C, 0xCC, 0x33, 0x60, 0xCF, 0xFB, 0xFF, 0xF7, 0xFC, 0xC1,
0xB3, 0x0C, 0xCC, 0x33, 0xF1, 0x87, 0x80, 0x3C, 0x1F, 0x86, 0x61, 0x98,
0x3C, 0x1E, 0x6C, 0xDB, 0x1C, 0xC7, 0x3F, 0xE7, 0xDC, 0xFF, 0xC0, 0x13,
0x66, 0xCC, 0xCC, 0xCC, 0xCC, 0x66, 0x31, 0x8C, 0x66, 0x33, 0x33, 0x33,
0x33, 0x66, 0xC8, 0x39, 0xFF, 0xF8, 0x86, 0xDD, 0xD1, 0x00, 0x18, 0x18,
0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x6D, 0xEC, 0xFF, 0xC0, 0xFF, 0x80,
0x06, 0x1C, 0x30, 0x60, 0xC3, 0x06, 0x0C, 0x30, 0x60, 0xC3, 0x06, 0x0C,
0x38, 0x60, 0x38, 0xFB, 0xBE, 0x3C, 0x78, 0xF1, 0xE3, 0xEE, 0xF8, 0xE0,
0x1B, 0xFE, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x7D, 0xFD, 0x18, 0x30, 0xE3,
0x8E, 0x38, 0xE1, 0xFF, 0xF8, 0x7D, 0xFC, 0x18, 0x33, 0xE7, 0x81, 0x83,
0x87, 0xFF, 0xE0, 0x06, 0x0E, 0x1E, 0x3E, 0x36, 0x66, 0xE6, 0xFF, 0xFF,
0x06, 0x06, 0x7E, 0xFD, 0x83, 0x0F, 0x9F, 0x83, 0x83, 0x07, 0xFB, 0xE0,
0x1C, 0x79, 0xC7, 0x0F, 0xDF, 0xF1, 0xE3, 0xC6, 0xF8, 0xE0, 0xFF, 0xFC,
0x30, 0xE1, 0x87, 0x0C, 0x18, 0x60, 0xC1, 0x80, 0x3C, 0xFF, 0x1E, 0x3E,
0xEF, 0xBF, 0xE3, 0xC7, 0xFD, 0xF0, 0x38, 0xFB, 0x1E, 0x3C, 0x7F, 0xDF,
0x87, 0x1C, 0xF1, 0xC0, 0xFF, 0x80, 0x3F, 0xE0, 0x77, 0x70, 0x00, 0x06,
0x66, 0xCC, 0x06, 0x3E, 0xF8, 0xC0, 0xF8, 0x3F, 0x06, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x60, 0x7C, 0x1F, 0x03, 0x1F, 0xFC, 0x60, 0x7D, 0xFC,
0x18, 0x30, 0xC3, 0x0C, 0x18, 0x00, 0x70, 0xE1, 0xC0, 0x0F, 0xC0, 0x7F,
0xC3, 0x83, 0x98, 0x06, 0xE7, 0xCF, 0x3F, 0x3D, 0x8C, 0xF6, 0x33, 0xD8,
0xCF, 0xBF, 0xE6, 0x7F, 0x1E, 0x00, 0x3F, 0xC0, 0x3F, 0x00, 0x0E, 0x01,
0xC0, 0x7C, 0x0D, 0x83, 0xB8, 0x63, 0x0C, 0x63, 0xFE, 0x7F, 0xCC, 0x1B,
0x01, 0x80, 0xFC, 0x7F, 0xB0, 0xD8, 0x6F, 0xE7, 0xFB, 0x07, 0x83, 0xC3,
0xFF, 0xBF, 0x80, 0x1F, 0x1F, 0xD8, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80,
0x60, 0x3F, 0xC7, 0xC0, 0xFE, 0x3F, 0xCC, 0x3B, 0x07, 0xC0, 0xF0, 0x3C,
0x0F, 0x07, 0xC3, 0xBF, 0xCF, 0xE0, 0xFF, 0xFF, 0xC0, 0xC0, 0xFE, 0xFE,
0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0x1F, 0x1F, 0xD8, 0x18, 0x0C, 0x06, 0x0F, 0x07,
0x83, 0x71, 0xBF, 0xC7, 0xE0, 0xC1, 0xE0, 0xF0, 0x78, 0x3F, 0xFF, 0xFF,
0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x60, 0xFF, 0xFF, 0xFC, 0x06, 0x0C, 0x18,
0x30, 0x60, 0xC1, 0x83, 0x07, 0xF9, 0xE0, 0xC1, 0xB0, 0xCC, 0x63, 0x30,
0xF8, 0x3C, 0x0D, 0x83, 0x30, 0xC6, 0x30, 0xCC, 0x18, 0xC0, 0xC0, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x60, 0x33, 0x83, 0x9C,
0x1C, 0xF1, 0xED, 0x8D, 0xEE, 0xEF, 0x36, 0x79, 0xF3, 0xC7, 0x1E, 0x38,
0xF0, 0x06, 0xC0, 0xF8, 0x3F, 0x0F, 0xE3, 0xDC, 0xF3, 0xBC, 0x7F, 0x0F,
0xC1, 0xF0, 0x7C, 0x0C, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80,
0xF0, 0x1F, 0x07, 0x71, 0xCF, 0xF8, 0x7C, 0x00, 0xFC, 0xFE, 0xC3, 0xC3,
0xC3, 0xFE, 0xFC, 0xC0, 0xC0, 0xC0, 0xC0, 0x1F, 0x07, 0xF1, 0xC7, 0x70,
0x7C, 0x07, 0x80, 0xF0, 0x1F, 0x07, 0x71, 0xCF, 0xF0, 0xF8, 0x07, 0x00,
0x7C, 0x07, 0x80, 0xFC, 0x7F, 0x30, 0xD8, 0x6C, 0x37, 0xF3, 0xE1, 0x98,
0xC6, 0x63, 0xB0, 0xE0, 0x3D, 0xFF, 0x06, 0x0F, 0x0F, 0x87, 0x83, 0x07,
0xFD, 0xF0, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0xBF,
0x8F, 0x80, 0xC0, 0x6C, 0x19, 0x83, 0x38, 0xE3, 0x18, 0x63, 0x06, 0xC0,
0xD8, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0xC0, 0x07, 0x87, 0x0D, 0x8E, 0x33,
0x1C, 0x66, 0x6C, 0xC6, 0xDB, 0x0D, 0xB6, 0x1B, 0x6C, 0x1C, 0x70, 0x38,
0xE0, 0x71, 0xC0, 0xE0, 0xEC, 0x18, 0xC6, 0x0D, 0x80, 0xE0, 0x1C, 0x03,
0x80, 0xD8, 0x31, 0x8C, 0x1B, 0x83, 0x80, 0xC0, 0xD8, 0x67, 0x38, 0xCC,
0x1E, 0x07, 0x80, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0xFF, 0xFF, 0x06,
0x0C, 0x1C, 0x18, 0x30, 0x70, 0x60, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C, 0x63,
0x18, 0xC6, 0x31, 0x8C, 0x63, 0xFF, 0xC1, 0xC1, 0x83, 0x06, 0x06, 0x0C,
0x18, 0x18, 0x30, 0x60, 0x60, 0xC1, 0x83, 0x83, 0xFF, 0xC6, 0x31, 0x8C,
0x63, 0x18, 0xC6, 0x31, 0x8F, 0xFF, 0x08, 0x0E, 0x0F, 0x86, 0xC7, 0x77,
0x1D, 0x04, 0xFF, 0xFF, 0x4E, 0x72, 0x7C, 0xFC, 0x1B, 0xFF, 0xF8, 0xFF,
0xBF, 0xC1, 0x83, 0x06, 0x0F, 0x9F, 0xB3, 0xE3, 0xC7, 0x9F, 0xF7, 0xC0,
0x3D, 0xFE, 0x30, 0xC3, 0x87, 0xCF, 0x06, 0x0C, 0x18, 0x33, 0xEF, 0xF9,
0xE3, 0xC7, 0xCD, 0xF9, 0xF0, 0x38, 0xFB, 0x1F, 0xFF, 0xF8, 0x1F, 0x1E,
0x7F, 0xF1, 0x8F, 0xFF, 0x18, 0xC6, 0x31, 0x80, 0x3E, 0xFF, 0x9E, 0x3C,
0x7C, 0xDF, 0x9F, 0x06, 0xFB, 0xE0, 0xC1, 0x83, 0x06, 0x0F, 0xDF, 0xF1,
0xE3, 0xC7, 0x8F, 0x1E, 0x30, 0xFC, 0xFF, 0xFF, 0x33, 0x30, 0x33, 0x33,
0x33, 0x33, 0x3F, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC6, 0xCC, 0xD8, 0xF0,
0xD8, 0xCC, 0xC6, 0xC7, 0xDB, 0x6D, 0xB6, 0xDB, 0xB0, 0xFD, 0xEF, 0xFF,
0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xFD, 0xFF, 0x1E,
0x3C, 0x78, 0xF1, 0xE3, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
0xF9, 0xFB, 0x3E, 0x3C, 0x79, 0xFF, 0x7C, 0xC1, 0x83, 0x00, 0x3E, 0xFF,
0x9E, 0x3C, 0x7C, 0xDF, 0xBF, 0x06, 0x0C, 0x18, 0xFF, 0xF1, 0x8C, 0x63,
0x18, 0x7F, 0xEC, 0x3E, 0x7C, 0x3F, 0xFE, 0xC6, 0x3F, 0xFC, 0x63, 0x18,
0xFB, 0xC0, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xFF, 0xBF, 0xC1, 0xB1, 0x98,
0xCE, 0xE3, 0x61, 0xF0, 0x70, 0x38, 0xC6, 0x79, 0xCD, 0xBB, 0x35, 0x66,
0xAC, 0x77, 0x0E, 0xE1, 0x8C, 0xE3, 0xBB, 0x8D, 0x83, 0x81, 0xC1, 0xB1,
0xDD, 0xC7, 0xE3, 0xB1, 0x98, 0xCE, 0xE3, 0x61, 0xF0, 0x70, 0x38, 0x18,
0x7C, 0x3C, 0x00, 0xFF, 0xF1, 0x8E, 0x71, 0x8F, 0xFF, 0x3B, 0xD8, 0xC6,
0x31, 0x98, 0xC3, 0x18, 0xC6, 0x31, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7,
0x8C, 0x63, 0x18, 0xC3, 0x19, 0x8C, 0x63, 0x1B, 0xDC, 0x73, 0xFF, 0xCE,
0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x7F, 0x00, 0xFC, 0xFF,
0xFC, 0x18, 0x63, 0xDF, 0xE3, 0x0C, 0x30, 0x7C, 0xF1, 0x86, 0x1F, 0x3F,
0x70, 0x60, 0x60, 0xFE, 0xFE, 0x60, 0x60, 0x7F, 0x7F, 0x42, 0xFF, 0x7E,
0x66, 0x66, 0x7E, 0xFF, 0x42, 0xC3, 0x66, 0x66, 0x3C, 0x3C, 0x7E, 0x7E,
0x18, 0x7E, 0x7E, 0x18, 0xFF, 0xF0, 0x0F, 0xFF, 0x7F, 0xFC, 0x38, 0x7B,
0xFC, 0xF3, 0xFD, 0xE1, 0xC3, 0xFF, 0xE0, 0xDE, 0xC0, 0x1F, 0x07, 0xF1,
0xC7, 0x77, 0x7D, 0xE7, 0xB0, 0xF7, 0x9F, 0x77, 0x71, 0xC7, 0xF0, 0x7C,
0x00, 0x70, 0xDF, 0xFD, 0xBC, 0x11, 0x1D, 0xDD, 0xDD, 0xC7, 0x71, 0xDC,
0x44, 0xFF, 0xFC, 0x18, 0x30, 0x60, 0xC0, 0xFF, 0xC0, 0x1F, 0x07, 0xF1,
0xC7, 0x7F, 0x7D, 0xB7, 0xBE, 0xF6, 0xDF, 0xDF, 0x71, 0xC7, 0xF0, 0x7C,
0x00, 0xFF, 0xC0, 0x7B, 0xFC, 0xF3, 0xFD, 0xE0, 0x18, 0x18, 0x18, 0xFF,
0xFF, 0x18, 0x18, 0x18, 0x00, 0xFF, 0xFF, 0xF0, 0xCE, 0xEE, 0x7C, 0xF8,
0xDC, 0x31, 0x8F, 0xC0, 0x27, 0xE4, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xFF,
0xFF, 0xC1, 0x83, 0x00, 0x7F, 0xFF, 0xFE, 0x7F, 0x3F, 0x9F, 0xCC, 0xE6,
0x33, 0x19, 0x8C, 0xC6, 0x63, 0x31, 0x98, 0xCC, 0xFF, 0x80, 0x47, 0xA0,
0x7F, 0x33, 0x33, 0x7B, 0x3C, 0xF3, 0xCD, 0xE0, 0x44, 0x77, 0x1D, 0xC7,
0x77, 0x77, 0x71, 0x10, 0x70, 0xC7, 0x8C, 0x0C, 0x60, 0x66, 0x03, 0x30,
0x1B, 0x38, 0x19, 0xC1, 0x9E, 0x0D, 0xB0, 0xCF, 0xC6, 0x0C, 0x71, 0x8F,
0x30, 0x33, 0x03, 0x60, 0x36, 0x03, 0xDE, 0x0C, 0x31, 0x87, 0x18, 0xE3,
0x1C, 0x31, 0xF0, 0xF8, 0x60, 0x63, 0x07, 0x0C, 0x06, 0x60, 0x19, 0x80,
0x6C, 0xEF, 0x33, 0x81, 0x9E, 0x06, 0xD8, 0x33, 0xF0, 0xC1, 0x80, 0x38,
0x70, 0xE0, 0x01, 0x87, 0x1C, 0x60, 0xC1, 0xFD, 0xF0, 0x08, 0x03, 0x80,
0x38, 0x02, 0x00, 0x00, 0x1C, 0x03, 0x80, 0xF8, 0x1B, 0x07, 0x70, 0xC6,
0x18, 0xC7, 0xFC, 0xFF, 0x98, 0x36, 0x03, 0x04, 0x01, 0xC0, 0x70, 0x04,
0x00, 0x00, 0x1C, 0x03, 0x80, 0xF8, 0x1B, 0x07, 0x70, 0xC6, 0x18, 0xC7,
0xFC, 0xFF, 0x98, 0x36, 0x03, 0x04, 0x01, 0xC0, 0x6C, 0x00, 0x00, 0xE0,
0x1C, 0x07, 0xC0, 0xD8, 0x3B, 0x86, 0x30, 0xC6, 0x3F, 0xE7, 0xFC, 0xC1,
0xB0, 0x18, 0x0C, 0x83, 0xF0, 0x4C, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x80,
0xF8, 0x1B, 0x07, 0x70, 0xC6, 0x18, 0xC7, 0xFC, 0xFF, 0x98, 0x36, 0x03,
0x1B, 0x03, 0x60, 0x00, 0x00, 0x00, 0xE0, 0x1C, 0x07, 0xC0, 0xD8, 0x3B,
0x86, 0x30, 0xC6, 0x3F, 0xE7, 0xFC, 0xC1, 0xB0, 0x18, 0x0E, 0x03, 0x60,
0x6C, 0x07, 0x00, 0xE0, 0x1C, 0x06, 0xC0, 0xD8, 0x3B, 0x86, 0x30, 0xC6,
0x3F, 0xE7, 0xFC, 0xC1, 0xB0, 0x18, 0x01, 0xFE, 0x07, 0xFC, 0x1F, 0x00,
0x36, 0x00, 0xCF, 0xC1, 0x9F, 0x87, 0xF0, 0x1F, 0xE0, 0x30, 0xC0, 0xC1,
0xFF, 0x83, 0xF8, 0x1F, 0x1F, 0xD8, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80,
0x60, 0x3F, 0xC7, 0xC1, 0x80, 0x60, 0xE0, 0x10, 0x38, 0x1C, 0x08, 0x00,
0xFF, 0xFF, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x08,
0x1C, 0x38, 0x10, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0,
0xC0, 0xFF, 0xFF, 0x10, 0x38, 0x6C, 0x00, 0xFF, 0xFF, 0xC0, 0xC0, 0xFE,
0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x6C, 0x6C, 0x00, 0x00, 0xFF, 0xFF,
0xC0, 0xC0, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x4E, 0x72, 0x06,
0x66, 0x66, 0x66, 0x66, 0x66, 0x27, 0xE4, 0x06, 0x66, 0x66, 0x66, 0x66,
0x66, 0x23, 0xB6, 0x06, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x80, 0xDE,
0xC0, 0x06, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x80, 0x7F, 0x0F, 0xF1,
0x87, 0x30, 0x7F, 0x87, 0xF0, 0xD8, 0x1B, 0x07, 0x61, 0xCF, 0xF1, 0xFC,
0x00, 0x19, 0x0F, 0xC2, 0x60, 0x00, 0x00, 0x30, 0x3E, 0x0F, 0xC3, 0xF8,
0xF7, 0x3C, 0xEF, 0x1F, 0xC3, 0xF0, 0x7C, 0x1F, 0x03, 0x08, 0x03, 0x80,
0x38, 0x02, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01,
0xE0, 0x3E, 0x0E, 0xE3, 0x9F, 0xF0, 0xF8, 0x02, 0x00, 0xE0, 0x38, 0x02,
0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3E,
0x0E, 0xE3, 0x9F, 0xF0, 0xF8, 0x04, 0x01, 0xC0, 0x6C, 0x00, 0x01, 0xF0,
0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xF0, 0x77, 0x1C, 0xFF,
0x87, 0xC0, 0x0C, 0x83, 0xF0, 0x4C, 0x00, 0x00, 0x00, 0x3E, 0x0F, 0xE3,
0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xE3, 0x9F, 0xF0, 0xF8,
0x1B, 0x03, 0x60, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0,
0x78, 0x0F, 0x01, 0xF0, 0x77, 0x1C, 0xFF, 0x87, 0xC0, 0x45, 0xDD, 0xF1,
0xC7, 0xDD, 0xD1, 0x00, 0x1F, 0xE7, 0xF9, 0x87, 0x61, 0xFC, 0x67, 0x9C,
0xF3, 0x1F, 0xC3, 0x70, 0xCF, 0xFB, 0x7C, 0x00, 0x00, 0x10, 0x1C, 0x07,
0x01, 0x00, 0x06, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F,
0x1D, 0xFC, 0x7C, 0x04, 0x07, 0x07, 0x01, 0x00, 0x06, 0x0F, 0x07, 0x83,
0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0x1D, 0xFC, 0x7C, 0x08, 0x0E, 0x0D,
0x80, 0x0C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3E, 0x3B,
0xF8, 0xF8, 0x36, 0x1B, 0x00, 0x00, 0x0C, 0x1E, 0x0F, 0x07, 0x83, 0xC1,
0xE0, 0xF0, 0x78, 0x3E, 0x3B, 0xF8, 0xF8, 0x04, 0x03, 0x81, 0xC0, 0x20,
0x00, 0x30, 0x36, 0x19, 0xCE, 0x33, 0x07, 0x81, 0xE0, 0x30, 0x0C, 0x03,
0x00, 0xC0, 0x30, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0xC3, 0xFE, 0xFC,
0xC0, 0xC0, 0x3E, 0x3F, 0xB8, 0xD8, 0x6C, 0x66, 0x63, 0x39, 0x8E, 0xC1,
0xE0, 0xF3, 0xFB, 0xE0, 0x20, 0xE0, 0xE0, 0x80, 0x0F, 0x9F, 0x83, 0x7F,
0xFF, 0x1F, 0xF7, 0xE0, 0x08, 0x38, 0xE0, 0x80, 0x0F, 0x9F, 0x83, 0x7F,
0xFF, 0x1F, 0xF7, 0xE0, 0x10, 0x71, 0xB0, 0x07, 0xCF, 0xC1, 0xBF, 0xFF,
0x8F, 0xFB, 0xF0, 0x32, 0xFD, 0x30, 0x00, 0x0F, 0x9F, 0x83, 0x7F, 0xFF,
0x1F, 0xF7, 0xE0, 0x6C, 0xD8, 0x00, 0x07, 0xCF, 0xC1, 0xBF, 0xFF, 0x8F,
0xFB, 0xF0, 0x38, 0xD9, 0xB1, 0xC0, 0x0F, 0x9F, 0x83, 0x7F, 0xFF, 0x1F,
0xF7, 0xE0, 0x7D, 0xC7, 0xFE, 0x06, 0x37, 0xFF, 0xFF, 0xFC, 0x60, 0xFF,
0xE7, 0xDF, 0x3E, 0xFF, 0x86, 0x0C, 0x1C, 0x1F, 0x9F, 0x1C, 0x18, 0xE0,
0x20, 0xE0, 0xE0, 0x80, 0x07, 0x1F, 0x63, 0xFF, 0xFF, 0x03, 0xE3, 0xC0,
0x08, 0x38, 0xE0, 0x80, 0x07, 0x1F, 0x63, 0xFF, 0xFF, 0x03, 0xE3, 0xC0,
0x10, 0x71, 0xB0, 0x03, 0x8F, 0xB1, 0xFF, 0xFF, 0x81, 0xF1, 0xE0, 0x6C,
0xD8, 0x00, 0x03, 0x8F, 0xB1, 0xFF, 0xFF, 0x81, 0xF1, 0xE0, 0x4E, 0x72,
0x06, 0x66, 0x66, 0x66, 0x60, 0x27, 0xE4, 0x06, 0x66, 0x66, 0x66, 0x60,
0x23, 0xB6, 0x06, 0x31, 0x8C, 0x63, 0x18, 0xC0, 0xDE, 0xC0, 0x03, 0x18,
0xC6, 0x31, 0x8C, 0x60, 0x18, 0x1F, 0x1E, 0x06, 0x03, 0x3F, 0x7F, 0xC3,
0xC3, 0xC7, 0x7E, 0x3C, 0x65, 0xFA, 0x60, 0x00, 0x1F, 0xBF, 0xE3, 0xC7,
0x8F, 0x1E, 0x3C, 0x60, 0x10, 0x38, 0x1C, 0x08, 0x00, 0x3C, 0x7E, 0xE7,
0xC3, 0xC3, 0xE7, 0x7E, 0x3C, 0x08, 0x1C, 0x38, 0x10, 0x00, 0x3C, 0x7E,
0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C, 0x10, 0x38, 0x6C, 0x00, 0x3C, 0x7E,
0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C, 0x32, 0x7E, 0x4C, 0x00, 0x00, 0x3C,
0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C, 0x6C, 0x6C, 0x00, 0x00, 0x3C,
0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C, 0x38, 0x70, 0xE0, 0x0F, 0xFF,
0xC0, 0x1C, 0x38, 0x70, 0x3F, 0x7E, 0xEF, 0xCB, 0xD3, 0xF7, 0x7E, 0xFC,
0x20, 0xE0, 0xE0, 0x80, 0x18, 0xF1, 0xE3, 0xC7, 0x8F, 0x1F, 0xF7, 0xE0,
0x08, 0x38, 0xE0, 0x80, 0x18, 0xF1, 0xE3, 0xC7, 0x8F, 0x1F, 0xF7, 0xE0,
0x10, 0x71, 0xB0, 0x0C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0xFB, 0xF0, 0x6C,
0xD8, 0x00, 0x0C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0xFB, 0xF0, 0x04, 0x07,
0x07, 0x01, 0x00, 0x07, 0x1D, 0x8C, 0xC6, 0x77, 0x1B, 0x0F, 0x83, 0x81,
0xC0, 0xC3, 0xE1, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0xFE, 0xC7, 0xC3,
0xC3, 0xC7, 0xFE, 0xFC, 0xC0, 0xC0, 0xC0, 0x36, 0x1B, 0x00, 0x00, 0x0E,
0x3B, 0x19, 0x8C, 0xEE, 0x36, 0x1F, 0x07, 0x03, 0x81, 0x87, 0xC3, 0xC0 };
const GFXglyph Ubuntu_Bold8pt8bGlyphs[] PROGMEM = {
{ 0, 1, 1, 4, 0, 0 }, // 0x20 ' ' U+0020
{ 1, 2, 11, 4, 1, -10 }, // 0x21 '!' U+0021
{ 4, 5, 5, 7, 1, -11 }, // 0x22 '"' U+0022
{ 8, 9, 11, 11, 1, -10 }, // 0x23 '#' U+0023
{ 21, 7, 15, 9, 1, -12 }, // 0x24 '$' U+0024
{ 35, 14, 11, 16, 1, -10 }, // 0x25 '%' U+0025
{ 55, 10, 11, 11, 1, -10 }, // 0x26 '&' U+0026
{ 69, 2, 5, 4, 1, -11 }, // 0x27 ''' U+0027
{ 71, 4, 16, 6, 1, -12 }, // 0x28 '(' U+0028
{ 79, 4, 16, 6, 1, -12 }, // 0x29 ')' U+0029
{ 87, 7, 7, 8, 1, -10 }, // 0x2a '*' U+002A
{ 94, 8, 8, 10, 1, -8 }, // 0x2b '+' U+002B
{ 102, 3, 5, 4, 0, -1 }, // 0x2c ',' U+002C
{ 104, 5, 2, 7, 1, -5 }, // 0x2d '-' U+002D
{ 106, 3, 3, 5, 1, -2 }, // 0x2e '.' U+002E
{ 108, 7, 16, 7, 0, -12 }, // 0x2f '/' U+002F
{ 122, 7, 11, 9, 1, -10 }, // 0x30 '0' U+0030
{ 132, 5, 11, 9, 1, -10 }, // 0x31 '1' U+0031
{ 139, 7, 11, 9, 1, -10 }, // 0x32 '2' U+0032
{ 149, 7, 11, 9, 1, -10 }, // 0x33 '3' U+0033
{ 159, 8, 11, 9, 1, -10 }, // 0x34 '4' U+0034
{ 170, 7, 11, 9, 1, -10 }, // 0x35 '5' U+0035
{ 180, 7, 11, 9, 1, -10 }, // 0x36 '6' U+0036
{ 190, 7, 11, 9, 1, -10 }, // 0x37 '7' U+0037
{ 200, 7, 11, 9, 1, -10 }, // 0x38 '8' U+0038
{ 210, 7, 11, 9, 1, -10 }, // 0x39 '9' U+0039
{ 220, 3, 9, 5, 1, -8 }, // 0x3a ':' U+003A
{ 224, 4, 12, 5, 0, -8 }, // 0x3b ';' U+003B
{ 230, 8, 7, 9, 1, -7 }, // 0x3c '<' U+003C
{ 237, 8, 6, 10, 1, -7 }, // 0x3d '=' U+003D
{ 243, 8, 7, 9, 0, -7 }, // 0x3e '>' U+003E
{ 250, 7, 12, 7, 0, -11 }, // 0x3f '?' U+003F
{ 261, 14, 14, 16, 1, -10 }, // 0x40 '@' U+0040
{ 286, 11, 11, 11, 0, -10 }, // 0x41 'A' U+0041
{ 302, 9, 11, 11, 1, -10 }, // 0x42 'B' U+0042
{ 315, 9, 11, 11, 1, -10 }, // 0x43 'C' U+0043
{ 328, 10, 11, 12, 1, -10 }, // 0x44 'D' U+0044
{ 342, 8, 11, 10, 1, -10 }, // 0x45 'E' U+0045
{ 353, 8, 11, 9, 1, -10 }, // 0x46 'F' U+0046
{ 364, 9, 11, 11, 1, -10 }, // 0x47 'G' U+0047
{ 377, 9, 11, 11, 1, -10 }, // 0x48 'H' U+0048
{ 390, 2, 11, 4, 1, -10 }, // 0x49 'I' U+0049
{ 393, 7, 11, 8, 0, -10 }, // 0x4a 'J' U+004A
{ 403, 10, 11, 11, 1, -10 }, // 0x4b 'K' U+004B
{ 417, 8, 11, 9, 1, -10 }, // 0x4c 'L' U+004C
{ 428, 13, 11, 15, 1, -10 }, // 0x4d 'M' U+004D
{ 446, 10, 11, 12, 1, -10 }, // 0x4e 'N' U+004E
{ 460, 11, 11, 13, 1, -10 }, // 0x4f 'O' U+004F
{ 476, 8, 11, 10, 1, -10 }, // 0x50 'P' U+0050
{ 487, 11, 14, 13, 1, -10 }, // 0x51 'Q' U+0051
{ 507, 9, 11, 10, 1, -10 }, // 0x52 'R' U+0052
{ 520, 7, 11, 9, 1, -10 }, // 0x53 'S' U+0053
{ 530, 8, 11, 8, 0, -10 }, // 0x54 'T' U+0054
{ 541, 9, 11, 11, 1, -10 }, // 0x55 'U' U+0055
{ 554, 11, 11, 11, 0, -10 }, // 0x56 'V' U+0056
{ 570, 15, 11, 15, 0, -10 }, // 0x57 'W' U+0057
{ 591, 11, 11, 11, 0, -10 }, // 0x58 'X' U+0058
{ 607, 10, 11, 10, 0, -10 }, // 0x59 'Y' U+0059
{ 621, 8, 11, 10, 1, -10 }, // 0x5a 'Z' U+005A
{ 632, 5, 16, 6, 1, -12 }, // 0x5b '[' U+005B
{ 642, 7, 16, 7, 0, -12 }, // 0x5c '\' U+005C
{ 656, 5, 16, 6, 0, -12 }, // 0x5d ']' U+005D
{ 666, 9, 7, 9, 0, -10 }, // 0x5e '^' U+005E
{ 674, 8, 2, 8, 0, 2 }, // 0x5f '_' U+005F
{ 676, 4, 4, 5, 1, -12 }, // 0x60 '`' U+0060
{ 678, 7, 8, 9, 1, -7 }, // 0x61 'a' U+0061
{ 685, 7, 12, 9, 1, -11 }, // 0x62 'b' U+0062
{ 696, 6, 8, 8, 1, -7 }, // 0x63 'c' U+0063
{ 702, 7, 12, 9, 1, -11 }, // 0x64 'd' U+0064
{ 713, 7, 8, 9, 1, -7 }, // 0x65 'e' U+0065
{ 720, 5, 12, 6, 1, -11 }, // 0x66 'f' U+0066
{ 728, 7, 11, 9, 1, -7 }, // 0x67 'g' U+0067
{ 738, 7, 12, 9, 1, -11 }, // 0x68 'h' U+0068
{ 749, 2, 12, 4, 1, -11 }, // 0x69 'i' U+0069
{ 752, 4, 15, 4, -1, -11 }, // 0x6a 'j' U+006A
{ 760, 8, 12, 9, 1, -11 }, // 0x6b 'k' U+006B
{ 772, 3, 12, 4, 1, -11 }, // 0x6c 'l' U+006C
{ 777, 12, 8, 14, 1, -7 }, // 0x6d 'm' U+006D
{ 789, 7, 8, 9, 1, -7 }, // 0x6e 'n' U+006E
{ 796, 8, 8, 10, 1, -7 }, // 0x6f 'o' U+006F
{ 804, 7, 11, 9, 1, -7 }, // 0x70 'p' U+0070
{ 814, 7, 11, 9, 1, -7 }, // 0x71 'q' U+0071
{ 824, 5, 8, 6, 1, -7 }, // 0x72 'r' U+0072
{ 829, 6, 8, 8, 1, -7 }, // 0x73 's' U+0073
{ 835, 5, 10, 7, 1, -9 }, // 0x74 't' U+0074
{ 842, 7, 8, 9, 1, -7 }, // 0x75 'u' U+0075
{ 849, 9, 8, 9, 0, -7 }, // 0x76 'v' U+0076
{ 858, 11, 8, 11, 0, -7 }, // 0x77 'w' U+0077
{ 869, 9, 8, 9, 0, -7 }, // 0x78 'x' U+0078
{ 878, 9, 11, 9, 0, -7 }, // 0x79 'y' U+0079
{ 891, 6, 8, 8, 1, -7 }, // 0x7a 'z' U+007A
{ 897, 5, 16, 5, 0, -12 }, // 0x7b '{' U+007B
{ 907, 2, 16, 4, 1, -12 }, // 0x7c '|' U+007C
{ 911, 5, 16, 5, 0, -12 }, // 0x7d '}' U+007D
{ 921, 8, 3, 9, 1, -5 }, // 0x7e '~' U+007E
{ 924, 6, 12, 8, 1, -11 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
{ 933, 1, 1, 4, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
{ 934, 2, 11, 4, 1, -7 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
{ 937, 6, 12, 9, 1, -9 }, // 0x82 'CENT SIGN' U+00A2
{ 946, 8, 11, 9, 0, -10 }, // 0x83 'POUND SIGN' U+00A3
{ 957, 8, 8, 9, 0, -8 }, // 0x84 'CURRENCY SIGN' U+00A4
{ 965, 8, 11, 8, 0, -10 }, // 0x85 'YEN SIGN' U+00A5
{ 976, 2, 16, 5, 1, -12 }, // 0x86 'BROKEN BAR' U+00A6
{ 980, 6, 14, 8, 1, -10 }, // 0x87 'SECTION SIGN' U+00A7
{ 991, 5, 2, 9, 2, -11 }, // 0x88 'DIAERESIS' U+00A8
{ 993, 11, 11, 13, 1, -10 }, // 0x89 'COPYRIGHT SIGN' U+00A9
{ 1009, 5, 6, 6, 0, -10 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
{ 1013, 9, 7, 10, 0, -7 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
{ 1021, 7, 6, 9, 1, -6 }, // 0x8c 'NOT SIGN' U+00AC
{ 1027, 5, 2, 7, 1, -5 }, // 0x8d 'SOFT HYPHEN' U+00AD
{ 1029, 11, 11, 13, 1, -10 }, // 0x8e 'REGISTERED SIGN' U+00AE
{ 1045, 5, 2, 6, 0, -11 }, // 0x8f 'MACRON' U+00AF
{ 1047, 6, 6, 6, 0, -12 }, // 0x90 'DEGREE SIGN' U+00B0
{ 1052, 8, 11, 10, 1, -10 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
{ 1063, 5, 6, 6, 0, -10 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
{ 1067, 5, 7, 6, 0, -10 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
{ 1072, 4, 4, 5, 0, -12 }, // 0x94 'ACUTE ACCENT' U+00B4
{ 1074, 7, 11, 9, 1, -7 }, // 0x95 'MICRO SIGN' U+00B5
{ 1084, 9, 14, 11, 1, -10 }, // 0x96 'PILCROW SIGN' U+00B6
{ 1100, 3, 3, 5, 1, -5 }, // 0x97 'MIDDLE DOT' U+00B7
{ 1102, 3, 4, 5, 1, 1 }, // 0x98 'CEDILLA' U+00B8
{ 1104, 4, 6, 6, 1, -10 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
{ 1107, 6, 6, 8, 1, -10 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
{ 1112, 9, 7, 10, 0, -7 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
{ 1120, 13, 11, 14, 1, -10 }, // 0x9c 'VULGAR FRACTION ONE QUARTER' U+00BC
{ 1138, 12, 11, 14, 1, -10 }, // 0x9d 'VULGAR FRACTION ONE HALF' U+00BD
{ 1155, 14, 11, 14, 0, -10 }, // 0x9e 'VULGAR FRACTION THREE QUARTERS' U+00BE
{ 1175, 7, 11, 7, 0, -7 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
{ 1185, 11, 16, 11, 0, -15 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
{ 1207, 11, 16, 11, 0, -15 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
{ 1229, 11, 15, 11, 0, -14 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
{ 1250, 11, 16, 11, 0, -15 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
{ 1272, 11, 15, 11, 0, -14 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
{ 1293, 11, 15, 11, 0, -14 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
{ 1314, 15, 11, 16, 0, -10 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
{ 1335, 9, 14, 11, 1, -10 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
{ 1351, 8, 16, 10, 1, -15 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
{ 1367, 8, 16, 10, 1, -15 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
{ 1383, 8, 15, 10, 1, -14 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
{ 1398, 8, 15, 10, 1, -14 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
{ 1413, 4, 16, 4, 0, -15 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
{ 1421, 4, 16, 4, 0, -15 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
{ 1429, 5, 15, 4, 0, -14 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
{ 1439, 5, 15, 4, 0, -14 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
{ 1449, 11, 11, 12, 0, -10 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
{ 1465, 10, 16, 12, 1, -15 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
{ 1485, 11, 16, 13, 1, -15 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
{ 1507, 11, 16, 13, 1, -15 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
{ 1529, 11, 15, 13, 1, -14 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
{ 1550, 11, 16, 13, 1, -15 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
{ 1572, 11, 15, 13, 1, -14 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
{ 1593, 7, 7, 9, 1, -7 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
{ 1600, 11, 12, 13, 1, -10 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
{ 1617, 9, 16, 11, 1, -15 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
{ 1635, 9, 16, 11, 1, -15 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
{ 1653, 9, 15, 11, 1, -14 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
{ 1670, 9, 15, 11, 1, -14 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
{ 1687, 10, 16, 10, 0, -15 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
{ 1707, 8, 11, 10, 1, -10 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
{ 1718, 9, 12, 11, 1, -11 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
{ 1732, 7, 13, 9, 1, -12 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
{ 1744, 7, 13, 9, 1, -12 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
{ 1756, 7, 12, 9, 1, -11 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
{ 1767, 7, 13, 9, 1, -12 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
{ 1779, 7, 12, 9, 1, -11 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
{ 1790, 7, 13, 9, 1, -12 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
{ 1802, 12, 8, 14, 1, -7 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
{ 1814, 7, 11, 8, 1, -7 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
{ 1824, 7, 13, 9, 1, -12 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
{ 1836, 7, 13, 9, 1, -12 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
{ 1848, 7, 12, 9, 1, -11 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
{ 1859, 7, 12, 9, 1, -11 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
{ 1870, 4, 13, 4, 0, -12 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
{ 1877, 4, 13, 4, 0, -12 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
{ 1884, 5, 12, 4, 0, -11 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
{ 1892, 5, 12, 4, -1, -11 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
{ 1900, 8, 12, 10, 1, -11 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
{ 1912, 7, 13, 9, 1, -12 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
{ 1924, 8, 13, 10, 1, -12 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
{ 1937, 8, 13, 10, 1, -12 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
{ 1950, 8, 12, 10, 1, -11 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
{ 1962, 8, 13, 10, 1, -12 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
{ 1975, 8, 12, 10, 1, -11 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
{ 1987, 7, 10, 9, 1, -9 }, // 0xd7 'DIVISION SIGN' U+00F7
{ 1996, 8, 8, 10, 1, -7 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
{ 2004, 7, 13, 9, 1, -12 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
{ 2016, 7, 13, 9, 1, -12 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
{ 2028, 7, 12, 9, 1, -11 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
{ 2039, 7, 12, 9, 1, -11 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
{ 2050, 9, 16, 9, 0, -12 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
{ 2068, 8, 15, 10, 1, -11 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
{ 2083, 9, 15, 9, 0, -11 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
const GFXfont Ubuntu_Bold8pt8b PROGMEM = {
(uint8_t *)Ubuntu_Bold8pt8bBitmaps,
(GFXglyph *)Ubuntu_Bold8pt8bGlyphs,
0x20, 0xDF, 18 };
// Approx. 3451 bytes

111
lib/obp60task/gen_set.pl Executable file
View File

@@ -0,0 +1,111 @@
#!/bin/perl -w
#A tool to generate the part of config.json that deals with pages and fields.
#List of all pages and the number of parameters they expect.
%NoOfFieldsPerPage=qw(
ApparentWind 0
XTETrack 0
Battery2 0
Battery 0
BME280 0
Clock 0
DST810 0
FourValues2 4
FourValues 4
Generator 0
KeelPosition 0
OneValue 1
RollPitch 0
RudderPosition 0
Solar 0
ThreeValues 3
TwoValues 2
Voltage 0
White 0
WindRose 0
WindRoseFlex 6
);
# No changes needed beyond this point
#max number of pages supported by OBP60
$NoOfPages=10;
#Default selection for each page
@Defaults=qw(Voltage WindRose OneValue TwoValues ThreeValues FourValues FourValues2 Clock RollPitch Battery2);
@Numbers=qw(one two three four five six seven eight nine ten);
@Pages=sort(keys(%NoOfFieldsPerPage));
$MaxNoOfFieldsPerPage=0; # inital value, gets updated with maximum entry from %NoOfFieldsPerPage
#find max. number of fields without additional modules
foreach (values(%NoOfFieldsPerPage)){
if ($_ > $MaxNoOfFieldsPerPage){
$MaxNoOfFieldsPerPage=$_;
}
}
for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
print "{\n";
print "\t","\"name\": \"page", $PageNo,"type\",\n";
print "\t","\"label\": \"Type\",\n";
print "\t",'"type": "list",',"\n";
print "\t",'"default": "';
print "$Defaults[$PageNo-1]";
print'"',"\n";
print "\t",'"description": "Type of page for page ',$PageNo,'",',"\n";
print "\t",'"list": [';
for ($p=0;$p<=$#Pages;$p++) {
print '"', $Pages[$p], '"' ;
if ($p < $#Pages){print ","}
}
print "]\n";
print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
print "\t",'"capabilities": {',"\n";
print "\t\t",'"obp60":"true"',"\n";
print "\t",'}',"\n";
print "\t",'"condition":[';
for ($vp=$PageNo;$vp<=$NoOfPages;$vp++){
print '"{visiblePages":"',$vp,'"},';
}
print "\b",']',"\n";
print '},',"\n";
for ($FieldNo=1; $FieldNo<=$MaxNoOfFieldsPerPage;$FieldNo++){
print "{\n";
print "\t",'"name": "page',$PageNo,'value',$FieldNo,'",',"\n";
print "\t",'"label": "Field ',$FieldNo,'",',"\n";
print "\t",'"type": "boatData",',"\n";
print "\t",'"default": "",',"\n";
print "\t",'"description": "The display for field ',$Numbers[$FieldNo-1],'",',"\n";
print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
print "\t",'"capabilities": {',"\n";
print "\t",' "obp60":"true"',"\n";
print "\t",'}, ',"\n";
print "\t",'"condition":[';
foreach $page (@Pages) {
if($NoOfFieldsPerPage{$page}>=$FieldNo){
print '{"page1type":"',$page,'"},';
}
}
print "\b],\n";
print '},',"\n";
}
print "{\n";
print "\t","\"name\": \"page", $PageNo,"fluid\",\n";
print "\t",'"label": "Fluid type",',"\n";
print "\t",'"type": "list",',"\n";
print "\t",'"default": "0",',"\n";
print "\t",'"list": [',"\n";
print "\t",'{"l":"Fuel (0)","v":"0"},',"\n";
print "\t",'{"l":"Water (1)","v":"1"},',"\n";
print "\t",'{"l":"Gray Water (2)","v":"2"},',"\n";
print "\t",'{"l":"Live Well (3)","v":"3"},',"\n";
print "\t",'{"l":"Oil (4)","v":"4"},',"\n";
print "\t",'{"l":"Black Water (5)","v":"5"},',"\n";
print "\t",'{"l":"Fuel Gasoline (6)","v":"6"}',"\n";
print "\t",'],',"\n";
print "\t",'"description": "Fluid type in tank",',"\n";
print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
print "\t",'"capabilities": {',"\n";
print "\t",'"obp60":"true"',"\n";
print "\t",'},',"\n";
print "\t",'"condition":[{"page',$PageNo,'type":"Fluid"}]',"\n";
print '},',"\n";
}

View File

@@ -1,131 +0,0 @@
#!/usr/bin/env python3
# A tool to generate that part of config.json that deals with pages and fields.
#
#Usage: 1. modify this script (e.g.add a page, change number of fields, etc.)
# 2. Delete all lines from config.json from the curly backet before "name": "page1type" to o the end of the file (as of today, delete from line 917 to the end of the File)
# 3. run ./gen_set.py >> config.json
import json
# List of all pages and the number of parameters they expect.
no_of_fields_per_page = {
"Wind": 0,
"XTETrack": 0,
"Battery2": 0,
"Battery": 0,
"BME280": 0,
"Clock": 0,
"Compass" : 0,
"DST810": 0,
"Fluid": 1,
"FourValues2": 4,
"FourValues": 4,
"Generator": 0,
"KeelPosition": 0,
"OneValue": 1,
"RollPitch": 2,
"RudderPosition": 0,
"SixValues" : 6,
"Solar": 0,
"ThreeValues": 3,
"TwoValues": 2,
"Voltage": 0,
"WhitePage": 0,
"WindRose": 0,
"WindRoseFlex": 6,
}
# No changes needed beyond this point
# max number of pages supported by OBP60
no_of_pages = 10
# Default selection for each page
default_pages = [
"Voltage",
"WindRose",
"OneValue",
"TwoValues",
"ThreeValues",
"FourValues",
"FourValues2",
"Clock",
"RollPitch",
"Battery2",
]
numbers = [
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
]
pages = sorted(no_of_fields_per_page.keys())
max_no_of_fields_per_page = max(no_of_fields_per_page.values())
output = []
for page_no in range(1, no_of_pages + 1):
page_data = {
"name": f"page{page_no}type",
"label": "Type",
"type": "list",
"default": default_pages[page_no - 1],
"description": f"Type of page for page {page_no}",
"list": pages,
"category": f"OBP60 Page {page_no}",
"capabilities": {"obp60": "true"},
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
#"fields": [],
}
output.append(page_data)
for field_no in range(1, max_no_of_fields_per_page + 1):
field_data = {
"name": f"page{page_no}value{field_no}",
"label": f"Field {field_no}",
"type": "boatData",
"default": "",
"description": f"The display for field {numbers[field_no - 1]}",
"category": f"OBP60 Page {page_no}",
"capabilities": {"obp60": "true"},
"condition": [
{f"page{page_no}type": page}
for page in pages
if no_of_fields_per_page[page] >= field_no
],
}
output.append(field_data)
fluid_data ={
"name": f"page{page_no}fluid",
"label": "Fluid type",
"type": "list",
"default": "0",
"list": [
{"l":"Fuel (0)","v":"0"},
{"l":"Water (1)","v":"1"},
{"l":"Gray Water (2)","v":"2"},
{"l":"Live Well (3)","v":"3"},
{"l":"Oil (4)","v":"4"},
{"l":"Black Water (5)","v":"5"},
{"l":"Fuel Gasoline (6)","v":"6"}
],
"description": "Fluid type in tank",
"category": f"OBP60 Page {page_no}",
"capabilities": {
"obp60":"true"
},
"condition":[{f"page{page_no}type":"Fluid"}]
}
output.append(fluid_data)
json_output = json.dumps(output, indent=4)
# print omitting first and last line containing [ ] of JSON array
#print(json_output[1:-1])
# print omitting first line containing [ of JSON array
print(json_output[1:])
# print(",")

84
lib/obp60task/hbuffer.cpp Normal file
View File

@@ -0,0 +1,84 @@
/* History Buffer
*
* Storage backed buffer for sensordata
* Permanent storage only supported type: FRAM on I2C-Bus
*
* Values can be 1 to 4 bytes in length
*
* Header: 32 bytes of size
* 0 0x00 HB00 4 magic number
* 4 0x04 xxxxxxxxxxxxxxxx 16 name, space padded
* 20 0x14 n 1 byte size of values in buffer
* 21 0x15 mm 2 buffer size in count of values
* 23 0x17 dd 2 time step in seconds between values
* 25 0x19 tttt 4 unix timestamp of head
* 29 0x1d hh 2 head pointer
* 31 0x1f 0xff 1 header end sign
*
* 32 0x20 ... start of buffer data
*
* Usage example: 7 hours of data collected every 75 seconds
* TODO
*
*/
#include <stdint.h>
#include <time.h>
class HistoryBuffer {
private:
// Header prototype for permanent storage
uint8_t header[32] = {
0x41, 0x48, 0x30, 0x30, // magic: HB00
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // empty name
0x01, // byte size
0x50, 0x01, // value count
0x4b, 0x00, // time step
0x00, 0x00, 0x00, 0x00, // unix time stamp
0x00, 0x00, // head pointer
0xff // end sign
};
uint16_t head = 0; // head pointer to next new value position
time_t timestamp; // last modification time of head
uint16_t delta_t; // time step in seconds
public:
HistoryBuffer(uint16_t size) {
}
~HistoryBuffer() {
// free memory
}
void begin() {
//
}
void finish() {
}
uint16_t add() {
// returns new head value pointer
}
uint8_t* get() {
// returns complete buffer in order new to old
}
uint8_t getvalue(uint16_t dt) {
// Return a single value delta seconds ago
uint16_t index = head - abs(dt) / delta_t;
return 0;
}
uint8_t getvalue3() {
}
bool clear() {
// clears buffer and permanent storage
return true;
}
};
class History {
public:
History() {
}
~History() {
}
void *addSeries() {
}
};

21
lib/obp60task/hbuffer.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef __HBUFFER_H__
#define __HBUFFER_H__
class HistoryBuffer {
public:
HistoryBuffer(uint16_t size);
void begin();
void finish();
uint16_t add();
uint8_t* get() ;
uint8_t getvalue(uint16_t dt);
uint8_t getvalue3();
void clear();
};
class History {
public:
History();
void *addSeries();
};
#endif

View File

@@ -0,0 +1,2 @@
cd /workspace/esp32-nmea2000-obp60
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run

View File

@@ -1,51 +0,0 @@
#ifndef _LOGO64_XBM_
#define _LOGO64_XBM_ 1
#define logo64_width 64
#define logo64_height 64
static unsigned char logo64_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xc1, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xc1,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, 0xc1, 0x7f, 0xf8, 0x01, 0xfe,
0x00, 0x00, 0xc0, 0xc1, 0x1f, 0xe0, 0x01, 0xfc, 0x00, 0x00, 0xe0, 0xc1,
0x0f, 0xc3, 0xf1, 0xf8, 0x00, 0x00, 0xf0, 0xc1, 0xc7, 0x8f, 0xf1, 0xf9,
0x00, 0x00, 0xf8, 0xc1, 0xc7, 0x8f, 0xf1, 0xf9, 0x00, 0x00, 0xf8, 0xc1,
0xe7, 0x9f, 0xf1, 0xf8, 0x00, 0x00, 0xfc, 0xc1, 0xe7, 0x9f, 0x01, 0xfc,
0x00, 0x00, 0xfe, 0xc1, 0xe7, 0x9f, 0x01, 0xfe, 0x00, 0x00, 0xfe, 0xc1,
0xc7, 0x8f, 0xf1, 0xff, 0x00, 0x00, 0xff, 0xc1, 0xc7, 0x8f, 0xf1, 0xff,
0x00, 0x80, 0xff, 0xc1, 0x8f, 0xc7, 0xf1, 0xff, 0x00, 0x80, 0xff, 0xc1,
0x1f, 0xe0, 0xf1, 0xff, 0x00, 0xc0, 0xff, 0xc1, 0x7f, 0xf8, 0xf1, 0xff,
0x00, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xc1,
0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf8, 0xff, 0xc1, 0x0f, 0xe0, 0xf8, 0xfc, 0x00, 0xfc, 0xff, 0xc1,
0x0f, 0xe0, 0xf8, 0xfc, 0x00, 0xfc, 0xff, 0xc1, 0xcf, 0xff, 0xf0, 0xfc,
0x00, 0xfe, 0xff, 0xc1, 0xcf, 0xff, 0xe0, 0xfc, 0x00, 0xff, 0xff, 0xc1,
0xcf, 0xff, 0xe4, 0xfc, 0x00, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0xc4, 0xfc,
0x80, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0xcc, 0xfc, 0xc0, 0xff, 0xff, 0xc1,
0xcf, 0xff, 0x8c, 0xfc, 0xe0, 0xff, 0xff, 0xc1, 0xcf, 0xff, 0x9c, 0xfc,
0xe0, 0xff, 0xff, 0xc1, 0xcf, 0xff, 0x1c, 0xfc, 0xf0, 0xff, 0xff, 0xc1,
0xcf, 0xff, 0x3c, 0xfc, 0xf8, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0x7c, 0xfc,
0xf8, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xc1,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff,
0xfe, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x00, 0x38, 0x00, 0x04, 0x00, 0x00, 0x44, 0x00, 0x10, 0x48,
0x00, 0x00, 0x00, 0x01, 0x44, 0x86, 0x7b, 0x48, 0x67, 0xc4, 0xf0, 0x77,
0x3c, 0x09, 0x12, 0x38, 0x91, 0x24, 0x09, 0x11, 0x44, 0xc9, 0x13, 0x08,
0x91, 0xe4, 0x09, 0x61, 0x44, 0x49, 0x12, 0x08, 0x91, 0x24, 0x08, 0x41,
0x3c, 0xc6, 0x73, 0x08, 0x61, 0xc4, 0x71, 0x77, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#endif

View File

@@ -1,171 +0,0 @@
#ifndef _UNKNOWN_XBM_
#define _UNKNOWN_XBM_ 1
#define unknown_width 120
#define unknown_height 130
static unsigned char unknown_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xe0, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x70, 0x80, 0xcf, 0x01, 0x00, 0x00,
0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0xc0, 0x7f,
0x00, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x80,
0xff, 0xfb, 0x7b, 0x00, 0x00, 0xf8, 0x7f, 0xe0, 0x0f, 0x00, 0x00, 0x00,
0x00, 0xfc, 0x07, 0xb8, 0xff, 0xfb, 0x7f, 0x00, 0xff, 0x3f, 0xf8, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0xd0, 0xff, 0xfd, 0x19, 0xe0, 0xff,
0x0d, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0xf9, 0x3f,
0x0d, 0xfc, 0x7f, 0x86, 0xff, 0x07, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x07,
0xfe, 0xc1, 0xdf, 0x07, 0xff, 0xc1, 0xe3, 0x3d, 0x03, 0x00, 0x00, 0x3f,
0x00, 0x00, 0x07, 0x7e, 0x81, 0xff, 0x84, 0x7f, 0xf3, 0x7b, 0x07, 0x03,
0x00, 0x00, 0x7e, 0x80, 0x3f, 0x0f, 0xf0, 0xc3, 0x3b, 0xe4, 0xdd, 0x9d,
0xcf, 0x80, 0x01, 0x00, 0x00, 0x6c, 0x00, 0xff, 0x3f, 0xe0, 0x17, 0x9c,
0x7f, 0xf7, 0xc3, 0x63, 0x80, 0x01, 0x00, 0x00, 0xfe, 0x0c, 0xf0, 0xfd,
0xc3, 0x3c, 0xde, 0xfd, 0xef, 0xf8, 0x18, 0x80, 0x01, 0x00, 0x00, 0xfe,
0x0e, 0xf0, 0x9f, 0x8f, 0x78, 0xcf, 0xfe, 0x1b, 0x3f, 0x0e, 0xc0, 0x00,
0x00, 0x00, 0xfe, 0x1d, 0xf0, 0xff, 0x9f, 0x21, 0xcc, 0xfb, 0xe7, 0x8f,
0x03, 0xc0, 0x00, 0x00, 0x00, 0xcc, 0x1f, 0xb0, 0xff, 0x1f, 0x00, 0xc0,
0xbf, 0xb9, 0xc7, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x3c, 0x1f,
0xfe, 0x00, 0xfe, 0x6f, 0xfe, 0xf1, 0x01, 0xc0, 0x00, 0x00, 0xf8, 0xfb,
0x1f, 0xbc, 0xfe, 0xff, 0xc0, 0xff, 0x9d, 0x7f, 0x7c, 0x00, 0x60, 0x00,
0x00, 0xfc, 0xef, 0x1d, 0xfc, 0xc3, 0xff, 0xe9, 0xcf, 0xed, 0x1f, 0x1f,
0x00, 0x60, 0x00, 0x00, 0xfe, 0xef, 0x1d, 0x00, 0x97, 0xf0, 0xf9, 0xcf,
0xfd, 0x87, 0x07, 0x03, 0x60, 0x00, 0x00, 0xfe, 0xcc, 0x0c, 0x00, 0xfc,
0x81, 0xff, 0xdf, 0xfd, 0xc0, 0xf9, 0x03, 0x60, 0x00, 0x00, 0xe4, 0xdc,
0x0f, 0x00, 0xf8, 0x9f, 0xff, 0xdf, 0x3d, 0xe0, 0x0f, 0x00, 0x60, 0x00,
0x00, 0xc0, 0xdf, 0x03, 0x00, 0xe0, 0xf1, 0xfe, 0xdf, 0x0c, 0xfe, 0xff,
0x01, 0x60, 0x00, 0x00, 0xc0, 0xcf, 0x01, 0x00, 0x60, 0xf3, 0xff, 0xdb,
0x06, 0xff, 0x01, 0x00, 0x70, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x78,
0xff, 0x1f, 0x9b, 0x87, 0xff, 0xff, 0x0f, 0x30, 0x00, 0x00, 0x00, 0x66,
0x03, 0x00, 0xfc, 0x7f, 0xfb, 0x99, 0xc7, 0xff, 0xff, 0x00, 0x30, 0x00,
0x00, 0x00, 0x06, 0x03, 0x00, 0xc6, 0xff, 0xff, 0xd9, 0x67, 0xff, 0xc1,
0x01, 0x70, 0x00, 0x00, 0x00, 0xc7, 0x03, 0x00, 0x07, 0x7c, 0xe3, 0xf9,
0xe3, 0xff, 0x7f, 0x00, 0x70, 0x00, 0x00, 0x80, 0xf3, 0x07, 0x00, 0x1f,
0x6c, 0xe0, 0x7b, 0xe3, 0xff, 0xff, 0x01, 0x70, 0x00, 0x00, 0x80, 0xd9,
0x06, 0x80, 0xff, 0x0f, 0xce, 0xef, 0xe3, 0xff, 0xf7, 0x01, 0x70, 0x00,
0x00, 0xe0, 0xbf, 0x0d, 0xc0, 0xff, 0x43, 0xe4, 0xef, 0xe3, 0x3f, 0x7f,
0x07, 0x60, 0x00, 0x00, 0xe0, 0xbf, 0x1d, 0xe0, 0x78, 0x43, 0x70, 0xec,
0xe1, 0xff, 0xf8, 0x1d, 0x60, 0x00, 0x00, 0xe0, 0xff, 0x19, 0x70, 0x00,
0x03, 0x37, 0xfc, 0xf1, 0xbf, 0xc3, 0x07, 0x60, 0x00, 0x00, 0xc0, 0xff,
0x19, 0x70, 0x80, 0x01, 0x3b, 0xd6, 0xf9, 0xef, 0x1c, 0x3e, 0x60, 0x00,
0x00, 0x80, 0x63, 0x1b, 0xf0, 0xc6, 0x39, 0x19, 0xfe, 0xf8, 0xbf, 0x31,
0xf8, 0x60, 0x00, 0x00, 0x00, 0x60, 0x3b, 0xf8, 0xfe, 0x98, 0x1f, 0xfe,
0xf8, 0x7f, 0x67, 0xe0, 0x61, 0x00, 0x00, 0x00, 0x60, 0x33, 0xfc, 0x7f,
0x80, 0x0f, 0xeb, 0xfc, 0xff, 0x0d, 0x80, 0xc7, 0x00, 0x00, 0x00, 0x60,
0x33, 0x0c, 0x7f, 0x06, 0x0c, 0x7f, 0xec, 0x6f, 0x0b, 0x00, 0xfe, 0x00,
0x00, 0x00, 0x60, 0x76, 0x0e, 0xf8, 0xbf, 0x87, 0x7f, 0xee, 0xdf, 0x00,
0x00, 0xf8, 0x01, 0x00, 0x00, 0xc0, 0x76, 0x0e, 0xb8, 0xa0, 0x87, 0x3f,
0xde, 0x3f, 0x01, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xc0, 0xf6, 0x0f, 0x3c,
0x80, 0xdf, 0x3f, 0xdf, 0x77, 0x02, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
0xdd, 0xef, 0x1f, 0x80, 0xfe, 0x9f, 0xdf, 0xe7, 0x06, 0x00, 0xe0, 0x03,
0x00, 0x00, 0x80, 0xfd, 0xfe, 0x1f, 0xcc, 0xff, 0xdf, 0xdf, 0xee, 0x18,
0x00, 0xf0, 0x03, 0x00, 0x00, 0x80, 0xfd, 0xff, 0x1b, 0xdc, 0xf6, 0xcf,
0xdf, 0xc0, 0x19, 0x00, 0x70, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x03, 0x98,
0x01, 0xb6, 0xcf, 0x93, 0x80, 0x33, 0x00, 0x30, 0x00, 0x00, 0x00, 0x80,
0x7f, 0x01, 0x1c, 0xc0, 0xfe, 0xff, 0x9f, 0x00, 0x03, 0x00, 0x30, 0x00,
0x00, 0x00, 0x80, 0x9f, 0x01, 0x0c, 0xc0, 0xff, 0xe7, 0x9b, 0x01, 0x06,
0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x0e, 0xcc, 0xff, 0xe3,
0xbb, 0x01, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0x07,
0x8c, 0xff, 0xf9, 0xbb, 0x01, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x80,
0xbf, 0xff, 0xcf, 0x1f, 0xdf, 0xfd, 0xbb, 0x09, 0x38, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x80, 0xfb, 0xff, 0x8d, 0xdf, 0x6f, 0xfc, 0xbb, 0x01, 0x70,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x8f, 0xff, 0x3f, 0xff,
0xbb, 0x01, 0x60, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xef, 0xe0, 0x8f,
0xbf, 0x1f, 0xbf, 0xab, 0x09, 0xe0, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
0xff, 0xf0, 0x8d, 0xd6, 0xc3, 0xbb, 0xab, 0x01, 0xc0, 0x01, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x31, 0x00, 0x7e, 0xe0, 0x39, 0xab, 0x19, 0x80,
0x03, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x66, 0x19, 0x80, 0x79, 0x7c, 0x3c,
0xa9, 0x01, 0x00, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x19, 0x80,
0x6d, 0x7e, 0x1c, 0xb1, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x1f, 0x80, 0x0d, 0x1c, 0x10, 0xb1, 0x01, 0x00, 0x06, 0x0e, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x3f, 0x10, 0x00, 0x38, 0x00, 0xb1, 0x01, 0x00,
0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3d, 0xb3, 0x00, 0x3b, 0x00,
0xa1, 0x01, 0x00, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe7, 0xf1,
0xd8, 0x7f, 0x03, 0xb1, 0x01, 0x00, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc3, 0xfb, 0xf0, 0x7f, 0x01, 0xb1, 0x01, 0x00, 0x18, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x83, 0xfb, 0xf0, 0x7f, 0x01, 0xb1, 0x01, 0x00,
0x18, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x01, 0x7f, 0x00,
0x80, 0x01, 0x00, 0x30, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f,
0x01, 0xff, 0x07, 0x80, 0x01, 0x00, 0x30, 0x06, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xfd, 0x1d, 0x01, 0xfb, 0x3f, 0x80, 0x01, 0x00, 0x70, 0x06, 0x00,
0x00, 0x00, 0x00, 0xc0, 0xf0, 0xde, 0x67, 0x18, 0x7f, 0x80, 0x01, 0x00,
0x60, 0x07, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x78, 0xcf, 0x0f, 0x86, 0xfd,
0x81, 0x01, 0x00, 0x65, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xaf, 0xbf,
0x3d, 0x80, 0xf9, 0x81, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
0xe0, 0xaf, 0xff, 0x78, 0x00, 0xe0, 0x83, 0x01, 0x7f, 0xf8, 0x01, 0x00,
0x00, 0x00, 0x00, 0x70, 0xfe, 0x7f, 0x70, 0x20, 0x6c, 0x87, 0xe0, 0x07,
0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0xf8, 0x0f, 0xf0, 0x30, 0x06,
0xcf, 0xf8, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xdb, 0x0e,
0xd8, 0x00, 0x30, 0xcf, 0x3c, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf8, 0xfb, 0x38, 0xfc, 0x01, 0x20, 0xcc, 0x0f, 0x00, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1c, 0x3e, 0xf8, 0xbf, 0x03, 0x06, 0xfd, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x1e, 0xf8, 0xdf, 0x0f, 0x02,
0xff, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x0f, 0xf0,
0x07, 0x3e, 0x30, 0xfa, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00,
0xfe, 0x07, 0x00, 0x03, 0x78, 0x30, 0xfb, 0x03, 0x00, 0x80, 0x03, 0x00,
0x00, 0x00, 0x00, 0xff, 0x06, 0x00, 0xc3, 0xff, 0x00, 0xff, 0x1f, 0x00,
0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x03, 0x00, 0xbf, 0xdf, 0x01,
0xfe, 0x1f, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00,
0xfe, 0x8f, 0x83, 0xef, 0x0f, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x80,
0xef, 0x00, 0x00, 0xf8, 0x03, 0x83, 0xb1, 0x03, 0x00, 0x60, 0x03, 0x00,
0x00, 0xe0, 0x80, 0x61, 0x00, 0x00, 0x80, 0x01, 0x04, 0xb0, 0x03, 0x03,
0x30, 0x03, 0x00, 0x00, 0xfc, 0xc1, 0x30, 0x06, 0x00, 0x80, 0x01, 0x1e,
0xa0, 0x87, 0x03, 0x30, 0x03, 0x00, 0x00, 0x7e, 0xff, 0xb8, 0x0f, 0x00,
0x80, 0x8b, 0x1f, 0x04, 0x86, 0x03, 0x18, 0x03, 0x00, 0x00, 0xf6, 0x7f,
0xf8, 0x3f, 0x00, 0x80, 0xff, 0x77, 0xfe, 0x86, 0x07, 0x0e, 0x01, 0x00,
0x00, 0xfe, 0x19, 0x00, 0x76, 0x00, 0x00, 0xff, 0x63, 0xf6, 0x86, 0xfd,
0x87, 0x01, 0x00, 0x00, 0xf6, 0x0f, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x60,
0x00, 0x8c, 0xf3, 0x81, 0x01, 0x00, 0x00, 0x06, 0x06, 0xfe, 0x7c, 0x00,
0x00, 0x70, 0xc0, 0x00, 0x8e, 0x07, 0x83, 0x01, 0x00, 0x00, 0xf8, 0xb3,
0xff, 0x7f, 0x00, 0x00, 0x60, 0xc0, 0x9c, 0x0f, 0xff, 0xc1, 0x00, 0x00,
0x00, 0xfc, 0xd9, 0x03, 0x3f, 0x00, 0x00, 0xe0, 0xc0, 0x80, 0x0d, 0x7e,
0xc0, 0x00, 0x00, 0x00, 0x0e, 0xde, 0x00, 0x1c, 0x00, 0x00, 0xe0, 0xff,
0x01, 0xfc, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0xde, 0xdf, 0x00, 0x00, 0x00,
0x00, 0xfe, 0xbf, 0x03, 0xfc, 0x00, 0x66, 0x00, 0x00, 0x00, 0xda, 0xcc,
0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x62, 0x1f, 0x00, 0x67, 0x00, 0x00,
0x00, 0x7e, 0xcc, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x03, 0xe3, 0x5f, 0xc1,
0x33, 0x00, 0x00, 0x00, 0x3e, 0x8e, 0x01, 0x00, 0x00, 0xf8, 0xf1, 0x03,
0x06, 0xfc, 0x7f, 0x33, 0x00, 0x00, 0x00, 0x0e, 0xde, 0x00, 0x00, 0x00,
0x6e, 0xc0, 0x07, 0x0e, 0xfc, 0x1f, 0x13, 0x00, 0x00, 0x00, 0x1e, 0x7c,
0x00, 0x00, 0x00, 0x1f, 0xe2, 0x3f, 0xef, 0x7f, 0x00, 0x1b, 0x00, 0x00,
0x00, 0x1c, 0x6c, 0x02, 0x00, 0x80, 0x07, 0xf8, 0xff, 0x47, 0x0c, 0x80,
0x19, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x03, 0x00, 0xc0, 0x03, 0xfb, 0xff,
0x0d, 0x0c, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x60,
0x40, 0x3f, 0x18, 0x4c, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x01, 0x00, 0x70, 0x40, 0x1f, 0x18, 0xfc, 0x37, 0x80, 0x0b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xb0, 0x1f, 0x18, 0x0c, 0x3e, 0x80,
0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc8, 0x08, 0x78,
0x2c, 0x06, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x60, 0x00, 0xf8, 0xcf, 0x06, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x35, 0x00, 0xf8, 0x9f, 0x06, 0x00, 0xfe, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x00, 0xf8, 0x77, 0x03, 0x00,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x31, 0x00, 0xd8,
0xdd, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
0x1a, 0x00, 0x08, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xce, 0x1e, 0x00, 0x0c, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x18, 0x00, 0x0c, 0x8c, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x1f, 0x00, 0x7c,
0xef, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce,
0x1e, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xce, 0xf0, 0x03, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xfb, 0x01, 0x0c, 0x5f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xef, 0x01, 0x06,
0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
0xd7, 0x81, 0x87, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0xdf, 0xc3, 0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xfe, 0xff, 0xff, 0x3b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xfc, 0x7f, 0xfe,
0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
0xfd, 0x7f, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x37, 0xe6, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf7, 0xe3, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#endif

View File

@@ -1,347 +0,0 @@
/******************************************************************************
* Image functions:
* - Convert a 1bit framebuffer in RAM to
* - GIF, compressed, based on giflib and gif_hash
* - PBM, portable bitmap, very simple copy
* - BMP, bigger with a little bit fiddling around
*
* SPDX-License-Identifier: MIT
*****************************************************************************/
#include <Arduino.h> // needed for PROGMEM
#include <vector>
#include "GwLog.h" // needed for logger
#include "imglib.h"
GifFilePrivateType gifprivate;
void ClearHashTable(GifHashTableType *HashTable) {
memset(HashTable->HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
}
GifHashTableType *InitHashTable(void) {
GifHashTableType *HashTable;
if ((HashTable = (GifHashTableType *)ps_malloc(sizeof(GifHashTableType))) == NULL) {
return NULL;
}
ClearHashTable(HashTable);
return HashTable;
}
static int KeyItem(uint32_t Item) {
return ((Item >> 12) ^ Item) & HT_KEY_MASK;
}
void InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code) {
int HKey = KeyItem(Key);
uint32_t *HTable = HashTable->HTable;
while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
HKey = (HKey + 1) & HT_KEY_MASK;
}
HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
}
int ExistsHashTable(GifHashTableType *HashTable, uint32_t Key) {
int HKey = KeyItem(Key);
uint32_t *HTable = HashTable->HTable, HTKey;
while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
if (Key == HTKey) {
return HT_GET_CODE(HTable[HKey]);
}
HKey = (HKey + 1) & HT_KEY_MASK;
}
return -1;
}
/******************************************************************************
Put 2 bytes (a word) into the given file in little-endian order:
******************************************************************************/
void GifPutWord(std::vector<uint8_t>* gifBuffer, uint16_t Word) {
/*cuint8_t c[2];
[0] = LOBYTE(Word);
c[1] = HIBYTE(Word);
gifBuffer->push_back(c[0]);
gifBuffer->push_back(c[1]); */
gifBuffer->push_back(LOBYTE(Word));
gifBuffer->push_back(HIBYTE(Word));
}
/******************************************************************************
This routines buffers the given characters until 255 characters are ready
to be output. If Code is equal to -1 the buffer is flushed (EOF).
The buffer is Dumped with first byte as its size, as GIF format requires.
******************************************************************************/
void GifBufferedOutput(std::vector<uint8_t>* gifBuffer, GifByteType *Buf, int c) {
if (c == FLUSH_OUTPUT) {
// Flush everything out.
for (int i = 0; i < Buf[0] + 1; i++) {
gifBuffer->push_back(Buf[i]);
}
// Mark end of compressed data, by an empty block (see GIF doc):
Buf[0] = 0;
gifBuffer->push_back(0);
} else {
if (Buf[0] == 255) {
// Dump out this buffer - it is full:
for (int i = 0; i < Buf[0] + 1; i++) {
gifBuffer->push_back(Buf[i]);
}
Buf[0] = 0;
}
Buf[++Buf[0]] = c;
}
}
/******************************************************************************
The LZ compression output routine:
This routine is responsible for the compression of the bit stream into
8 bits (bytes) packets.
******************************************************************************/
void GifCompressOutput(std::vector<uint8_t>* gifBuffer, const int Code) {
if (Code == FLUSH_OUTPUT) {
while (gifprivate.CrntShiftState > 0) {
// Get Rid of what is left in DWord, and flush it.
GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
gifprivate.CrntShiftDWord >>= 8;
gifprivate.CrntShiftState -= 8;
}
gifprivate.CrntShiftState = 0; // For next time.
GifBufferedOutput(gifBuffer, gifprivate.Buf, FLUSH_OUTPUT);
} else {
gifprivate.CrntShiftDWord |= ((long)Code) << gifprivate.CrntShiftState;
gifprivate.CrntShiftState += gifprivate.RunningBits;
while (gifprivate.CrntShiftState >= 8) {
// Dump out full bytes:
GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
gifprivate.CrntShiftDWord >>= 8;
gifprivate.CrntShiftState -= 8;
}
}
/* If code cannt fit into RunningBits bits, must raise its size. Note */
/* however that codes above LZ_MAX_CODE are used for special signaling. */
if (gifprivate.RunningCode >= gifprivate.MaxCode1 && Code <= LZ_MAX_CODE) {
gifprivate.MaxCode1 = 1 << ++gifprivate.RunningBits;
}
}
/******************************************************************************
Setup the LZ compression for this image:
******************************************************************************/
void GifSetupCompress(std::vector<uint8_t>* gifBuffer) {
gifBuffer->push_back(0x02);// Bits per pixel wit minimum 2
gifprivate.Buf[0] = 0; // Nothing was output yet
gifprivate.BitsPerPixel = 2; // Minimum is 2
gifprivate.ClearCode = (1 << 2);
gifprivate.EOFCode = gifprivate.ClearCode + 1;
gifprivate.RunningCode = gifprivate.EOFCode + 1;
gifprivate.RunningBits = 2 + 1; // Number of bits per code
gifprivate.MaxCode1 = 1 << gifprivate.RunningBits; // Max. code + 1
gifprivate.CrntCode = FIRST_CODE; // Signal that this is first one!
gifprivate.CrntShiftState = 0; // No information in CrntShiftDWord
gifprivate.CrntShiftDWord = 0;
GifCompressOutput(gifBuffer, gifprivate.ClearCode);
}
void createGifHeader(std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
// SCREEN DESCRIPTOR
gifBuffer->push_back('G');
gifBuffer->push_back('I');
gifBuffer->push_back('F');
gifBuffer->push_back('8');
gifBuffer->push_back('7');
gifBuffer->push_back('a');
GifPutWord(gifBuffer, width);
GifPutWord(gifBuffer, height);
gifBuffer->push_back(0x80 | (1 << 4));
gifBuffer->push_back(0x00); // Index into the ColorTable for background color
gifBuffer->push_back(0x00); // Pixel Aspect Ratio
// Colormap
gifBuffer->push_back(0xff); // Color 0
gifBuffer->push_back(0xff);
gifBuffer->push_back(0xff);
gifBuffer->push_back(0x00); // Color 1
gifBuffer->push_back(0x00);
gifBuffer->push_back(0x00);
// IMAGE DESCRIPTOR
gifBuffer->push_back(DESCRIPTOR_INTRODUCER);
GifPutWord(gifBuffer, 0);
GifPutWord(gifBuffer, 0);
GifPutWord(gifBuffer, width);
GifPutWord(gifBuffer, height);
gifBuffer->push_back(0x00); // No colormap here , we use the global one
}
/******************************************************************************
The LZ compression routine:
This version compresses the given buffer Line of length LineLen.
This routine can be called a few times (one per scan line, for example), in
order to complete the whole image.
******************************************************************************/
void GifCompressLine(std::vector<uint8_t>* gifBuffer, const GifPixelType *Line, const int LineLen) {
int i = 0, CrntCode;
GifHashTableType *HashTable;
HashTable = gifprivate.HashTable;
if (gifprivate.CrntCode == FIRST_CODE) { // Its first time!
CrntCode = Line[i++];
} else {
CrntCode =
gifprivate.CrntCode; // Get last code in compression
}
while (i < LineLen) { // Decode LineLen items
GifPixelType Pixel = Line[i++]; // Get next pixel from stream.
/* Form a new unique key to search hash table for the code
* combines CrntCode as Prefix string with Pixel as postfix
* char.
*/
int NewCode;
unsigned long NewKey = (((uint32_t)CrntCode) << 8) + Pixel;
if ((NewCode = ExistsHashTable(HashTable, NewKey)) >= 0) {
/* This Key is already there, or the string is old one,
* so simple take new code as our CrntCode:
*/
CrntCode = NewCode;
} else {
/* Put it in hash table, output the prefix code, and
* make our CrntCode equal to Pixel.
*/
GifCompressOutput(gifBuffer, CrntCode);
CrntCode = Pixel;
/* If however the HashTable if full, we send a clear
* first and Clear the hash table.
*/
if (gifprivate.RunningCode >= LZ_MAX_CODE) {
// Time to do some clearance:
GifCompressOutput(gifBuffer, gifprivate.ClearCode);
gifprivate.RunningCode = gifprivate.EOFCode + 1;
gifprivate.RunningBits = gifprivate.BitsPerPixel + 1;
gifprivate.MaxCode1 = 1 << gifprivate.RunningBits;
ClearHashTable(HashTable);
} else {
// Put this unique key with its relative Code in hash table:
InsertHashTable(HashTable, NewKey, gifprivate.RunningCode++);
}
}
}
// Preserve the current state of the compression algorithm:
gifprivate.CrntCode = CrntCode;
if (gifprivate.PixelCount == 0) {
// We are done - output last Code and flush output buffers:
GifCompressOutput(gifBuffer, CrntCode);
GifCompressOutput(gifBuffer, gifprivate.EOFCode);
GifCompressOutput(gifBuffer, FLUSH_OUTPUT);
}
}
bool createBMP(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
// For BMP the line size has to be a multiple of 4 bytes.
// So padding is needed. Also the lines have to be in reverded
// order compared to plain buffer
// BMP header for black-and-white image (1 bit per pixel)
const uint8_t bmp_header[] PROGMEM = {
// BITMAPFILEHEADER (14 Bytes)
0x42, 0x4D, // bfType: 'BM' signature
0x2e, 0x3d, 0x00, 0x00, // bfSize: file size in bytes
0x00, 0x00, // bfReserved1
0x00, 0x00, // bfReserved2
0x3e, 0x00, 0x00, 0x00, // bfOffBits: offset in bytes to pixeldata
// BITMAPINFOHEADER (40 Bytes)
0x28, 0x00, 0x00, 0x00, // biSize: DIB header size
(uint8_t)LOBYTE(width), (uint8_t)HIBYTE(width), 0x00, 0x00, // biWidth
(uint8_t)LOBYTE(height), (uint8_t)HIBYTE(height), 0x00, 0x00, // biHeight
0x01, 0x00, // biPlanes: Number of color planes (1)
0x01, 0x00, // biBitCount: Color depth (1 bit per pixel)
0x00, 0x00, 0x00, 0x00, // biCompression: Compression (none)
0xf0, 0x3c, 0x00, 0x00, // biSizeImage: Image data size (calculate)
0x13, 0x0b, 0x00, 0x00, // biXPelsPerMeter: Horizontal resolution (2835 pixels/meter)
0x13, 0x0b, 0x00, 0x00, // biYPelsPerMeter: Vertical resolution (2835 pixels/meter)
0x02, 0x00, 0x00, 0x00, // biClrUsed: Colors in color palette (2)
0x00, 0x00, 0x00, 0x00, // biClrImportant: Important colors (all)
// PALETTE: COLORTRIPLES of RGBQUAD (n * 4 Bytes)
0x00, 0x00, 0x00, 0x00, // Color palette: Black
0xff, 0xff, 0xff, 0x00 // Color palette: White
};
size_t bmp_headerSize = sizeof(bmp_header);
size_t lineSize = (width / 8);
size_t paddingSize = 0;
if (lineSize % 4 != 0) {
paddingSize = 4 - lineSize % 4;
}
size_t imageSize = bmp_headerSize + (lineSize + paddingSize) * height;
imageBuffer->resize(imageSize);
memcpy(imageBuffer->data(), bmp_header, bmp_headerSize);
for (int y = 0; y < height; y++) {
uint8_t* srcRow = frameBuffer + (y * lineSize);
uint8_t* destRow = imageBuffer->data() + bmp_headerSize + ((height - 1 - y) * (lineSize + paddingSize));
memcpy(destRow, srcRow, lineSize);
for (int j = 0; j < paddingSize; j++) {
destRow[lineSize + j] = 0x00;
}
}
return true;
}
bool createPBM(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
// creates binary PBM image inside imagebuffer
// returns bytesize of created image
const char pbm_header[] PROGMEM = "P4\n#Created by OBP60\n400 300\n";
size_t pbm_headerSize = sizeof(pbm_header) - 1; // We don't want trailing zero
size_t imageSize = pbm_headerSize + width / 8 * height;
imageBuffer->resize(imageSize);
memcpy(imageBuffer->data(), pbm_header, pbm_headerSize);
memcpy(imageBuffer->data() + pbm_headerSize, frameBuffer, width / 8 * height);
return true;
}
bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
size_t imageSize = 0;
uint16_t bufOffset = 0; // Offset into imageBuffer for next write access
gifprivate.HashTable = InitHashTable();
if (gifprivate.HashTable == NULL) {
return false;
}
gifprivate.PixelCount = width * height;
createGifHeader(gifBuffer, width, height);
// Reset compress algorithm parameters.
GifSetupCompress(gifBuffer);
gifBuffer->reserve(4096); // to avoid lots of alloactions
GifPixelType line[width];
for (int y = 0; y < height; y++) {
// convert uint8_t pixels to single pixels
for (int x = 0; x < width; x++) {
int byteIndex = (y * width + x) / 8;
uint8_t bitIndex = 7 - ((y * width + x) % 8);
line[x] = (framebuffer[byteIndex] & (uint8_t)(1 << bitIndex)) == 0;
}
gifprivate.PixelCount -= width;
GifCompressLine(gifBuffer, line, width);
}
gifBuffer->push_back(TERMINATOR_INTRODUCER);
free((GifHashTableType *)gifprivate.HashTable);
return true;
}

View File

@@ -1,70 +0,0 @@
/******************************************************************************
*
* imglib.h
*
* SPDX-License-Identifier: MIT
*****************************************************************************/
#ifndef _IMGLIB_H_
#define _IMGLIB_H_ 1
// extract bytes from an unsigned word
#define LOBYTE(x) ((x)&0xff)
#define HIBYTE(x) (((x) >> 8) & 0xff)
// GIF encoding constants
#define DESCRIPTOR_INTRODUCER 0x2c
#define TERMINATOR_INTRODUCER 0x3b
#define LZ_MAX_CODE 4095 // Biggest code possible in 12 bits
#define LZ_BITS 12
#define FLUSH_OUTPUT 4096 // Impossible code, to signal flush
#define FIRST_CODE 4097 // Impossible code, to signal first
#define NO_SUCH_CODE 4098 // Impossible code, to signal empty
// magfic constants and declarations for GIF LZW
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
/* The 32 bits of the long are divided into two parts for the key & code: */
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
/* The key is the upper 20 bits. The code is the lower 12. */
#define HT_GET_KEY(l) (l >> 12)
#define HT_GET_CODE(l) (l & 0x0FFF)
#define HT_PUT_KEY(l) (l << 12)
#define HT_PUT_CODE(l) (l & 0x0FFF)
typedef unsigned char GifPixelType;
typedef unsigned char GifByteType;
typedef struct GifHashTableType {
uint32_t HTable[HT_SIZE];
} GifHashTableType;
typedef struct GifFilePrivateType {
uint8_t BitsPerPixel; // Bits per pixel (Codes uses at least this + 1)
uint16_t ClearCode; // The CLEAR LZ code
uint16_t EOFCode; // The EOF LZ code
uint16_t RunningCode; // The next code algorithm can generate
uint16_t RunningBits; // The number of bits required to represent RunningCode
uint16_t MaxCode1; // 1 bigger than max. possible code, in RunningBits bits
uint16_t LastCode; // The code before the current code.
uint16_t CrntCode; // Current algorithm code
uint16_t CrntShiftState; // Number of bits in CrntShiftDWord
uint32_t CrntShiftDWord; // For bytes decomposition into codes
uint32_t PixelCount; // Number of pixels in image
GifByteType Buf[256]; // Compressed input is buffered here
GifHashTableType *HashTable;
} GifFilePrivateType;
bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
bool createBMP(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
bool createPBM(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height);
#endif /* _IMGLIB_H */

View File

@@ -1,4 +1,4 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#include "obp60task.h"
#include "Pagedata.h" // Data exchange for pages
#include "OBP60Hardware.h" // PIN definitions
@@ -9,17 +9,9 @@
#include <NMEA0183.h> // NMEA0183
#include <NMEA0183Msg.h>
#include <NMEA0183Messages.h>
#include <GxEPD2_BW.h> // GxEPD2 lib for b/w E-Ink displays
#include <GxEPD2_BW.h> // GxEPD2 lib for black 6 white E-Ink displays
#include "OBP60Extensions.h" // Functions lib for extension board
#include "OBP60Keypad.h" // Functions for keypad
#include "BoatDataCalibration.h" // Functions lib for data instance calibration
#ifdef BOARD_OBP40S3
#include "driver/rtc_io.h" // Needs for weakup from deep sleep
#include <FS.h> // SD-Card access
#include <SD.h>
#include <SPI.h>
#endif
// True type character sets includes
// See OBP60ExtensionPort.cpp
@@ -28,10 +20,10 @@
//#include GxEPD_BitmapExamples // Example picture
#include "MFD_OBP60_400x300_sw.h" // MFD with logo
#include "Logo_OBP_400x300_sw.h" // OBP Logo
#include "images/unknown.xbm" // unknown page indicator
#include "OBP60QRWiFi.h" // Functions lib for WiFi QR code
#include "OBPSensorTask.h" // Functions lib for sensor data
#include "LedSpiTask.h"
// Global vars
bool initComplete = false; // Initialization complete
@@ -41,9 +33,6 @@ int taskRunCounter = 0; // Task couter for loop section
//####################################################################################
void OBP60Init(GwApi *api){
GwLog *logger = api->getLogger();
GwConfigHandler *config = api->getConfig();
// Set a new device name and hidden the original name in the main config
String devicename = api->getConfig()->getConfigItem(api->getConfig()->deviceName,true)->asString();
api->getConfig()->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN);
@@ -54,60 +43,18 @@ void OBP60Init(GwApi *api){
// Init hardware
hardwareInit(api);
hardwareInit();
// Init power rail 5.0V
String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
if(powermode == "Max Power" || powermode == "Only 5.0V"){
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
setPortPin(OBP_POWER_SD, true); // Power on SD card
#endif
}
else{
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
#endif
}
#ifdef BOARD_OBP40S3
bool sdcard = config->getBool(config->useSDCard);
if (sdcard) {
SPIClass SD_SPI = SPIClass(HSPI);
SD_SPI.begin(SD_SPI_CLK, SD_SPI_MISO, SD_SPI_MOSI);
if (SD.begin(SD_SPI_CS, SD_SPI, 80000000)) {
String sdtype = "unknown";
uint8_t cardType = SD.cardType();
switch (cardType) {
case CARD_MMC:
sdtype = "MMC";
break;
case CARD_SD:
sdtype = "SDSC";
break;
case CARD_SDHC:
sdtype = "SDHC";
break;
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG(GwLog::LOG,"SD card type %s of size %d MB detected", sdtype, cardSize);
}
}
// Deep sleep wakeup configuration
esp_sleep_enable_ext0_wakeup(OBP_WAKEWUP_PIN, 0); // 1 = High, 0 = Low
rtc_gpio_pullup_en(OBP_WAKEWUP_PIN); // Activate pullup resistor
rtc_gpio_pulldown_dis(OBP_WAKEWUP_PIN); // Disable pulldown resistor
#endif
// Settings for e-paper display
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Fast Refresh Mode is: %s", fastrefresh.c_str());
@@ -117,16 +64,6 @@ void OBP60Init(GwApi *api){
}
#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
int freq = getCpuFrequencyMhz();
api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq);
@@ -139,10 +76,10 @@ void OBP60Init(GwApi *api){
if(String(backlightMode) == "On"){
setBacklightLED(brightness, colorMapping(backlightColor));
}
else if(String(backlightMode) == "Off"){
if(String(backlightMode) == "Off"){
setBacklightLED(0, COLOR_BLACK); // Backlight LEDs off (blue without britghness)
}
else if(String(backlightMode) == "Control by Key"){
if(String(backlightMode) == "Control by Key"){
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
}
@@ -169,7 +106,6 @@ typedef struct {
GwLog* logger = NULL;
// GwApi* api = NULL;
uint sensitivity = 100;
bool use_syspage = true;
} MyData;
// Keyboard Task
@@ -181,7 +117,7 @@ void keyboardTask(void *param){
// Loop for keyboard task
while (true){
keycode = readKeypad(data->logger, data->sensitivity, data->use_syspage);
keycode = readKeypad(data->sensitivity);
//send a key event
if(keycode != 0){
xQueueSend(data->queue, &keycode, 0);
@@ -247,6 +183,13 @@ class PageList{
}
};
class PageStruct{
public:
Page *page=NULL;
PageData parameters;
PageDescription *description=NULL;
};
/**
* this function will add all the pages we know to the pagelist
* each page should have defined a registerXXXPage variable of type
@@ -258,23 +201,19 @@ void registerAllPages(PageList &list){
//this way this separate source file can be compiled by it's own
//and has no access to any of our data except the one that we
//give as a parameter to the page function
extern PageDescription registerPageSystem;
//we add the variable to our list
list.add(&registerPageSystem);
extern PageDescription registerPageOneValue;
//we add the variable to our list
list.add(&registerPageOneValue);
extern PageDescription registerPageTwoValues;
list.add(&registerPageTwoValues);
extern PageDescription registerPageThreeValues;
list.add(&registerPageThreeValues);
extern PageDescription registerPageSixValues;
list.add(&registerPageSixValues);
extern PageDescription registerPageFourValues;
list.add(&registerPageFourValues);
extern PageDescription registerPageFourValues2;
list.add(&registerPageFourValues2);
extern PageDescription registerPageWind;
list.add(&registerPageWind);
extern PageDescription registerPageApparentWind;
list.add(&registerPageApparentWind);
extern PageDescription registerPageWindRose;
list.add(&registerPageWindRose);
extern PageDescription registerPageWindRoseFlex;
@@ -285,8 +224,6 @@ void registerAllPages(PageList &list){
list.add(&registerPageDST810);
extern PageDescription registerPageClock;
list.add(&registerPageClock);
extern PageDescription registerPageCompass;
list.add(&registerPageCompass);
extern PageDescription registerPageWhite;
list.add(&registerPageWhite);
extern PageDescription registerPageBME280;
@@ -309,44 +246,19 @@ void registerAllPages(PageList &list){
list.add(&registerPageXTETrack);
extern PageDescription registerPageFluid;
list.add(&registerPageFluid);
extern PageDescription registerPageBarograph;
list.add(&registerPageBarograph);
}
// Undervoltage detection for shutdown display
void underVoltageDetection(GwApi *api, CommonData &common){
// Read settings
double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat();
double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat();
// Read supply voltage
#if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
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
double calVoltage = actVoltage * vslope + voffset; // Calibration
if(calVoltage < 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_Bold20pt8b);
getdisplay().setCursor(65, 150);
getdisplay().print("Undervoltage");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(65, 175);
getdisplay().print("Charge battery and restart system");
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
float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat());
float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat());
// Read supplay voltage
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // V = 1/20 * Vin
actVoltage = actVoltage * vslope + voffset;
if(actVoltage < MIN_VOLTAGE){
// Switch off all power lines
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
setFlashLED(false); // Flash LED Off
@@ -354,17 +266,13 @@ void underVoltageDetection(GwApi *api, CommonData &common){
setPortPin(OBP_POWER_50, false); // Power rail 5.0V Off
// Shutdown EInk display
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().fillScreen(common.bgcolor);// Clear screen
getdisplay().fillScreen(common.bgcolor); // Clear screen
getdisplay().setTextColor(common.fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt8b);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(65, 150);
getdisplay().print("Undervoltage");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(65, 175);
getdisplay().print("To wake up repower system");
getdisplay().nextPage(); // Partial update
getdisplay().powerOff(); // Display power off
#endif
// Stop system
while(true){
esp_deep_sleep_start(); // Deep Sleep without weakup. Weakup only after power cycle (restart).
@@ -379,27 +287,20 @@ void OBP60Task(GwApi *api){
// return;
GwLog *logger=api->getLogger();
GwConfigHandler *config=api->getConfig();
#ifdef HARDWARE_V21
startLedTask(api);
#endif
PageList allPages;
registerAllPages(allPages);
CommonData commonData;
commonData.logger=logger;
commonData.config=config;
#ifdef HARDWARE_V21
// Keyboard coordinates for page footer
initKeys(commonData);
#endif
tN2kMsg N2kMsg;
LOG_DEBUG(GwLog::LOG,"obp60task started");
for (auto it=allPages.pages.begin();it != allPages.pages.end();it++){
LOG_DEBUG(GwLog::LOG,"found registered page %s",(*it)->pageName.c_str());
}
// Init E-Ink display
String displaymode = api->getConfig()->getConfigItem(api->getConfig()->display,true)->asString();
String displaycolor = api->getConfig()->getConfigItem(api->getConfig()->displaycolor,true)->asString();
@@ -416,9 +317,6 @@ void OBP60Task(GwApi *api){
bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
#ifdef BOARD_OBP40S3
bool syspage_enabled = config->getBool(config->systemPage);
#endif
#ifdef DISPLAY_GDEY042T81
getdisplay().init(115200, true, 2, false); // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse
@@ -457,30 +355,6 @@ void OBP60Task(GwApi *api){
// Init pages
int numPages=1;
PageStruct pages[MAX_PAGE_NUMBER];
// Set start page
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;
BoatValueList boatValues; //all the boat values for the api query
//commonData.distanceformat=config->getString(xxx);
//add all necessary data to common data
@@ -504,7 +378,6 @@ void OBP60Task(GwApi *api){
pages[i].description=description;
pages[i].page=description->creator(commonData);
pages[i].parameters.pageName=pageType;
pages[i].parameters.pageNumber = i + 1;
LOG_DEBUG(GwLog::DEBUG,"found page %s for number %d",pageType.c_str(),i);
//fill in all the user defined parameters
for (int uid=0;uid<description->userParam;uid++){
@@ -524,18 +397,6 @@ void OBP60Task(GwApi *api){
pages[i].parameters.values.push_back(value);
}
}
// add out of band system page (always available)
Page *syspage = allPages.pages[0]->creator(commonData);
// Read all calibration data settings from config
calibrationData.readConfig(config, logger);
// Display screenshot handler for HTTP request
// http://192.168.15.1/api/user/OBP60Task/screenshot
api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) {
doImageRequest(api, &pageNumber, pages, request);
});
//now we have prepared the page data
//we start a separate task that will fetch our keys...
MyData allParameters;
@@ -543,9 +404,6 @@ void OBP60Task(GwApi *api){
allParameters.page0=3;
allParameters.queue=xQueueCreate(10,sizeof(int));
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);
SharedData *shared=new SharedData(api);
createSensorTask(shared);
@@ -555,27 +413,16 @@ void OBP60Task(GwApi *api){
// Configuration values for main loop
String gpsFix = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
String backlight = api->getConfig()->getConfigItem(api->getConfig()->backlight,true)->asString();
String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
float tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asFloat();
commonData.backlight.mode = backlightMapping(config->getConfigItem(config->backlight,true)->asString());
commonData.backlight.color = colorMapping(config->getConfigItem(config->blColor,true)->asString());
commonData.backlight.brightness = 2.55 * uint(config->getConfigItem(config->blBrightness,true)->asInt());
commonData.powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
String tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asString();
String backlightColor = api->getConfig()->getConfigItem(api->getConfig()->blColor,true)->asString();
Color color = colorMapping(backlightColor);
uint brightness = 2.55 * uint(api->getConfig()->getConfigItem(api->getConfig()->blBrightness,true)->asInt());
bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean();
String cpuspeed = api->getConfig()->getConfigItem(api->getConfig()->cpuSpeed,true)->asString();
uint hdopAccuracy = uint(api->getConfig()->getConfigItem(api->getConfig()->hdopAccuracy,true)->asInt());
double homelat = commonData.config->getString(commonData.config->homeLAT).toDouble();
double homelon = commonData.config->getString(commonData.config->homeLON).toDouble();
bool homevalid = homelat >= -180.0 and homelat <= 180 and homelon >= -90.0 and homelon <= 90.0;
if (homevalid) {
LOG_DEBUG(GwLog::LOG, "Home location set to %f : %f", homelat, homelon);
} else {
LOG_DEBUG(GwLog::LOG, "No valid home location found");
}
// refreshmode defined in init section
// Boat values for main loop
@@ -586,6 +433,9 @@ void OBP60Task(GwApi *api){
GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP
LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop");
// Set start page
int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
int lastPage=pageNumber;
commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime
commonData.date = boatValues.findValueOrCreate("GPSD"); // Load GpsTime
@@ -598,22 +448,18 @@ void OBP60Task(GwApi *api){
long starttime3 = millis(); // Display update all 1s
long starttime4 = millis(); // Delayed display update after 4s when select a new page
long starttime5 = millis(); // Calculate sunrise and sunset all 1s
pages[pageNumber].page->setupKeys(); // Initialize keys for first page
// Main loop runs with 100ms
//####################################################################################
bool systemPage = false;
Page *currentPage;
while (true){
delay(100); // Delay 100ms (loop time)
bool keypressed = false;
// Undervoltage detection
if(uvoltage == true){
underVoltageDetection(api, commonData);
}
}
// Set CPU speed after boot after 1min
if(millis() > firststart + (1 * 60 * 1000) && cpuspeedsetted == false){
@@ -650,47 +496,23 @@ void OBP60Task(GwApi *api){
int keyboardMessage=0;
while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){
LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage);
keypressed = true;
if (keyboardMessage == 12 and !systemPage) {
LOG_DEBUG(GwLog::LOG, "Calling system page");
systemPage = true; // System page is out of band
syspage->setupKeys();
keyboardMessage = 0;
Page *currentPage=pages[pageNumber].page;
if (currentPage ){
keyboardMessage=currentPage->handleKey(keyboardMessage);
}
else {
currentPage = pages[pageNumber].page;
if (systemPage && keyboardMessage == 1) {
// exit system mode with exit key number 1
systemPage = false;
currentPage->setupKeys();
keyboardMessage = 0;
}
}
if (systemPage) {
keyboardMessage = syspage->handleKey(keyboardMessage);
} else if (currentPage) {
keyboardMessage = currentPage->handleKey(keyboardMessage);
}
if (keyboardMessage > 0) // not handled by page
if (keyboardMessage > 0)
{
// Decoding all key codes
// #6 Backlight on if key controled
if (commonData.backlight.mode == BacklightMode::KEY) {
// if(String(backlight) == "Control by Key"){
if(String(backlight) == "Control by Key"){
if(keyboardMessage == 6){
LOG_DEBUG(GwLog::LOG,"Toggle Backlight LED");
toggleBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
toggleBacklightLED(brightness, color);
}
}
#ifdef BOARD_OBP40S3
// #3 Deep sleep mode for OBP40
if ((keyboardMessage == 3) and !syspage_enabled){
deepSleep(commonData);
}
#endif
// #9 Swipe right or #4 key right
if ((keyboardMessage == 9) or (keyboardMessage == 4))
// #9 Swipe right
if (keyboardMessage == 9)
{
pageNumber++;
if (pageNumber >= numPages){
@@ -699,8 +521,8 @@ void OBP60Task(GwApi *api){
commonData.data.actpage = pageNumber + 1;
commonData.data.maxpage = numPages;
}
// #10 Swipe left or #3 key left
if ((keyboardMessage == 10) or (keyboardMessage == 3))
// #10 Swipe left
if (keyboardMessage == 10)
{
pageNumber--;
if (pageNumber < 0){
@@ -725,20 +547,17 @@ void OBP60Task(GwApi *api){
starttime5 = millis();
if(time->valid == true && date->valid == true && lat->valid == true && lon->valid == true){
// Provide sundata to all pages
commonData.sundata = calcSunsetSunrise(time->value , date->value, lat->value, lon->value, tz);
commonData.sundata = calcSunsetSunrise(api, time->value , date->value, lat->value, lon->value, tz.toDouble());
// Backlight with sun control
if (commonData.backlight.mode == BacklightMode::SUN) {
// if(String(backlight) == "Control by Sun"){
if(String(backlight) == "Control by Sun"){
if(commonData.sundata.sunDown == true){
setBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
setBacklightLED(brightness, color);
}
else{
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
}
}
}
} else if (homevalid and commonData.data.rtcValid) {
// No gps fix but valid home location and time configured
commonData.sundata = calcSunsetSunriseRTC(&commonData.data.rtcTime, homelat, homelon, tz);
}
}
@@ -787,67 +606,37 @@ void OBP60Task(GwApi *api){
}
}
// Refresh display data, default all 1s
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);
// Refresh display data all 1s
if(millis() > starttime3 + 1000){
starttime3 = millis();
//refresh data from api
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
api->getStatus(commonData.status);
// Clear display
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
getdisplay().fillScreen(commonData.bgcolor); // Clear display
// Show header if enabled
if (pages[pageNumber].description && pages[pageNumber].description->header or systemPage){
// build header using commonData
displayHeader(commonData, date, time, hdop); // Show page header
getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor); // Clear display
if (pages[pageNumber].description && pages[pageNumber].description->header){
//build some header and footer using commonData
getdisplay().fillScreen(commonData.bgcolor); // Clear display
displayHeader(commonData, date, time, hdop); // Sown header
}
// Call the particular page
if (systemPage) {
displayFooter(commonData);
PageData sysparams; // empty
syspage->displayPage(sysparams);
Page *currentPage=pages[pageNumber].page;
if (currentPage == NULL){
LOG_DEBUG(GwLog::ERROR,"page number %d not found",pageNumber);
// Error handling for missing page
}
else {
if (currentPage == NULL){
LOG_DEBUG(GwLog::ERROR,"page number %d not found", pageNumber);
// Error handling for missing page
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().fillScreen(commonData.bgcolor); // Clear display
getdisplay().drawXBitmap(200 - unknown_width / 2, 150 - unknown_height / 2, unknown_bits, unknown_width, unknown_height, commonData.fgcolor);
getdisplay().setCursor(140, 250);
getdisplay().setFont(&Atari16px);
getdisplay().print("Here be dragons!");
getdisplay().nextPage(); // Partial update (fast)
else{
if (lastPage != pageNumber){
currentPage->displayNew(commonData,pages[pageNumber].parameters);
lastPage=pageNumber;
}
else{
if (lastPage != pageNumber){
if (hasFRAM) fram.write(FRAM_PAGE_NO, pageNumber); // remember page for device restart
currentPage->setupKeys();
currentPage->displayNew(pages[pageNumber].parameters);
lastPage=pageNumber;
}
//call the page code
LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber);
// Show footer if enabled (together with header)
if (pages[pageNumber].description && pages[pageNumber].description->header){
displayFooter(commonData);
}
currentPage->displayPage(pages[pageNumber].parameters);
}
//call the page code
LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber);
currentPage->displayPage(commonData,pages[pageNumber].parameters);
}
} // refresh display all 1s
}
}
}
vTaskDelete(NULL);

View File

@@ -1,30 +1,17 @@
#pragma once
#include "GwApi.h"
//we only compile for some boards
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#ifdef BOARD_OBP60S3
#define USBSerial Serial
#ifdef HARDWARE_V21
// CAN NMEA2000
#define ESP32_CAN_TX_PIN 46
#define ESP32_CAN_RX_PIN 3
// Bus load in 50mA steps
#define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on
// RS485 NMEA0183
#define GWSERIAL_TX 17
#define GWSERIAL_RX 8
#define GWSERIAL_MODE "UNI"
#endif
#ifdef BOARD_OBP40S3
// CAN NMEA2000
#define ESP32_CAN_TX_PIN 15
#define ESP32_CAN_RX_PIN 16
// Bus load in 50mA steps
#define N2K_LOAD_LEVEL 2 // 2x50mA = 100mA max bus load
// RS485 NMEA0183
#define GWSERIAL_TX 9
#define GWSERIAL_RX 14
#define GWSERIAL_MODE "UNI"
#endif
// CAN NMEA2000
#define ESP32_CAN_TX_PIN 46
#define ESP32_CAN_RX_PIN 3
// Bus load in 50mA steps
#define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on
// RS485 NMEA0183
#define GWSERIAL_TX 17
#define GWSERIAL_RX 8
#define GWSERIAL_MODE "UNI"
// Allowed to set a new password for access point
#define FORCE_AP_PWCHANGE
@@ -35,11 +22,6 @@
// OBP60 Task
void OBP60Task(GwApi *param);
DECLARE_USERTASK_PARAM(OBP60Task, 35000); // Need 35k RAM as stack size
#ifdef HARDWARE_V21
DECLARE_CAPABILITY(obp60,true);
#endif
#ifdef BOARD_OBP40S3
DECLARE_CAPABILITY(obp40,true)
#endif
DECLARE_STRING_CAPABILITY(HELP_URL, "https://obp60-v2-docu.readthedocs.io/de/latest/"); // Link to help pages
#endif
#endif

View File

@@ -2,11 +2,7 @@
#if you want a pio run to only build
#your special environments you can set this here
#by uncommenting the next line
default_envs =
obp60_s3
obp40_s3
default_envs = obp60_s3
[env:obp60_s3]
platform = espressif32@6.8.1
board_build.variants_dir = variants
@@ -21,16 +17,14 @@ lib_deps =
${basedeps.lib_deps}
Wire
SPI
ESP32time
esphome/AsyncTCP-esphome@2.0.1
robtillaart/PCF8574@0.3.9
adafruit/Adafruit Unified Sensor @ 1.1.13
blemasle/MCP23017@2.0.0
adafruit/Adafruit BusIO@1.5.0
adafruit/Adafruit GFX Library@1.11.9
#zinggjm/GxEPD2@1.5.8
zinggjm/GxEPD2@1.5.8
#https://github.com/ZinggJM/GxEPD2
https://github.com/thooge/GxEPD2
sstaub/Ticker@4.4.0
adafruit/Adafruit BMP280 Library@2.6.2
adafruit/Adafruit BME280 Library@2.2.2
@@ -40,67 +34,23 @@ lib_deps =
paulstoffregen/OneWire@2.3.8
milesburton/DallasTemperature@3.11.0
signetica/SunRise@2.0.2
adafruit/Adafruit FRAM I2C@^2.0.3
build_flags=
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
# -D ARDUINO_USB_MODE=1 #0=OTG (to implement other external devices), 1=CDC (is a serial device)
# -D ARDUINO_USB_CDC_ON_BOOT=1 #0=JTAG, 1=CDC (serial device)
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (seral device)
# -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC)
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
-D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3
# -D HARDWARE_V20 #OBP60 hardware revision V2.0
-D HARDWARE_V21 #OBP60 hardware revision V2.1
# -D HARDWARE_V20 #Hardware revision V2.0
-D HARDWARE_V21 #Hardware revision V2.1
# -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
# -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
# -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm
${env.build_flags}
#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
upload_port = /dev/ttyACM0 #OBP60 download via USB-C direct
upload_port = /dev/ttyACM0
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_speed = 230400
monitor_speed = 115200
[env:obp40_s3]
platform = espressif32@6.8.1
board_build.variants_dir = variants
board = obp40_s3_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone (CrowPanel 4.2)
board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
custom_config = config_obp40.json
framework = arduino
lib_deps =
${basedeps.lib_deps}
Wire
SPI
SD
ESP32time
esphome/AsyncTCP-esphome@2.0.1
robtillaart/PCF8574@0.3.9
adafruit/Adafruit Unified Sensor @ 1.1.13
blemasle/MCP23017@2.0.0
adafruit/Adafruit BusIO@1.5.0
adafruit/Adafruit GFX Library@1.11.9
#zinggjm/GxEPD2@1.5.8
#https://github.com/ZinggJM/GxEPD2
https://github.com/thooge/GxEPD2
sstaub/Ticker@4.4.0
adafruit/Adafruit BMP280 Library@2.6.2
adafruit/Adafruit BME280 Library@2.2.2
adafruit/Adafruit BMP085 Library@1.2.1
enjoyneering/HTU21D@1.2.1
robtillaart/INA226@0.2.0
paulstoffregen/OneWire@2.3.8
milesburton/DallasTemperature@3.11.0
signetica/SunRise@2.0.2
adafruit/Adafruit FRAM I2C@^2.0.3
build_flags=
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
-D BOARD_OBP40S3 #Board OBP40 with ESP32S3
-D HARDWARE_V10 #OBP40 hardware revision V1.0 SKU:DIE07300S V1.1 (CrowPanel 4.2)
-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}
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_speed = 230400
monitor_speed = 115200

33
lib/obp60task/run Normal file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
# This script compile the software and loads the bin files into the web flash tool
# in the Gitpod Docker container.
# The web flashtool can be started from the Github website with:
# http://YourGitHubName.github.io/LoRa-Boat-Monitor/flash_tool/esp_flash_tool.html
# Attention! Start this cript only in the Gitpod Docker container.
# Start the script with: bash run
# Path definitions
projectpath="./.pio/build/nodemcu-32s"
toolpath="./docs/flash_tool"
# Install tools
echo "Installing tools"
cd /workspace/esp32-nmea2000
pip3 install -U esptool
pip3 install platformio
# Compile the firmware
echo "Compiling Firmware"
platformio run -e obp60_s3
# Copy all bin files in docs folder for online flash tool
#echo "Copy bin files"
#cp $projectpath/bootloader.bin $toolpath/bootloader.bin
#cp $projectpath/partitions.bin $toolpath/partitions.bin
#cp $projectpath/firmware.bin $toolpath/firmware.bin
# Merge all bin files to one merge file
#echo "Merge all bin files"
#esptool.py --chip ESP32 merge_bin -o $toolpath/merged-firmware.bin --flash_mode dio --flash_size 4MB 0x1000 $toolpath/bootloader.bin 0x8000 $toolpath/partitions.bin 0x10000 $toolpath/firmware.bin

View File

@@ -1,13 +0,0 @@
#!/bin/bash
# This script installing the tool chain
# in the Gitpod Docker container.
# Attention! Start this cript only in the Gitpod Docker container.
# Start the script with: bash run
# Install tools
echo "Installing tools"
cd /workspace/esp32-nmea2000
pip3 install -U esptool
pip3 install platformio

Some files were not shown because too many files have changed in this diff Show More