mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-02-12 07:33:07 +01:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8cf34343f | |||
| c00a0ecbed | |||
| a16ee74b32 | |||
| 601d56ee49 | |||
| 9a04029cb4 | |||
| 22e3ca3875 | |||
| 8e72537286 | |||
| 494acbf0d0 | |||
| d7251eeb8a | |||
| c4406fd009 | |||
| 0097a1eb1e | |||
| c932724473 | |||
| 672a3843d1 | |||
| 1e0acf2a8f | |||
| 63ae42588f | |||
| cba21574cb | |||
| fbe6c1a9a5 | |||
| ae9334236b | |||
| 318a218470 | |||
| c6df6eac56 | |||
| 4513f9d7b0 | |||
| 2749f25d15 | |||
| 992348ce92 | |||
| 8695d3eeb5 | |||
| 54b4954797 | |||
| 1ada6e5a82 | |||
| 15ca3614ba | |||
| e5ca2a3a3d | |||
| cf305e9f5a | |||
| f823dadc6b | |||
| 2d47702627 | |||
| 15674543b6 | |||
| 0dd6b7c9cf | |||
| cbc0c09d65 | |||
| 1d05c2b5d4 | |||
| 38bdc4f577 | |||
| b8a31f2280 | |||
| 7cff3e62e6 | |||
| 39966098cc | |||
| 11a061d5a2 | |||
| 4600cb7228 | |||
| e89d1ac62e | |||
| 6fb5e01969 | |||
| 5c731bc662 | |||
| 25c2742f5b | |||
| 6479c7d711 | |||
| e287bfa72e | |||
| 5a652e2c19 | |||
| 5081f3a684 | |||
| 7de226b447 | |||
| f6e2fa7806 | |||
| d5b0af3b19 | |||
| aed389f3b2 | |||
| 32ba4a64ed | |||
|
|
7edd201daa | ||
| f4d88f1b8b | |||
| 08cd2ad4b1 | |||
| b50d82eff0 | |||
| 6ae4e195d6 | |||
| c5e346f4eb |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -62,5 +62,5 @@ jobs:
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ steps.version.outputs.version}}
|
||||
file: ./.pio/build/*/*${{ steps.version.outputs.version }}*-{all,update}.bin
|
||||
file: ./.pio/build/*/*-{all,update}.bin
|
||||
file_glob: true
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
||||
generated/*
|
||||
lib/generated
|
||||
webinstall/token.php
|
||||
*~
|
||||
|
||||
23
Readme.md
23
Readme.md
@@ -43,10 +43,6 @@ What is included
|
||||
|
||||
For the details of the mapped PGNs and NMEA sentences refer to [Conversions](doc/Conversions.pdf).
|
||||
|
||||
License
|
||||
-------
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either [version 2 of the License](LICENSE), or (at your option) any later version.
|
||||
|
||||
Hardware
|
||||
--------
|
||||
The software is prepared to run on different kinds of ESP32 based modules and accessoirs. For some of them prebuild binaries are available that only need to be flashed, others would require to add some definitions of the used PINs and features and to build the binary.
|
||||
@@ -174,25 +170,6 @@ For details refer to the [example description](lib/exampletask/Readme.md).
|
||||
|
||||
Changelog
|
||||
---------
|
||||
[20251126](../../releases/tag/20251126)
|
||||
* fix a bug in the Actisense reader that could lead to an endless loop (making the device completely non responsive)
|
||||
* upgrade to 4.24.1 of the NMEA2000 library (2025/11/01) - refer to the [changes](https://github.com/ttlappalainen/NMEA2000/blob/master/Documents/src/changes.md) - Especially UTF8 support
|
||||
*********
|
||||
[20251007](../../releases/tag/20251007)
|
||||
*********
|
||||
* add AIS Aton translations (PGN 129041 <-> Ais class 21)
|
||||
* improved mapping of AIS transducer information (NMEA2000) to AIS channel and Talker on NMEA0183
|
||||
* use a forked version of the NMEA2000 library (as an intermediate workaround)
|
||||
* [#114](../../issues/114) correctly translate AIS type 1/3 from PGN 129038
|
||||
* add support for a generic S3 build in the build UI
|
||||
* [#117](../../issues/117) add support for a transmit enable pin for RS 485 conections (also in the build UI)
|
||||
* [#116](../../issues/116) SDA and SCL are swapped in the build UI
|
||||
* [#112](../../issues/112) clearify licenses
|
||||
* [#110](../../issues/110) / [#115](../../pull/115) support for the M5 GPS unit v1.1
|
||||
* [#102](../../issues/102) optimize Wifi reconnect handling
|
||||
* [#111](../../pull/111) allow for a custom python build script
|
||||
* [#113](../../issues/113) support for M5 stack Env4
|
||||
|
||||
[20250305](../../releases/tag/20250305)
|
||||
*********
|
||||
* better handling for reconnect to a raspberry pi after reset [#102](../../issues/102)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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,7 +104,18 @@ def writeFileIfChanged(fileName,data):
|
||||
return True
|
||||
|
||||
def mergeConfig(base,other):
|
||||
for cname in 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:
|
||||
@@ -150,25 +161,13 @@ def expandConfig(config):
|
||||
rt.append(replaceTexts(c,replace))
|
||||
return rt
|
||||
|
||||
def createUserItemList(dirs,itemName,files):
|
||||
rt=[]
|
||||
for d in dirs:
|
||||
iname=os.path.join(d,itemName)
|
||||
if os.path.exists(iname):
|
||||
rt.append(iname)
|
||||
for f in files:
|
||||
if not os.path.exists(f):
|
||||
raise Exception("user item %s not found"%f)
|
||||
rt.append(f)
|
||||
return rt
|
||||
|
||||
def generateMergedConfig(inFile,outFile,addFiles=[]):
|
||||
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,addFiles)
|
||||
config=mergeConfig(config,addDirs)
|
||||
config=expandConfig(config)
|
||||
data=json.dumps(config,indent=2)
|
||||
writeFileIfChanged(outFile,data)
|
||||
@@ -206,6 +205,11 @@ def generateCfg(inFile,outFile,impl):
|
||||
secret="false";
|
||||
if item.get('type') == 'password':
|
||||
secret="true"
|
||||
"""
|
||||
PSRAM Allocator TODO Tests
|
||||
new (heap_caps_malloc(sizeof(GwConfigInterface), MALLOC_CAP_SPIRAM))
|
||||
"""
|
||||
#data+=" new (heap_caps_malloc(sizeof(GwConfigInterface), MALLOC_CAP_SPIRAM)) GwConfigInterface(%s,\"%s\",%s);\n"%(name,item.get('default'),secret)
|
||||
data+=" new GwConfigInterface(%s,\"%s\",%s);\n"%(name,item.get('default'),secret)
|
||||
data+='}\n'
|
||||
writeFileIfChanged(outFile,data)
|
||||
@@ -388,7 +392,12 @@ def getLibs():
|
||||
|
||||
|
||||
|
||||
def joinFiles(target,flist):
|
||||
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
|
||||
@@ -459,28 +468,7 @@ def handleDeps(env):
|
||||
)
|
||||
env.AddBuildMiddleware(injectIncludes)
|
||||
|
||||
def getOption(env,name,toArray=True):
|
||||
try:
|
||||
opt=env.GetProjectOption(name)
|
||||
if toArray:
|
||||
if opt is None:
|
||||
return []
|
||||
if isinstance(opt,list):
|
||||
return opt
|
||||
return opt.split("\n" if "\n" in opt else ",")
|
||||
return opt
|
||||
except:
|
||||
pass
|
||||
if toArray:
|
||||
return []
|
||||
|
||||
def getFileList(files):
|
||||
base=basePath()
|
||||
rt=[]
|
||||
for f in files:
|
||||
if f is not None and f != "":
|
||||
rt.append(os.path.join(base,f))
|
||||
return rt
|
||||
def prebuild(env):
|
||||
global userTaskDirs
|
||||
print("#prebuild running")
|
||||
@@ -490,18 +478,14 @@ def prebuild(env):
|
||||
if ldf_mode == 'off':
|
||||
print("##ldf off - own dependency handling")
|
||||
handleDeps(env)
|
||||
extraConfigs=getOption(env,'custom_config',toArray=True)
|
||||
extraJs=getOption(env,'custom_js',toArray=True)
|
||||
extraCss=getOption(env,'custom_css',toArray=True)
|
||||
|
||||
userTaskDirs=getUserTaskDirs()
|
||||
mergedConfig=os.path.join(outPath(),os.path.basename(CFG_FILE))
|
||||
generateMergedConfig(os.path.join(basePath(),CFG_FILE),mergedConfig,createUserItemList(userTaskDirs,"config.json", getFileList(extraConfigs)))
|
||||
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"),createUserItemList(["web"]+userTaskDirs,INDEXJS,getFileList(extraJs)))
|
||||
joinFiles(os.path.join(outPath(),INDEXCSS+".gz"),createUserItemList(["web"]+userTaskDirs,INDEXCSS,getFileList(extraCss)))
|
||||
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:
|
||||
@@ -522,10 +506,12 @@ def prebuild(env):
|
||||
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")
|
||||
version = "dev{}{}".format(datetime.now().strftime("%Y%m%d"), "-ext")
|
||||
env.Append(CPPDEFINES=[('GWDEVVERSION',version)])
|
||||
|
||||
def cleangenerated(source, target, env):
|
||||
# TODO source / target order?
|
||||
print("CLEAN: {} - {}".format(source, target))
|
||||
od=outPath()
|
||||
if os.path.isdir(od):
|
||||
print("#cleaning up %s"%od)
|
||||
@@ -535,7 +521,6 @@ def cleangenerated(source, target, env):
|
||||
fn=os.path.join(od,f)
|
||||
os.unlink(f)
|
||||
|
||||
|
||||
print("#prescript...")
|
||||
prebuild(env)
|
||||
board="PLATFORM_BOARD_%s"%env["BOARD"].replace("-","_").upper()
|
||||
@@ -547,16 +532,17 @@ env.Append(
|
||||
)
|
||||
#script does not run on clean yet - maybe in the future
|
||||
env.AddPostAction("clean",cleangenerated)
|
||||
extraScripts=getFileList(getOption(env,'custom_script',toArray=True))
|
||||
for script in extraScripts:
|
||||
|
||||
#look for extra task scripts and include them here
|
||||
for taskdir in userTaskDirs:
|
||||
script = os.path.join(taskdir, "extra_task.py")
|
||||
if os.path.isfile(script):
|
||||
print(f"#extra {script}")
|
||||
taskname = os.path.basename(os.path.normpath(taskdir))
|
||||
print("#extra task script for '{}'".format(taskname))
|
||||
with open(script) as fh:
|
||||
try:
|
||||
code = compile(fh.read(), script, 'exec')
|
||||
except SyntaxError as e:
|
||||
print(f"#ERROR: script {script} does not compile: {e}")
|
||||
code = compile(fh.read(), taskname, 'exec')
|
||||
except SyntaxError:
|
||||
print("#ERROR: script does not compile")
|
||||
continue
|
||||
exec(code)
|
||||
else:
|
||||
print(f"#ERROR: script {script} not found")
|
||||
|
||||
@@ -627,7 +627,7 @@ void AisDecoder::decodeType21(PayloadBuffer &_buffer, unsigned int _uMsgType, in
|
||||
}
|
||||
|
||||
// decode message fields (binary buffer has to go through all fields, but some fields are not used)
|
||||
auto repeat=_buffer.getUnsignedValue(2); // repeatIndicator
|
||||
_buffer.getUnsignedValue(2); // repeatIndicator
|
||||
auto mmsi = _buffer.getUnsignedValue(30);
|
||||
auto aidType = _buffer.getUnsignedValue(5);
|
||||
auto name = _buffer.getString(120);
|
||||
@@ -640,11 +640,11 @@ void AisDecoder::decodeType21(PayloadBuffer &_buffer, unsigned int _uMsgType, in
|
||||
auto toStarboard = _buffer.getUnsignedValue(6);
|
||||
|
||||
_buffer.getUnsignedValue(4); // epfd type
|
||||
auto timestamp=_buffer.getUnsignedValue(6); // timestamp
|
||||
auto offPosition=_buffer.getBoolValue(); // off position
|
||||
_buffer.getUnsignedValue(6); // timestamp
|
||||
_buffer.getBoolValue(); // off position
|
||||
_buffer.getUnsignedValue(8); // reserved
|
||||
auto raim=_buffer.getBoolValue(); // RAIM
|
||||
auto virtualAton=_buffer.getBoolValue(); // virtual aid
|
||||
_buffer.getBoolValue(); // RAIM
|
||||
_buffer.getBoolValue(); // virtual aid
|
||||
_buffer.getBoolValue(); // assigned mode
|
||||
_buffer.getUnsignedValue(1); // spare
|
||||
|
||||
@@ -654,9 +654,7 @@ void AisDecoder::decodeType21(PayloadBuffer &_buffer, unsigned int _uMsgType, in
|
||||
nameExt = _buffer.getString(88);
|
||||
}
|
||||
|
||||
onType21(mmsi, aidType, name + nameExt, posAccuracy, posLon, posLat,
|
||||
toBow, toStern, toPort, toStarboard,
|
||||
repeat,timestamp, raim, virtualAton, offPosition);
|
||||
onType21(mmsi, aidType, name + nameExt, posAccuracy, posLon, posLat, toBow, toStern, toPort, toStarboard);
|
||||
}
|
||||
|
||||
/* decode Voyage Report and Static Data (type nibble already pulled from buffer) */
|
||||
|
||||
@@ -297,8 +297,7 @@ namespace AIS
|
||||
bool assigned, unsigned int repeat, bool raim) = 0;
|
||||
|
||||
virtual void onType21(unsigned int _uMmsi, unsigned int _uAidType, const std::string &_strName, bool _bPosAccuracy, int _iPosLon, int _iPosLat,
|
||||
unsigned int _uToBow, unsigned int _uToStern, unsigned int _uToPort, unsigned int _uToStarboard,
|
||||
unsigned int repeat,unsigned int timestamp, bool raim, bool virtualAton, bool offPosition) = 0;
|
||||
unsigned int _uToBow, unsigned int _uToStern, unsigned int _uToPort, unsigned int _uToStarboard) = 0;
|
||||
|
||||
virtual void onType24A(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi, const std::string &_strName) = 0;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _GWAPI_H
|
||||
#include "GwMessage.h"
|
||||
#include "N2kMsg.h"
|
||||
#include "Nmea2kTwai.h"
|
||||
#include "NMEA0183Msg.h"
|
||||
#include "GWConfig.h"
|
||||
#include "GwBoatData.h"
|
||||
@@ -23,6 +24,7 @@ class GwApi{
|
||||
bool formatSet=false;
|
||||
public:
|
||||
double value=0;
|
||||
String svalue="";
|
||||
bool valid=false;
|
||||
int source=-1;
|
||||
bool changed=false; //will be set by getBoatDataValues
|
||||
@@ -222,6 +224,7 @@ class GwApi{
|
||||
* accessing boat data must only be executed from within the main thread
|
||||
* you need to use the request pattern as shown in GwExampleTask.cpp
|
||||
*/
|
||||
virtual Nmea2kTwai *getNMEA2000()=0;
|
||||
virtual GwBoatData *getBoatData()=0;
|
||||
virtual ~GwApi(){}
|
||||
};
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
#define LOGLEVEL GwLog::DEBUG
|
||||
#endif
|
||||
#endif
|
||||
#ifdef GWBUILD_NAME
|
||||
#define FIRMWARE_TYPE GWSTRINGIFY(GWBUILD_NAME)
|
||||
#else
|
||||
|
||||
#define FIRMWARE_TYPE GWSTRINGIFY(PIO_ENV_BUILD)
|
||||
#endif
|
||||
#define IDF_VERSION GWSTRINGIFY(ESP_IDF_VERSION_MAJOR) "." GWSTRINGIFY(ESP_IDF_VERSION_MINOR) "." GWSTRINGIFY(ESP_IDF_VERSION_PATCH)
|
||||
@@ -2,11 +2,6 @@
|
||||
#include <GwJsonDocument.h>
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
#include "GWConfig.h"
|
||||
#define GWTYPE_DOUBLE 1
|
||||
#define GWTYPE_UINT32 2
|
||||
#define GWTYPE_UINT16 3
|
||||
#define GWTYPE_INT16 4
|
||||
#define GWTYPE_USER 100
|
||||
|
||||
class GwBoatItemTypes
|
||||
{
|
||||
@@ -15,7 +10,9 @@ public:
|
||||
static int getType(const uint16_t &x) { return GWTYPE_UINT16; }
|
||||
static int getType(const int16_t &x) { return GWTYPE_INT16; }
|
||||
static int getType(const double &x) { return GWTYPE_DOUBLE; }
|
||||
static int getType(const String &x) { return GWTYPE_STRING; }
|
||||
static int getType(const GwSatInfoList &x) { return GWTYPE_USER + 1; }
|
||||
static int getType(const GwAisTargetList &x) { return GWTYPE_USER + 1; }
|
||||
};
|
||||
|
||||
bool GwBoatItemBase::isValid(unsigned long now) const
|
||||
@@ -252,6 +249,10 @@ static void writeToString(GwTextWriter *writer, const int16_t &value)
|
||||
{
|
||||
writer->writeInteger(value);
|
||||
}
|
||||
static void writeToString(GwTextWriter *writer, String value)
|
||||
{
|
||||
writer->writeString(value.c_str());
|
||||
}
|
||||
static void writeToString(GwTextWriter *writer, GwSatInfoList &value)
|
||||
{
|
||||
writer->writeInteger(value.getNumSats());
|
||||
@@ -288,6 +289,8 @@ template class GwBoatItem<double>;
|
||||
template class GwBoatItem<uint32_t>;
|
||||
template class GwBoatItem<uint16_t>;
|
||||
template class GwBoatItem<int16_t>;
|
||||
template class GwBoatItem<String>;
|
||||
|
||||
void GwSatInfoList::houseKeeping(unsigned long ts)
|
||||
{
|
||||
if (ts == 0)
|
||||
@@ -301,6 +304,7 @@ void GwSatInfoList::houseKeeping(unsigned long ts)
|
||||
}),
|
||||
sats.end());
|
||||
}
|
||||
|
||||
void GwSatInfoList::update(GwSatInfo entry, unsigned long validTill)
|
||||
{
|
||||
entry.validTill = validTill;
|
||||
@@ -343,6 +347,63 @@ void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
|
||||
GwBoatItem<GwSatInfoList>::toJsonDoc(doc, minTime);
|
||||
}
|
||||
|
||||
void GwAisTargetList::houseKeeping(unsigned long ts)
|
||||
{
|
||||
if (ts == 0) {
|
||||
ts = millis();
|
||||
}
|
||||
targets.erase(
|
||||
std::remove_if(
|
||||
targets.begin(),
|
||||
targets.end(),
|
||||
[ts, this](const GwAisTarget &target) {
|
||||
return target.validTill < ts;
|
||||
}
|
||||
),
|
||||
targets.end()
|
||||
);
|
||||
}
|
||||
|
||||
void GwAisTargetList::update(GwAisTarget target, unsigned long validTill)
|
||||
{
|
||||
target.validTill = validTill;
|
||||
for (auto it = targets.begin(); it != targets.end(); it++) {
|
||||
if (it->mmsi == target.mmsi) {
|
||||
*it = target;
|
||||
houseKeeping();
|
||||
return;
|
||||
}
|
||||
}
|
||||
houseKeeping();
|
||||
targets.push_back(target);
|
||||
}
|
||||
|
||||
GwBoatDataAisList::GwBoatDataAisList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map) : GwBoatItem<GwAisTargetList>(name, formatInfo, toType, map) {}
|
||||
|
||||
bool GwBoatDataAisList::update(GwAisTarget target, int source)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
if (isValid(now))
|
||||
{
|
||||
//priority handling
|
||||
//sources with lower ids will win
|
||||
//and we will not overwrite their value
|
||||
if (lastUpdateSource < source)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
lastUpdateSource = source;
|
||||
uls(now);
|
||||
data.update(target, now+invalidTime);
|
||||
return true;
|
||||
}
|
||||
void GwBoatDataAisList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
|
||||
{
|
||||
data.houseKeeping();
|
||||
GwBoatItem<GwAisTargetList>::toJsonDoc(doc, minTime);
|
||||
}
|
||||
|
||||
GwBoatData::GwBoatData(GwLog *logger, GwConfigHandler *cfg)
|
||||
{
|
||||
this->logger = logger;
|
||||
@@ -512,6 +573,11 @@ bool convertToJson(const GwSatInfoList &si, JsonVariant &variant)
|
||||
return variant.set(si.getNumSats());
|
||||
}
|
||||
|
||||
bool convertToJson(const GwAisTargetList &si, JsonVariant &variant)
|
||||
{
|
||||
return variant.set(si.getNumTargets());
|
||||
}
|
||||
|
||||
#ifdef _UNDEF
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
#define GW_BOAT_VALUE_LEN 32
|
||||
#define GWSC(name) static constexpr const char* name=#name
|
||||
|
||||
#define GWTYPE_DOUBLE 1
|
||||
#define GWTYPE_UINT32 2
|
||||
#define GWTYPE_UINT16 3
|
||||
#define GWTYPE_INT16 4
|
||||
#define GWTYPE_STRING 5
|
||||
#define GWTYPE_USER 100
|
||||
|
||||
//see https://github.com/wellenvogel/esp32-nmea2000/issues/44
|
||||
//factor to convert from N2k/SI rad/s to current NMEA rad/min
|
||||
#define ROT_WA_FACTOR 60
|
||||
@@ -58,6 +65,7 @@ class GwBoatItemBase{
|
||||
GWSC(formatRot);
|
||||
GWSC(formatDate);
|
||||
GWSC(formatTime);
|
||||
GWSC(formatName);
|
||||
protected:
|
||||
int type;
|
||||
unsigned long lastSet=0;
|
||||
@@ -92,6 +100,7 @@ class GwBoatItemBase{
|
||||
virtual int getLastSource(){return lastUpdateSource;}
|
||||
virtual void refresh(unsigned long ts=0){uls(ts);}
|
||||
virtual double getDoubleValue()=0;
|
||||
virtual String getStringValue()=0;
|
||||
String getName(){return name;}
|
||||
const String & getFormat() const{return format;}
|
||||
virtual void setInvalidTime(GwConfigHandler *cfg);
|
||||
@@ -120,7 +129,17 @@ template<class T> class GwBoatItem : public GwBoatItemBase{
|
||||
if (! isValid(millis())) return defaultv;
|
||||
return data;
|
||||
}
|
||||
virtual double getDoubleValue(){return (double)data;}
|
||||
virtual double getDoubleValue(){
|
||||
if constexpr (std::is_same<T, String>::value) {
|
||||
return 0.0; // TODO any better ideas?
|
||||
} else {
|
||||
return (double)data;
|
||||
}
|
||||
}
|
||||
virtual String getStringValue(){
|
||||
return (String)data;
|
||||
}
|
||||
|
||||
virtual void fillString();
|
||||
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime);
|
||||
virtual int getLastSource(){return lastUpdateSource;}
|
||||
@@ -177,6 +196,55 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class GwAisTarget {
|
||||
public:
|
||||
uint32_t mmsi;
|
||||
char callsign[8];
|
||||
char name[21];
|
||||
uint8_t vesseltype;
|
||||
double lat;
|
||||
double lon;
|
||||
float length;
|
||||
float beam;
|
||||
float sog;
|
||||
float cog;
|
||||
unsigned long validTill;
|
||||
};
|
||||
|
||||
class GwAisTargetList {
|
||||
public:
|
||||
static const GwBoatItemBase::TOType toType=GwBoatItemBase::TOType::ais;
|
||||
std::vector<GwAisTarget> targets;
|
||||
void houseKeeping(unsigned long ts=0);
|
||||
void update(GwAisTarget target, unsigned long validTill);
|
||||
int getNumTargets() const {
|
||||
return targets.size();
|
||||
}
|
||||
GwAisTarget *getAt(int idx){
|
||||
if (idx >= 0 && idx < targets.size()) return &targets.at(idx);
|
||||
return NULL;
|
||||
}
|
||||
operator double(){ return getNumTargets();}
|
||||
};
|
||||
|
||||
class GwBoatDataAisList : public GwBoatItem<GwAisTargetList> {
|
||||
public:
|
||||
GwBoatDataAisList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map = NULL);
|
||||
bool update(GwAisTarget target, int source);
|
||||
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime);
|
||||
GwAisTarget *getAt(int idx) {
|
||||
if (! isValid()) return NULL;
|
||||
return data.getAt(idx);
|
||||
}
|
||||
int getNumTargets(){
|
||||
if (! isValid()) return 0;
|
||||
return data.getNumTargets();
|
||||
}
|
||||
virtual double getDoubleValue(){
|
||||
return (double)(data.getNumTargets());
|
||||
}
|
||||
};
|
||||
|
||||
class GwBoatItemNameProvider
|
||||
{
|
||||
public:
|
||||
@@ -235,7 +303,9 @@ class GwBoatData{
|
||||
GWBOATDATA(double,XTE,formatXte) // cross track error
|
||||
GWBOATDATA(double,WPLat,formatLatitude) // waypoint latitude
|
||||
GWBOATDATA(double,WPLon,formatLongitude) // waypoint longitude
|
||||
GWBOATDATA(String,WPName,formatName) // waypoint name
|
||||
GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::toType,formatFixed0);
|
||||
GWSPECBOATDATA(GwBoatDataAisList,AisTarget,GwAisTargetList::toType,formatFixed0);
|
||||
public:
|
||||
GwBoatData(GwLog *logger, GwConfigHandler *cfg);
|
||||
~GwBoatData();
|
||||
|
||||
@@ -249,16 +249,3 @@ unsigned long GwChannel::countTx(){
|
||||
if (! countOut) return 0UL;
|
||||
return countOut->getGlobal();
|
||||
}
|
||||
String GwChannel::typeString(int type){
|
||||
switch (type){
|
||||
case GWSERIAL_TYPE_UNI:
|
||||
return "UNI";
|
||||
case GWSERIAL_TYPE_BI:
|
||||
return "BI";
|
||||
case GWSERIAL_TYPE_RX:
|
||||
return "RX";
|
||||
case GWSERIAL_TYPE_TX:
|
||||
return "TX";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -77,8 +77,7 @@ class GwChannel{
|
||||
if (maxSourceId < 0) return source == sourceId;
|
||||
return (source >= sourceId && source <= maxSourceId);
|
||||
}
|
||||
static String typeString(int type);
|
||||
String getMode(){return typeString(impl->getType());}
|
||||
String getMode(){return impl->getMode();}
|
||||
int getMinId(){return sourceId;};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
#include "GwBuffer.h"
|
||||
#include "GwChannelModes.h"
|
||||
class GwChannelInterface{
|
||||
public:
|
||||
virtual void loop(bool handleRead,bool handleWrite)=0;
|
||||
virtual void readMessages(GwMessageFetcher *writer)=0;
|
||||
virtual size_t sendToClients(const char *buffer, int sourceId, bool partial=false)=0;
|
||||
virtual Stream * getStream(bool partialWrites){ return NULL;}
|
||||
virtual int getType(){ return GWSERIAL_TYPE_BI;} //return the numeric type
|
||||
virtual String getMode(){return "UNKNOWN";}
|
||||
};
|
||||
@@ -15,10 +15,8 @@ class SerInit{
|
||||
int tx=-1;
|
||||
int mode=-1;
|
||||
int fixedBaud=-1;
|
||||
int ena=-1;
|
||||
int elow=1;
|
||||
SerInit(int s,int r,int t, int m, int b=-1,int en=-1,int el=-1):
|
||||
serial(s),rx(r),tx(t),mode(m),fixedBaud(b),ena(en),elow(el){}
|
||||
SerInit(int s,int r,int t, int m, int b=-1):
|
||||
serial(s),rx(r),tx(t),mode(m),fixedBaud(b){}
|
||||
};
|
||||
std::vector<SerInit> serialInits;
|
||||
|
||||
@@ -49,20 +47,11 @@ static int typeFromMode(const char *mode){
|
||||
#ifndef GWSERIAL_RX
|
||||
#define GWSERIAL_RX -1
|
||||
#endif
|
||||
#ifndef GWSERIAL_ENA
|
||||
#define GWSERIAL_ENA -1
|
||||
#endif
|
||||
#ifndef GWSERIAL_ELO
|
||||
#define GWSERIAL_ELO 0
|
||||
#endif
|
||||
#ifndef GWSERIAL_BAUD
|
||||
#define GWSERIAL_BAUD -1
|
||||
#endif
|
||||
#ifdef GWSERIAL_TYPE
|
||||
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, GWSERIAL_TYPE,GWSERIAL_BAUD,GWSERIAL_ENA,GWSERIAL_ELO)
|
||||
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, GWSERIAL_TYPE)
|
||||
#else
|
||||
#ifdef GWSERIAL_MODE
|
||||
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, typeFromMode(GWSERIAL_MODE),GWSERIAL_BAUD,GWSERIAL_ENA,GWSERIAL_ELO)
|
||||
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, typeFromMode(GWSERIAL_MODE))
|
||||
#endif
|
||||
#endif
|
||||
// serial 2
|
||||
@@ -72,20 +61,11 @@ CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, typeFromMode(GWSERIAL_M
|
||||
#ifndef GWSERIAL2_RX
|
||||
#define GWSERIAL2_RX -1
|
||||
#endif
|
||||
#ifndef GWSERIAL2_ENA
|
||||
#define GWSERIAL2_ENA -1
|
||||
#endif
|
||||
#ifndef GWSERIAL2_ELO
|
||||
#define GWSERIAL2_ELO 0
|
||||
#endif
|
||||
#ifndef GWSERIAL2_BAUD
|
||||
#define GWSERIAL2_BAUD -1
|
||||
#endif
|
||||
#ifdef GWSERIAL2_TYPE
|
||||
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, GWSERIAL2_TYPE,GWSERIAL2_BAUD,GWSERIAL2_ENA,GWSERIAL2_ELO)
|
||||
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, GWSERIAL2_TYPE)
|
||||
#else
|
||||
#ifdef GWSERIAL2_MODE
|
||||
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, typeFromMode(GWSERIAL2_MODE),GWSERIAL2_BAUD,GWSERIAL2_ENA,GWSERIAL2_ELO)
|
||||
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, typeFromMode(GWSERIAL2_MODE))
|
||||
#endif
|
||||
#endif
|
||||
class GwSerialLog : public GwLogWriter
|
||||
@@ -305,8 +285,8 @@ static ChannelParam channelParameters[]={
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
GwSerial* createSerial(GwLog *logger, T* s,int id, int type, bool canRead=true){
|
||||
return new GwSerialImpl<T>(logger,s,id,type,canRead);
|
||||
GwSerial* createSerial(GwLog *logger, T* s,int id, bool canRead=true){
|
||||
return new GwSerialImpl<T>(logger,s,id,canRead);
|
||||
}
|
||||
|
||||
static ChannelParam * findChannelParam(int id){
|
||||
@@ -320,7 +300,7 @@ static ChannelParam * findChannelParam(int id){
|
||||
return param;
|
||||
}
|
||||
|
||||
static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int idx,int type,int rx,int tx, bool setLog,int ena=-1,int elow=1){
|
||||
static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int idx,int rx,int tx, bool setLog=false){
|
||||
LOG_DEBUG(GwLog::DEBUG,"create serial: channel=%d, rx=%d,tx=%d",
|
||||
idx,rx,tx);
|
||||
ChannelParam *param=findChannelParam(idx);
|
||||
@@ -332,45 +312,19 @@ static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int id
|
||||
GwLog *streamLog=setLog?nullptr:logger;
|
||||
switch(param->id){
|
||||
case USB_CHANNEL_ID:
|
||||
serialStream=createSerial(streamLog,&USBSerial,param->id,type);
|
||||
serialStream=createSerial(streamLog,&USBSerial,param->id);
|
||||
break;
|
||||
case SERIAL1_CHANNEL_ID:
|
||||
serialStream=createSerial(streamLog,&Serial1,param->id,type);
|
||||
serialStream=createSerial(streamLog,&Serial1,param->id);
|
||||
break;
|
||||
case SERIAL2_CHANNEL_ID:
|
||||
serialStream=createSerial(streamLog,&Serial2,param->id,type);
|
||||
serialStream=createSerial(streamLog,&Serial2,param->id);
|
||||
break;
|
||||
}
|
||||
if (serialStream == nullptr){
|
||||
LOG_DEBUG(GwLog::ERROR,"invalid serial config with id %d",param->id);
|
||||
return nullptr;
|
||||
}
|
||||
if (ena >= 0){
|
||||
int value=-1;
|
||||
if (type == GWSERIAL_TYPE_UNI){
|
||||
String cfgMode=config->getString(param->direction);
|
||||
if (cfgMode == "send"){
|
||||
value=elow?0:1;
|
||||
}
|
||||
else{
|
||||
value=elow?1:0;
|
||||
}
|
||||
}
|
||||
if (type == GWSERIAL_TYPE_RX){
|
||||
value=elow?1:0;
|
||||
}
|
||||
if (type == GWSERIAL_TYPE_TX){
|
||||
value=elow?0:1;
|
||||
}
|
||||
if (value >= 0){
|
||||
LOG_DEBUG(GwLog::LOG,"serial %d: setting output enable %d to %d",param->id,ena,value);
|
||||
pinMode(ena,OUTPUT);
|
||||
digitalWrite(ena,value);
|
||||
}
|
||||
else{
|
||||
LOG_DEBUG(GwLog::ERROR,"serial %d: output enable ignored for mode %d",param->id, type);
|
||||
}
|
||||
}
|
||||
serialStream->begin(config->getInt(param->baud,115200),SERIAL_8N1,rx,tx);
|
||||
if (setLog){
|
||||
logger->setWriter(new GwSerialLog(serialStream,config->getBool(param->preventLog,false)));
|
||||
@@ -378,13 +332,12 @@ static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int id
|
||||
}
|
||||
return serialStream;
|
||||
}
|
||||
static GwChannel * createChannel(GwLog *logger, GwConfigHandler *config, int id,GwChannelInterface *impl){
|
||||
static GwChannel * createChannel(GwLog *logger, GwConfigHandler *config, int id,GwChannelInterface *impl, int type=GWSERIAL_TYPE_BI){
|
||||
ChannelParam *param=findChannelParam(id);
|
||||
if (param == nullptr){
|
||||
LOG_DEBUG(GwLog::ERROR,"invalid channel id %d",id);
|
||||
return nullptr;
|
||||
}
|
||||
int type=impl->getType();
|
||||
bool canRead=false;
|
||||
bool canWrite=false;
|
||||
bool validType=false;
|
||||
@@ -472,10 +425,10 @@ void GwChannelList::begin(bool fallbackSerial){
|
||||
GwChannel *channel=NULL;
|
||||
//usb
|
||||
if (! fallbackSerial){
|
||||
GwSerial *usbSerial=createSerialImpl(config, logger,USB_CHANNEL_ID,GWSERIAL_TYPE_BI,GWUSB_RX,GWUSB_TX,true);
|
||||
GwSerial *usbSerial=createSerialImpl(config, logger,USB_CHANNEL_ID,GWUSB_RX,GWUSB_TX,true);
|
||||
if (usbSerial != nullptr){
|
||||
usbSerial->enableWriteLock(); //as it is used for logging we need this additionally
|
||||
GwChannel *usbChannel=createChannel(logger,config,USB_CHANNEL_ID,usbSerial);
|
||||
GwChannel *usbChannel=createChannel(logger,config,USB_CHANNEL_ID,usbSerial,GWSERIAL_TYPE_BI);
|
||||
if (usbChannel != nullptr){
|
||||
addChannel(usbChannel);
|
||||
}
|
||||
@@ -491,11 +444,10 @@ void GwChannelList::begin(bool fallbackSerial){
|
||||
|
||||
//new serial config handling
|
||||
for (auto &&init:serialInits){
|
||||
LOG_INFO("creating serial channel %d, rx=%d,tx=%d,type=%d fixedBaud=%d ena=%d elow=%d",
|
||||
init.serial,init.rx,init.tx,init.mode,init.fixedBaud,init.ena,init.elow);
|
||||
GwSerial *ser=createSerialImpl(config,logger,init.serial,init.mode,init.rx,init.tx,false,init.ena,init.elow);
|
||||
LOG_INFO("creating serial channel %d, rx=%d,tx=%d,type=%d",init.serial,init.rx,init.tx,init.mode);
|
||||
GwSerial *ser=createSerialImpl(config,logger,init.serial,init.rx,init.tx);
|
||||
if (ser != nullptr){
|
||||
channel=createChannel(logger,config,init.serial,ser);
|
||||
channel=createChannel(logger,config,init.serial,ser,init.mode);
|
||||
if (channel != nullptr){
|
||||
addChannel(channel);
|
||||
}
|
||||
@@ -514,8 +466,8 @@ void GwChannelList::begin(bool fallbackSerial){
|
||||
config->getInt(config->remotePort),
|
||||
config->getBool(config->readTCL)
|
||||
);
|
||||
addChannel(createChannel(logger,config,TCP_CLIENT_CHANNEL_ID,client));
|
||||
}
|
||||
addChannel(createChannel(logger,config,TCP_CLIENT_CHANNEL_ID,client));
|
||||
|
||||
//udp writer
|
||||
if (config->getBool(GwConfigDefinitions::udpwEnabled)){
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
|
||||
@@ -57,44 +57,6 @@ Files
|
||||
|
||||
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)
|
||||
|
||||
* [script.py](script.py)<br>
|
||||
Starting from version 20251007 you can define a parameter "custom_script" in your [platformio.ini](platformio.ini).
|
||||
This parameter can contain a list of file names (relative to the project root) that will be added as a [platformio extra script](https://docs.platformio.org/en/latest/scripting/index.html#scripting). The scripts will be loaded at the end of the main [extra_script](../../extra_script.py).
|
||||
You can add code there that is specific for your build.
|
||||
Example:
|
||||
```
|
||||
# PlatformIO extra script for obp60task
|
||||
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]
|
||||
|
||||
propfilename = os.path.join(env["PROJECT_LIBDEPS_DIR"], env ["PIOENV"], "GxEPD2/library.properties")
|
||||
properties = {}
|
||||
with open(propfilename, 'r') as file:
|
||||
for line in file:
|
||||
match = re.match(r'^([^=]+)=(.*)$', line)
|
||||
if match:
|
||||
key = match.group(1).strip()
|
||||
value = match.group(2).strip()
|
||||
properties[key] = value
|
||||
|
||||
gxepd2vers = "unknown"
|
||||
try:
|
||||
if properties["name"] == "GxEPD2":
|
||||
gxepd2vers = properties["version"]
|
||||
except:
|
||||
pass
|
||||
|
||||
env["CPPDEFINES"].extend([("BOARD", env["BOARD"]), ("EPDTYPE", epdtype), ("PCBVERS", pcbvers), ("GXEPD2VERS", gxepd2vers)])
|
||||
|
||||
print("added hardware info to CPPDEFINES")
|
||||
print("friendly board name is '{}'".format(env.GetProjectOption ("board_name")))
|
||||
```
|
||||
|
||||
|
||||
Interfaces
|
||||
----------
|
||||
|
||||
@@ -14,6 +14,5 @@ custom_config=
|
||||
lib/exampletask/exampleConfig.json
|
||||
custom_js=lib/exampletask/example.js
|
||||
custom_css=lib/exampletask/example.css
|
||||
custom_script=lib/exampletask/script.py
|
||||
upload_port = /dev/esp32
|
||||
upload_protocol = esptool
|
||||
@@ -1,4 +0,0 @@
|
||||
Import("env")
|
||||
|
||||
print("exampletask extra script running")
|
||||
syntax error here
|
||||
@@ -79,7 +79,7 @@ GwUpdate::GwUpdate(GwLog *log, GwWebServer *webserver, PasswordChecker ckr)
|
||||
}
|
||||
if (!param->hasError())
|
||||
{
|
||||
AsyncWebParameter *hash=request->getParam("_hash");
|
||||
const AsyncWebParameter *hash=request->getParam("_hash");
|
||||
if (! hash){
|
||||
hash=request->getParam("_hash",true);
|
||||
}
|
||||
@@ -141,4 +141,4 @@ GwUpdate::GwUpdate(GwLog *log, GwWebServer *webserver, PasswordChecker ckr)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ void sendEmbeddedFile(String name,String contentType,AsyncWebServerRequest *requ
|
||||
std::map<String,EmbeddedFile*>::iterator it=embeddedFiles.find(name);
|
||||
if (it != embeddedFiles.end()){
|
||||
EmbeddedFile* found=it->second;
|
||||
AsyncWebServerResponse *response=request->beginResponse_P(200,contentType,found->start,found->len);
|
||||
AsyncWebServerResponse *response=request->beginResponse(200, contentType, found->start, found->len);
|
||||
response->addHeader(F("Content-Encoding"), F("gzip"));
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
defines for the channel modes(types)
|
||||
*/
|
||||
#ifndef _GWCHANNELMODES_H
|
||||
#define _GWCHANNELMODES_H
|
||||
#define GWSERIAL_TYPE_UNI 1
|
||||
#define GWSERIAL_TYPE_BI 2
|
||||
#define GWSERIAL_TYPE_RX 3
|
||||
#define GWSERIAL_TYPE_TX 4
|
||||
#define GWSERIAL_TYPE_UNK 0
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
@@ -20,7 +20,11 @@
|
||||
#endif
|
||||
#ifndef _GWHARDWARE_H
|
||||
#define _GWHARDWARE_H
|
||||
#include "GwChannelModes.h"
|
||||
#define GWSERIAL_TYPE_UNI 1
|
||||
#define GWSERIAL_TYPE_BI 2
|
||||
#define GWSERIAL_TYPE_RX 3
|
||||
#define GWSERIAL_TYPE_TX 4
|
||||
#define GWSERIAL_TYPE_UNK 0
|
||||
#include <GwConfigItem.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include "GwAppInfo.h"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
@@ -35,12 +35,7 @@
|
||||
#ifdef M5_GPS_KIT
|
||||
GWRESOURCE_USE(BASE,M5_GPS_KIT)
|
||||
GWRESOURCE_USE(SERIAL1,M5_GPS_KIT)
|
||||
#define _GWI_SERIAL1 BOARD_LEFT1,-1,GWSERIAL_TYPE_RX,9600
|
||||
#endif
|
||||
#ifdef M5_GPSV2_KIT
|
||||
GWRESOURCE_USE(BASE,M5_GPSV2_KIT)
|
||||
GWRESOURCE_USE(SERIAL1,M5_GPSV2_KIT)
|
||||
#define _GWI_SERIAL1 BOARD_LEFT1,-1,GWSERIAL_TYPE_RX,115200
|
||||
#define _GWI_SERIAL1 BOARD_LEFT1,-1,GWSERIAL_TYPE_UNI,9600
|
||||
#endif
|
||||
|
||||
//M5 ProtoHub
|
||||
@@ -66,11 +61,11 @@
|
||||
#endif
|
||||
|
||||
//can kit for M5 Atom
|
||||
#if defined (M5_CAN_KIT)
|
||||
#ifdef M5_CAN_KIT
|
||||
GWRESOURCE_USE(BASE,M5_CAN_KIT)
|
||||
GWRESOURCE_USE(CAN,M5_CANKIT)
|
||||
#define ESP32_CAN_TX_PIN BOARD_LEFT1
|
||||
#define ESP32_CAN_RX_PIN BOARD_LEFT2
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
@@ -43,13 +43,6 @@
|
||||
#define _GWI_SERIAL_GROOVE$GS$ GWSERIAL_TYPE_RX,9600
|
||||
#endif
|
||||
|
||||
#GROVE
|
||||
//https://docs.m5stack.com/en/unit/Unit-GPS%20v1.1
|
||||
#ifdef M5_GPSV11_UNIT$GS$
|
||||
GWRESOURCE_USE(GROOVE$G$,M5_GPSV11_UNIT$GS$)
|
||||
#define _GWI_SERIAL_GROOVE$GS$ GWSERIAL_TYPE_RX,115200
|
||||
#endif
|
||||
|
||||
#GROVE
|
||||
//CAN via groove
|
||||
#ifdef M5_CANUNIT$GS$
|
||||
@@ -71,15 +64,15 @@
|
||||
#endif
|
||||
|
||||
#GROVE
|
||||
#ifdef M5_ENV4$GS$
|
||||
#ifndef M5_GROOVEIIC$GS$
|
||||
#define M5_GROOVEIIC$GS$
|
||||
#endif
|
||||
GROOVE_IIC(SHT4X,$Z$,1)
|
||||
GROOVE_IIC(BMP280,$Z$,1)
|
||||
#define _GWSHT4X
|
||||
#define _GWBMP280
|
||||
#endif
|
||||
//#ifdef M5_ENV4$GS$
|
||||
// #ifndef M5_GROOVEIIC$GS$
|
||||
// #define M5_GROOVEIIC$GS$
|
||||
// #endif
|
||||
// GROOVE_IIC(SHT3X,$Z$,1)
|
||||
// GROOVE_IIC(BMP280,$Z$,1)
|
||||
// #define _GWSHT3X
|
||||
// #define _GWBMP280
|
||||
//#endif
|
||||
|
||||
#GROVE
|
||||
//example: -DSHT3XG1_A : defines STH3Xn1 on grove A - x depends on the other devices
|
||||
@@ -100,25 +93,6 @@
|
||||
#define _GWSHT3X
|
||||
#endif
|
||||
|
||||
#GROVE
|
||||
//example: -DSHT4XG1_A : defines STH4Xn1 on grove A - x depends on the other devices
|
||||
#ifdef GWSHT4XG1$GS$
|
||||
#ifndef M5_GROOVEIIC$GS$
|
||||
#define M5_GROOVEIIC$GS$
|
||||
#endif
|
||||
GROOVE_IIC(SHT4X,$Z$,1)
|
||||
#define _GWSHT4X
|
||||
#endif
|
||||
|
||||
#GROVE
|
||||
#ifdef GWSHT4XG2$GS$
|
||||
#ifndef M5_GROOVEIIC$GS$
|
||||
#define M5_GROOVEIIC$GS$
|
||||
#endif
|
||||
GROOVE_IIC(SHT4X,$Z$,2)
|
||||
#define _GWSHT4X
|
||||
#endif
|
||||
|
||||
#GROVE
|
||||
#ifdef GWQMP6988G1$GS$
|
||||
#ifndef M5_GROOVEIIC$GS$
|
||||
|
||||
@@ -23,7 +23,6 @@ class BME280Config : public IICSensorBase{
|
||||
bool prAct=true;
|
||||
bool tmAct=true;
|
||||
bool huAct=true;
|
||||
bool sEnv=true;
|
||||
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
||||
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_InsideHumidity;
|
||||
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
||||
@@ -153,7 +152,6 @@ SensorBase::Creator registerBME280(GwApi *api){
|
||||
CFG_SGET(s, prNam, prefix); \
|
||||
CFG_SGET(s, tmOff, prefix); \
|
||||
CFG_SGET(s, prOff, prefix); \
|
||||
CFG_SGET(s, sEnv, prefix); \
|
||||
s->busId = bus; \
|
||||
s->addr = baddr; \
|
||||
s->ok = true; \
|
||||
|
||||
@@ -29,7 +29,6 @@ class BMP280Config : public IICSensorBase{
|
||||
public:
|
||||
bool prAct=true;
|
||||
bool tmAct=true;
|
||||
bool sEnv=true;
|
||||
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
||||
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
||||
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_Undef;
|
||||
@@ -151,7 +150,6 @@ SensorBase::Creator registerBMP280(GwApi *api){
|
||||
CFG_SGET(s, prNam, prefix); \
|
||||
CFG_SGET(s, tmOff, prefix); \
|
||||
CFG_SGET(s, prOff, prefix); \
|
||||
CFG_SGET(s, sEnv,prefix); \
|
||||
s->busId = bus; \
|
||||
s->addr = baddr; \
|
||||
s->ok = true; \
|
||||
|
||||
@@ -104,19 +104,12 @@ void sendN2kTemperature(GwApi *api,CFG &cfg,double value, int counterId){
|
||||
|
||||
template <class CFG>
|
||||
void sendN2kEnvironmentalParameters(GwApi *api,CFG &cfg,double tmValue, double huValue, double prValue, int counterId){
|
||||
if (! cfg.sEnv) return;
|
||||
tN2kMsg msg;
|
||||
SetN2kEnvironmentalParameters(msg,1,cfg.tmSrc,tmValue,cfg.huSrc,huValue,prValue);
|
||||
api->sendN2kMessage(msg);
|
||||
if (huValue != N2kDoubleNA){
|
||||
api->increment(counterId,cfg.prefix+String("ehum"));
|
||||
}
|
||||
if (prValue != N2kDoubleNA){
|
||||
api->increment(counterId,cfg.prefix+String("epress"));
|
||||
}
|
||||
if (tmValue != N2kDoubleNA){
|
||||
api->increment(counterId,cfg.prefix+String("etemp"));
|
||||
}
|
||||
api->increment(counterId,cfg.prefix+String("hum"));
|
||||
api->increment(counterId,cfg.prefix+String("press"));
|
||||
api->increment(counterId,cfg.prefix+String("temp"));
|
||||
}
|
||||
|
||||
#ifndef _GWI_IIC1
|
||||
|
||||
@@ -23,7 +23,7 @@ static std::vector<IICGrove> iicGroveList;
|
||||
#include "GwBME280.h"
|
||||
#include "GwBMP280.h"
|
||||
#include "GwQMP6988.h"
|
||||
#include "GwSHTXX.h"
|
||||
#include "GwSHT3X.h"
|
||||
#include <map>
|
||||
|
||||
#include "GwTimer.h"
|
||||
@@ -91,7 +91,6 @@ void initIicTask(GwApi *api){
|
||||
GwConfigHandler *config=api->getConfig();
|
||||
std::vector<SensorBase::Creator> creators;
|
||||
creators.push_back(registerSHT3X(api));
|
||||
creators.push_back(registerSHT4X(api));
|
||||
creators.push_back(registerQMP6988(api));
|
||||
creators.push_back(registerBME280(api));
|
||||
creators.push_back(registerBMP280(api));
|
||||
@@ -148,13 +147,13 @@ bool initWire(GwLog *logger, TwoWire &wire, int num){
|
||||
#ifdef _GWI_IIC1
|
||||
return initWireDo(logger,wire,num,_GWI_IIC1);
|
||||
#endif
|
||||
return initWireDo(logger,wire,num,"",GWIIC_SCL,GWIIC_SDA);
|
||||
return initWireDo(logger,wire,num,"",GWIIC_SDA,GWIIC_SCL);
|
||||
}
|
||||
if (num == 2){
|
||||
#ifdef _GWI_IIC2
|
||||
return initWireDo(logger,wire,num,_GWI_IIC2);
|
||||
#endif
|
||||
return initWireDo(logger,wire,num,"",GWIIC_SCL2,GWIIC_SDA2);
|
||||
return initWireDo(logger,wire,num,"",GWIIC_SDA2,GWIIC_SCL2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@ class QMP6988Config : public IICSensorBase{
|
||||
public:
|
||||
String prNam="Pressure";
|
||||
bool prAct=true;
|
||||
bool sEnv=true;
|
||||
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
||||
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_Undef;
|
||||
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
||||
float prOff=0;
|
||||
QMP6988 *device=nullptr;
|
||||
@@ -42,7 +39,6 @@ class QMP6988Config : public IICSensorBase{
|
||||
float computed=pressure+prOff;
|
||||
LOG_DEBUG(GwLog::DEBUG,"%s measure %2.0fPa, computed %2.0fPa",prefix.c_str(), pressure,computed);
|
||||
sendN2kPressure(api,*this,computed,counterId);
|
||||
sendN2kEnvironmentalParameters(api,*this,N2kDoubleNA,N2kDoubleNA,computed,counterId);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +90,6 @@ SensorBase::Creator registerQMP6988(GwApi *api){
|
||||
CFG_SGET(s,prAct,prefix); \
|
||||
CFG_SGET(s,intv,prefix); \
|
||||
CFG_SGET(s,prOff,prefix); \
|
||||
CFG_SGET(s,sEnv,prefix); \
|
||||
s->busId = bus; \
|
||||
s->addr = baddr; \
|
||||
s->ok = true; \
|
||||
|
||||
138
lib/iictask/GwSHT3X.cpp
Normal file
138
lib/iictask/GwSHT3X.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "GwSHT3X.h"
|
||||
#ifdef _GWSHT3X
|
||||
class SHT3XConfig;
|
||||
static GwSensorConfigInitializerList<SHT3XConfig> configs;
|
||||
class SHT3XConfig : public IICSensorBase{
|
||||
public:
|
||||
String tmNam;
|
||||
String huNam;
|
||||
bool tmAct=false;
|
||||
bool huAct=false;
|
||||
tN2kHumiditySource huSrc;
|
||||
tN2kTempSource tmSrc;
|
||||
SHT3X *device=nullptr;
|
||||
using IICSensorBase::IICSensorBase;
|
||||
virtual bool isActive(){
|
||||
return tmAct || huAct;
|
||||
}
|
||||
virtual bool initDevice(GwApi * api,TwoWire *wire){
|
||||
if (! isActive()) return false;
|
||||
device=new SHT3X();
|
||||
device->init(addr,wire);
|
||||
GwLog *logger=api->getLogger();
|
||||
LOG_DEBUG(GwLog::LOG,"initialized %s at address %d, intv %ld",prefix.c_str(),(int)addr,intv);
|
||||
return true;
|
||||
}
|
||||
virtual bool preinit(GwApi * api){
|
||||
GwLog *logger=api->getLogger();
|
||||
LOG_DEBUG(GwLog::LOG,"%s configured",prefix.c_str());
|
||||
addHumidXdr(api,*this);
|
||||
addTempXdr(api,*this);
|
||||
return isActive();
|
||||
}
|
||||
virtual void measure(GwApi * api,TwoWire *wire, int counterId)
|
||||
{
|
||||
if (!device)
|
||||
return;
|
||||
GwLog *logger=api->getLogger();
|
||||
int rt = 0;
|
||||
if ((rt = device->get()) == 0)
|
||||
{
|
||||
double temp = device->cTemp;
|
||||
temp = CToKelvin(temp);
|
||||
double humid = device->humidity;
|
||||
LOG_DEBUG(GwLog::DEBUG, "%s measure temp=%2.1f, humid=%2.0f",prefix.c_str(), (float)temp, (float)humid);
|
||||
if (huAct)
|
||||
{
|
||||
sendN2kHumidity(api, *this, humid, counterId);
|
||||
}
|
||||
if (tmAct)
|
||||
{
|
||||
sendN2kTemperature(api, *this, temp, counterId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG(GwLog::DEBUG, "unable to query %s: %d",prefix.c_str(), rt);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void readConfig(GwConfigHandler *cfg){
|
||||
if (ok) return;
|
||||
configs.readConfig(this,cfg);
|
||||
return;
|
||||
}
|
||||
};
|
||||
SensorBase::Creator creator=[](GwApi *api,const String &prfx)-> SensorBase*{
|
||||
if (! configs.knowsPrefix(prfx)) return nullptr;
|
||||
return new SHT3XConfig(api,prfx);
|
||||
};
|
||||
SensorBase::Creator registerSHT3X(GwApi *api){
|
||||
GwLog *logger=api->getLogger();
|
||||
#if defined(GWSHT3X) || defined (GWSHT3X11)
|
||||
{
|
||||
api->addSensor(creator(api,"SHT3X11"));
|
||||
CHECK_IIC1();
|
||||
#pragma message "GWSHT3X11 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT3X12)
|
||||
{
|
||||
api->addSensor(creator(api,"SHT3X12"));
|
||||
CHECK_IIC1();
|
||||
#pragma message "GWSHT3X12 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT3X21)
|
||||
{
|
||||
api->addSensor(creator(api,"SHT3X21"));
|
||||
CHECK_IIC2();
|
||||
#pragma message "GWSHT3X21 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT3X22)
|
||||
{
|
||||
api->addSensor(creator(api,"SHT3X22"));
|
||||
CHECK_IIC2();
|
||||
#pragma message "GWSHT3X22 defined"
|
||||
}
|
||||
#endif
|
||||
return creator;
|
||||
};
|
||||
|
||||
/**
|
||||
* we do not dynamically compute the config names
|
||||
* just to get compile time errors if something does not fit
|
||||
* correctly
|
||||
*/
|
||||
#define CFGSHT3X(s, prefix, bus, baddr) \
|
||||
CFG_SGET(s, tmNam, prefix); \
|
||||
CFG_SGET(s, huNam, prefix); \
|
||||
CFG_SGET(s, iid, prefix); \
|
||||
CFG_SGET(s, tmAct, prefix); \
|
||||
CFG_SGET(s, huAct, prefix); \
|
||||
CFG_SGET(s, intv, prefix); \
|
||||
CFG_SGET(s, huSrc, prefix); \
|
||||
CFG_SGET(s, tmSrc, prefix); \
|
||||
s->busId = bus; \
|
||||
s->addr = baddr; \
|
||||
s->ok = true; \
|
||||
s->intv *= 1000;
|
||||
|
||||
#define SCSHT3X(prefix, bus, addr) \
|
||||
GWSENSORDEF(configs, SHT3XConfig, CFGSHT3X, prefix, bus, addr)
|
||||
|
||||
SCSHT3X(SHT3X11, 1, 0x44);
|
||||
SCSHT3X(SHT3X12, 1, 0x45);
|
||||
SCSHT3X(SHT3X21, 2, 0x44);
|
||||
SCSHT3X(SHT3X22, 2, 0x45);
|
||||
|
||||
#else
|
||||
SensorBase::Creator registerSHT3X(GwApi *api){
|
||||
return SensorBase::Creator();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#ifndef _GWSHTXX_H
|
||||
#define _GWSHTXX_H
|
||||
#ifndef _GWSHT3X_H
|
||||
#define _GWSHT3X_H
|
||||
#include "GwIicSensors.h"
|
||||
#ifdef _GWIIC
|
||||
#if defined(GWSHT3X) || defined(GWSHT3X11) || defined(GWSHT3X12) || defined(GWSHT3X21) || defined(GWSHT3X22)
|
||||
#define _GWSHT3X
|
||||
#endif
|
||||
#if defined(GWSHT4X) || defined(GWSHT4X11) || defined(GWSHT4X12) || defined(GWSHT4X21) || defined(GWSHT4X22)
|
||||
#define _GWSHT4X
|
||||
#endif
|
||||
#else
|
||||
#undef _GWSHT3X
|
||||
#undef GWSHT3X
|
||||
@@ -15,19 +12,9 @@
|
||||
#undef GWSHT3X12
|
||||
#undef GWSHT3X21
|
||||
#undef GWSHT3X22
|
||||
#undef _GWSHT4X
|
||||
#undef GWSHT4X
|
||||
#undef GWSHT4X11
|
||||
#undef GWSHT4X12
|
||||
#undef GWSHT4X21
|
||||
#undef GWSHT4X22
|
||||
#endif
|
||||
#ifdef _GWSHT3X
|
||||
#include "SHT3X.h"
|
||||
#endif
|
||||
#ifdef _GWSHT4X
|
||||
#include "SHT4X.h"
|
||||
#endif
|
||||
SensorBase::Creator registerSHT3X(GwApi *api);
|
||||
SensorBase::Creator registerSHT4X(GwApi *api);
|
||||
#endif
|
||||
@@ -1,254 +0,0 @@
|
||||
#include "GwSHTXX.h"
|
||||
#if defined(_GWSHT3X) || defined(_GWSHT4X)
|
||||
class SHTXXConfig : public IICSensorBase{
|
||||
public:
|
||||
String tmNam;
|
||||
String huNam;
|
||||
bool tmAct=false;
|
||||
bool huAct=false;
|
||||
bool sEnv=true;
|
||||
tN2kHumiditySource huSrc;
|
||||
tN2kTempSource tmSrc;
|
||||
using IICSensorBase::IICSensorBase;
|
||||
virtual bool isActive(){
|
||||
return tmAct || huAct;
|
||||
}
|
||||
virtual bool preinit(GwApi * api){
|
||||
GwLog *logger=api->getLogger();
|
||||
LOG_DEBUG(GwLog::LOG,"%s configured",prefix.c_str());
|
||||
addHumidXdr(api,*this);
|
||||
addTempXdr(api,*this);
|
||||
return isActive();
|
||||
}
|
||||
virtual bool doMeasure(GwApi * api,double &temp, double &humid){
|
||||
return false;
|
||||
}
|
||||
virtual void measure(GwApi * api,TwoWire *wire, int counterId) override
|
||||
{
|
||||
GwLog *logger=api->getLogger();
|
||||
double temp = N2kDoubleNA;
|
||||
double humid = N2kDoubleNA;
|
||||
if (doMeasure(api,temp,humid)){
|
||||
temp = CToKelvin(temp);
|
||||
LOG_DEBUG(GwLog::DEBUG, "%s measure temp=%2.1f, humid=%2.0f",prefix.c_str(), (float)temp, (float)humid);
|
||||
if (huAct)
|
||||
{
|
||||
sendN2kHumidity(api, *this, humid, counterId);
|
||||
}
|
||||
if (tmAct)
|
||||
{
|
||||
sendN2kTemperature(api, *this, temp, counterId);
|
||||
}
|
||||
if (huAct || tmAct){
|
||||
sendN2kEnvironmentalParameters(api,*this,temp,humid,N2kDoubleNA,counterId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* we do not dynamically compute the config names
|
||||
* just to get compile time errors if something does not fit
|
||||
* correctly
|
||||
*/
|
||||
#define INITSHTXX(type,prefix,bus,baddr) \
|
||||
[] (type *s ,GwConfigHandler *cfg) { \
|
||||
CFG_SGET(s, tmNam, prefix); \
|
||||
CFG_SGET(s, huNam, prefix); \
|
||||
CFG_SGET(s, iid, prefix); \
|
||||
CFG_SGET(s, tmAct, prefix); \
|
||||
CFG_SGET(s, huAct, prefix); \
|
||||
CFG_SGET(s, intv, prefix); \
|
||||
CFG_SGET(s, huSrc, prefix); \
|
||||
CFG_SGET(s, tmSrc, prefix); \
|
||||
CFG_SGET(s, sEnv,prefix); \
|
||||
s->busId = bus; \
|
||||
s->addr = baddr; \
|
||||
s->ok = true; \
|
||||
s->intv *= 1000; \
|
||||
}
|
||||
|
||||
#if defined(_GWSHT3X)
|
||||
class SHT3XConfig;
|
||||
static GwSensorConfigInitializerList<SHT3XConfig> configs3;
|
||||
class SHT3XConfig : public SHTXXConfig{
|
||||
SHT3X *device=nullptr;
|
||||
public:
|
||||
using SHTXXConfig::SHTXXConfig;
|
||||
virtual bool initDevice(GwApi * api,TwoWire *wire)override{
|
||||
if (! isActive()) return false;
|
||||
device=new SHT3X();
|
||||
device->init(addr,wire);
|
||||
GwLog *logger=api->getLogger();
|
||||
LOG_DEBUG(GwLog::LOG,"initialized %s at address %d, intv %ld",prefix.c_str(),(int)addr,intv);
|
||||
return true;
|
||||
}
|
||||
virtual bool doMeasure(GwApi *api,double &temp, double &humid) override{
|
||||
if (!device)
|
||||
return false;
|
||||
int rt=0;
|
||||
GwLog *logger=api->getLogger();
|
||||
if ((rt = device->get()) == 0)
|
||||
{
|
||||
temp = device->cTemp;
|
||||
humid = device->humidity;
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
LOG_DEBUG(GwLog::DEBUG, "unable to query %s: %d",prefix.c_str(), rt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual void readConfig(GwConfigHandler *cfg) override{
|
||||
if (ok) return;
|
||||
configs3.readConfig(this,cfg);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
SensorBase::Creator creator3=[](GwApi *api,const String &prfx)-> SensorBase*{
|
||||
if (! configs3.knowsPrefix(prfx)) return nullptr;
|
||||
return new SHT3XConfig(api,prfx);
|
||||
};
|
||||
SensorBase::Creator registerSHT3X(GwApi *api){
|
||||
GwLog *logger=api->getLogger();
|
||||
#if defined(GWSHT3X) || defined (GWSHT3X11)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT3X11"));
|
||||
CHECK_IIC1();
|
||||
#pragma message "GWSHT3X11 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT3X12)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT3X12"));
|
||||
CHECK_IIC1();
|
||||
#pragma message "GWSHT3X12 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT3X21)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT3X21"));
|
||||
CHECK_IIC2();
|
||||
#pragma message "GWSHT3X21 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT3X22)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT3X22"));
|
||||
CHECK_IIC2();
|
||||
#pragma message "GWSHT3X22 defined"
|
||||
}
|
||||
#endif
|
||||
return creator3;
|
||||
};
|
||||
|
||||
|
||||
#define SCSHT3X(prefix, bus, addr) \
|
||||
GwSensorConfigInitializer<SHT3XConfig> __initCFGSHT3X ## prefix \
|
||||
(configs3,GwSensorConfig<SHT3XConfig>(#prefix,INITSHTXX(SHT3XConfig,prefix,bus,addr)));
|
||||
|
||||
SCSHT3X(SHT3X11, 1, 0x44);
|
||||
SCSHT3X(SHT3X12, 1, 0x45);
|
||||
SCSHT3X(SHT3X21, 2, 0x44);
|
||||
SCSHT3X(SHT3X22, 2, 0x45);
|
||||
|
||||
#endif
|
||||
#if defined(_GWSHT4X)
|
||||
class SHT4XConfig;
|
||||
static GwSensorConfigInitializerList<SHT4XConfig> configs4;
|
||||
class SHT4XConfig : public SHTXXConfig{
|
||||
SHT4X *device=nullptr;
|
||||
public:
|
||||
using SHTXXConfig::SHTXXConfig;
|
||||
virtual bool initDevice(GwApi * api,TwoWire *wire)override{
|
||||
if (! isActive()) return false;
|
||||
device=new SHT4X();
|
||||
device->begin(wire,addr);
|
||||
GwLog *logger=api->getLogger();
|
||||
LOG_DEBUG(GwLog::LOG,"initialized %s at address %d, intv %ld",prefix.c_str(),(int)addr,intv);
|
||||
return true;
|
||||
}
|
||||
virtual bool doMeasure(GwApi *api,double &temp, double &humid) override{
|
||||
if (!device)
|
||||
return false;
|
||||
GwLog *logger=api->getLogger();
|
||||
if (device->update())
|
||||
{
|
||||
temp = device->cTemp;
|
||||
humid = device->humidity;
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
LOG_DEBUG(GwLog::DEBUG, "unable to query %s",prefix.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual void readConfig(GwConfigHandler *cfg) override{
|
||||
if (ok) return;
|
||||
configs4.readConfig(this,cfg);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
SensorBase::Creator creator4=[](GwApi *api,const String &prfx)-> SensorBase*{
|
||||
if (! configs4.knowsPrefix(prfx)) return nullptr;
|
||||
return new SHT4XConfig(api,prfx);
|
||||
};
|
||||
SensorBase::Creator registerSHT4X(GwApi *api){
|
||||
GwLog *logger=api->getLogger();
|
||||
#if defined(GWSHT4X) || defined (GWSHT4X11)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT4X11"));
|
||||
CHECK_IIC1();
|
||||
#pragma message "GWSHT4X11 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT4X12)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT4X12"));
|
||||
CHECK_IIC1();
|
||||
#pragma message "GWSHT4X12 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT4X21)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT4X21"));
|
||||
CHECK_IIC2();
|
||||
#pragma message "GWSHT4X21 defined"
|
||||
}
|
||||
#endif
|
||||
#if defined(GWSHT4X22)
|
||||
{
|
||||
api->addSensor(creator3(api,"SHT4X22"));
|
||||
CHECK_IIC2();
|
||||
#pragma message "GWSHT4X22 defined"
|
||||
}
|
||||
#endif
|
||||
return creator4;
|
||||
};
|
||||
|
||||
|
||||
#define SCSHT4X(prefix, bus, addr) \
|
||||
GwSensorConfigInitializer<SHT4XConfig> __initCFGSHT4X ## prefix \
|
||||
(configs4,GwSensorConfig<SHT4XConfig>(#prefix,INITSHTXX(SHT4XConfig,prefix,bus,addr)));
|
||||
|
||||
SCSHT4X(SHT4X11, 1, 0x44);
|
||||
SCSHT4X(SHT4X12, 1, 0x45);
|
||||
SCSHT4X(SHT4X21, 2, 0x44);
|
||||
SCSHT4X(SHT4X22, 2, 0x45);
|
||||
#endif
|
||||
#endif
|
||||
#ifndef _GWSHT3X
|
||||
SensorBase::Creator registerSHT3X(GwApi *api){
|
||||
return SensorBase::Creator();
|
||||
}
|
||||
#endif
|
||||
#ifndef _GWSHT4X
|
||||
SensorBase::Creator registerSHT4X(GwApi *api){
|
||||
return SensorBase::Creator();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "GwSHTXX.h"
|
||||
#include "GwSHT3X.h"
|
||||
#ifdef _GWSHT3X
|
||||
|
||||
bool SHT3X::init(uint8_t slave_addr_in, TwoWire* wire_in)
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
#include "GwSHTXX.h"
|
||||
#ifdef _GWSHT4X
|
||||
|
||||
uint8_t crc8(const uint8_t *data, int len) {
|
||||
/*
|
||||
*
|
||||
* CRC-8 formula from page 14 of SHT spec pdf
|
||||
*
|
||||
* Test data 0xBE, 0xEF should yield 0x92
|
||||
*
|
||||
* Initialization data 0xFF
|
||||
* Polynomial 0x31 (x8 + x5 +x4 +1)
|
||||
* Final XOR 0x00
|
||||
*/
|
||||
|
||||
const uint8_t POLYNOMIAL(0x31);
|
||||
uint8_t crc(0xFF);
|
||||
|
||||
for (int j = len; j; --j) {
|
||||
crc ^= *data++;
|
||||
|
||||
for (int i = 8; i; --i) {
|
||||
crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool SHT4X::begin(TwoWire* wire, uint8_t addr) {
|
||||
_addr = addr;
|
||||
_wire = wire;
|
||||
int error;
|
||||
_wire->beginTransmission(addr);
|
||||
error = _wire->endTransmission();
|
||||
if (error == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHT4X::update() {
|
||||
uint8_t readbuffer[6];
|
||||
uint8_t cmd = SHT4x_NOHEAT_HIGHPRECISION;
|
||||
uint16_t duration = 10;
|
||||
|
||||
if (_heater == SHT4X_NO_HEATER) {
|
||||
if (_precision == SHT4X_HIGH_PRECISION) {
|
||||
cmd = SHT4x_NOHEAT_HIGHPRECISION;
|
||||
duration = 10;
|
||||
}
|
||||
if (_precision == SHT4X_MED_PRECISION) {
|
||||
cmd = SHT4x_NOHEAT_MEDPRECISION;
|
||||
duration = 5;
|
||||
}
|
||||
if (_precision == SHT4X_LOW_PRECISION) {
|
||||
cmd = SHT4x_NOHEAT_LOWPRECISION;
|
||||
duration = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (_heater == SHT4X_HIGH_HEATER_1S) {
|
||||
cmd = SHT4x_HIGHHEAT_1S;
|
||||
duration = 1100;
|
||||
}
|
||||
if (_heater == SHT4X_HIGH_HEATER_100MS) {
|
||||
cmd = SHT4x_HIGHHEAT_100MS;
|
||||
duration = 110;
|
||||
}
|
||||
|
||||
if (_heater == SHT4X_MED_HEATER_1S) {
|
||||
cmd = SHT4x_MEDHEAT_1S;
|
||||
duration = 1100;
|
||||
}
|
||||
if (_heater == SHT4X_MED_HEATER_100MS) {
|
||||
cmd = SHT4x_MEDHEAT_100MS;
|
||||
duration = 110;
|
||||
}
|
||||
|
||||
if (_heater == SHT4X_LOW_HEATER_1S) {
|
||||
cmd = SHT4x_LOWHEAT_1S;
|
||||
duration = 1100;
|
||||
}
|
||||
if (_heater == SHT4X_LOW_HEATER_100MS) {
|
||||
cmd = SHT4x_LOWHEAT_100MS;
|
||||
duration = 110;
|
||||
}
|
||||
// _i2c.writeByte(_addr, cmd, 1);
|
||||
_wire->beginTransmission(_addr);
|
||||
_wire->write(cmd);
|
||||
_wire->write(1);
|
||||
_wire->endTransmission();
|
||||
|
||||
|
||||
delay(duration);
|
||||
|
||||
_wire->requestFrom(_addr, (uint8_t)6);
|
||||
|
||||
for (uint16_t i = 0; i < 6; i++) {
|
||||
readbuffer[i] = _wire->read();
|
||||
}
|
||||
|
||||
if (readbuffer[2] != crc8(readbuffer, 2) ||
|
||||
readbuffer[5] != crc8(readbuffer + 3, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float t_ticks = (uint16_t)readbuffer[0] * 256 + (uint16_t)readbuffer[1];
|
||||
float rh_ticks = (uint16_t)readbuffer[3] * 256 + (uint16_t)readbuffer[4];
|
||||
|
||||
cTemp = -45 + 175 * t_ticks / 65535;
|
||||
humidity = -6 + 125 * rh_ticks / 65535;
|
||||
humidity = min(max(humidity, (float)0.0), (float)100.0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHT4X::setPrecision(sht4x_precision_t prec) {
|
||||
_precision = prec;
|
||||
}
|
||||
|
||||
sht4x_precision_t SHT4X::getPrecision(void) {
|
||||
return _precision;
|
||||
}
|
||||
|
||||
void SHT4X::setHeater(sht4x_heater_t heat) {
|
||||
_heater = heat;
|
||||
}
|
||||
|
||||
sht4x_heater_t SHT4X::getHeater(void) {
|
||||
return _heater;
|
||||
}
|
||||
#endif
|
||||
@@ -1,76 +0,0 @@
|
||||
#ifndef __SHT4X_H_
|
||||
#define __SHT4X_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
#define SHT40_I2C_ADDR_44 0x44
|
||||
#define SHT40_I2C_ADDR_45 0x45
|
||||
#define SHT41_I2C_ADDR_44 0x44
|
||||
#define SHT41_I2C_ADDR_45 0x45
|
||||
#define SHT45_I2C_ADDR_44 0x44
|
||||
#define SHT45_I2C_ADDR_45 0x45
|
||||
|
||||
#define SHT4x_DEFAULT_ADDR 0x44 /**< SHT4x I2C Address */
|
||||
#define SHT4x_NOHEAT_HIGHPRECISION \
|
||||
0xFD /**< High precision measurement, no heater */
|
||||
#define SHT4x_NOHEAT_MEDPRECISION \
|
||||
0xF6 /**< Medium precision measurement, no heater */
|
||||
#define SHT4x_NOHEAT_LOWPRECISION \
|
||||
0xE0 /**< Low precision measurement, no heater */
|
||||
|
||||
#define SHT4x_HIGHHEAT_1S \
|
||||
0x39 /**< High precision measurement, high heat for 1 sec */
|
||||
#define SHT4x_HIGHHEAT_100MS \
|
||||
0x32 /**< High precision measurement, high heat for 0.1 sec */
|
||||
#define SHT4x_MEDHEAT_1S \
|
||||
0x2F /**< High precision measurement, med heat for 1 sec */
|
||||
#define SHT4x_MEDHEAT_100MS \
|
||||
0x24 /**< High precision measurement, med heat for 0.1 sec */
|
||||
#define SHT4x_LOWHEAT_1S \
|
||||
0x1E /**< High precision measurement, low heat for 1 sec */
|
||||
#define SHT4x_LOWHEAT_100MS \
|
||||
0x15 /**< High precision measurement, low heat for 0.1 sec */
|
||||
|
||||
#define SHT4x_READSERIAL 0x89 /**< Read Out of Serial Register */
|
||||
#define SHT4x_SOFTRESET 0x94 /**< Soft Reset */
|
||||
|
||||
typedef enum {
|
||||
SHT4X_HIGH_PRECISION,
|
||||
SHT4X_MED_PRECISION,
|
||||
SHT4X_LOW_PRECISION,
|
||||
} sht4x_precision_t;
|
||||
|
||||
/** Optional pre-heater configuration setting */
|
||||
typedef enum {
|
||||
SHT4X_NO_HEATER,
|
||||
SHT4X_HIGH_HEATER_1S,
|
||||
SHT4X_HIGH_HEATER_100MS,
|
||||
SHT4X_MED_HEATER_1S,
|
||||
SHT4X_MED_HEATER_100MS,
|
||||
SHT4X_LOW_HEATER_1S,
|
||||
SHT4X_LOW_HEATER_100MS,
|
||||
} sht4x_heater_t;
|
||||
|
||||
class SHT4X {
|
||||
public:
|
||||
bool begin(TwoWire* wire = &Wire, uint8_t addr = SHT40_I2C_ADDR_44);
|
||||
bool update(void);
|
||||
|
||||
float cTemp = 0;
|
||||
float humidity = 0;
|
||||
|
||||
void setPrecision(sht4x_precision_t prec);
|
||||
sht4x_precision_t getPrecision(void);
|
||||
void setHeater(sht4x_heater_t heat);
|
||||
sht4x_heater_t getHeater(void);
|
||||
|
||||
private:
|
||||
TwoWire* _wire;
|
||||
uint8_t _addr;
|
||||
|
||||
sht4x_precision_t _precision = SHT4X_HIGH_PRECISION;
|
||||
sht4x_heater_t _heater = SHT4X_NO_HEATER;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,77 +1,49 @@
|
||||
[
|
||||
{
|
||||
"type": "array",
|
||||
"name": "SHTXX",
|
||||
"name": "SHT3X",
|
||||
"replace": [
|
||||
{
|
||||
"b": "1",
|
||||
"i": "11",
|
||||
"n": "99",
|
||||
"x": "3"
|
||||
"n": "99"
|
||||
},
|
||||
{
|
||||
"b": "1",
|
||||
"i": "12",
|
||||
"n": "98",
|
||||
"x": "3"
|
||||
"n": "98"
|
||||
},
|
||||
{
|
||||
"b": "2",
|
||||
"i": "21",
|
||||
"n": "109",
|
||||
"x": "3"
|
||||
"n": "109"
|
||||
},
|
||||
{
|
||||
"b": "2",
|
||||
"i": "22",
|
||||
"n": "108",
|
||||
"x": "3"
|
||||
},
|
||||
{
|
||||
"b": "1",
|
||||
"i": "11",
|
||||
"n": "119",
|
||||
"x": "4"
|
||||
},
|
||||
{
|
||||
"b": "1",
|
||||
"i": "12",
|
||||
"n": "118",
|
||||
"x": "4"
|
||||
},
|
||||
{
|
||||
"b": "2",
|
||||
"i": "21",
|
||||
"n": "129",
|
||||
"x": "4"
|
||||
},
|
||||
{
|
||||
"b": "2",
|
||||
"i": "22",
|
||||
"n": "128",
|
||||
"x": "4"
|
||||
"n": "108"
|
||||
}
|
||||
|
||||
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"name": "SHT$xX$itmAct",
|
||||
"label": "SHT$xX$i Temp",
|
||||
"name": "SHT3X$itmAct",
|
||||
"label": "SHT3X$i Temp",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "Enable the $i. I2C SHT$xX temp sensor (bus $b)",
|
||||
"description": "Enable the $i. I2C SHT3x temp sensor (bus $b)",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
"SHT3X$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$itmSrc",
|
||||
"label": "SHT$xX$i Temp Type",
|
||||
"name": "SHT3X$itmSrc",
|
||||
"label": "SHT3X$i Temp Type",
|
||||
"type": "list",
|
||||
"default": "2",
|
||||
"description": "the NMEA2000 source type for the temperature (PGN 130312,130311)",
|
||||
"description": "the NMEA2000 source type for the temperature",
|
||||
"list": [
|
||||
{
|
||||
"l": "SeaTemperature",
|
||||
@@ -140,23 +112,23 @@
|
||||
],
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
"SHT3X$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$ihuAct",
|
||||
"label": "SHT$xX$i Humidity",
|
||||
"name": "SHT3X$ihuAct",
|
||||
"label": "SHT3X$i Humidity",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "Enable the $i. I2C SHT$xX humidity sensor (bus $b)",
|
||||
"description": "Enable the $i. I2C SHT3x humidity sensor (bus $b)",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
"SHT3X$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$ihuSrc",
|
||||
"label": "SHT$xX$i Humid Type",
|
||||
"name": "SHT3X$ihuSrc",
|
||||
"label": "SHT3X$i Humid Type",
|
||||
"list": [
|
||||
{
|
||||
"l": "OutsideHumidity",
|
||||
@@ -169,68 +141,57 @@
|
||||
],
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"SHT$xX": "true"
|
||||
"SHT3X": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$iiid",
|
||||
"label": "SHT$xX$i N2K iid",
|
||||
"name": "SHT3X$iiid",
|
||||
"label": "SHT3X$i N2K iid",
|
||||
"type": "number",
|
||||
"default": "$n",
|
||||
"description": "the N2K instance id for the $i. SHT$xX Temperature and Humidity (PGN 130312,130311) ",
|
||||
"description": "the N2K instance id for the $i. SHT3X Temperature and Humidity ",
|
||||
"category": "iicsensors$b",
|
||||
"min": 0,
|
||||
"max": 253,
|
||||
"check": "checkMinMax",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
"SHT3X$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$isEnv",
|
||||
"label": "SHT$xX$i send Env",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "also send PGN 130311",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$iintv",
|
||||
"label": "SHT$xX$i Interval",
|
||||
"name": "SHT3X$iintv",
|
||||
"label": "SHT3X$i Interval",
|
||||
"type": "number",
|
||||
"default": 2,
|
||||
"description": "Interval(s) to query SHT$xX Temperature and Humidity (1...300)",
|
||||
"description": "Interval(s) to query SHT3X Temperature and Humidity (1...300)",
|
||||
"category": "iicsensors$b",
|
||||
"min": 1,
|
||||
"max": 300,
|
||||
"check": "checkMinMax",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
"SHT3X$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$itmNam",
|
||||
"label": "SHT$xX$i Temp XDR",
|
||||
"name": "SHT3X$itmNam",
|
||||
"label": "SHT3X$i Temp XDR",
|
||||
"type": "String",
|
||||
"default": "Temp$i",
|
||||
"description": "set the XDR transducer name for the $i. SHT$xX Temperature, leave empty to disable NMEA0183 XDR ",
|
||||
"description": "set the XDR transducer name for the $i. SHT3X Temperature, leave empty to disable NMEA0183 XDR ",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
"SHT3X$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SHT$xX$ihuNam",
|
||||
"label": "SHT$xX$i Humid XDR",
|
||||
"name": "SHT3X$ihuNam",
|
||||
"label": "SHT3X$i Humid XDR",
|
||||
"type": "String",
|
||||
"default": "Humidity$i",
|
||||
"description": "set the XDR transducer name for the $i. SHT$xX Humidity, leave empty to disable NMEA0183 XDR",
|
||||
"description": "set the XDR transducer name for the $i. SHT3X Humidity, leave empty to disable NMEA0183 XDR",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"SHT$xX$i": "true"
|
||||
"SHT3X$i": "true"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -286,17 +247,6 @@
|
||||
"QMP6988$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "QMP6988$isEnv",
|
||||
"label": "QMP6988$i send Env",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "also send PGN 130311",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"QMP6988$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "QMP6988$iintv",
|
||||
"label": "QMP6988-$i Interval",
|
||||
@@ -523,7 +473,7 @@
|
||||
"label": "BME280-$i N2K iid",
|
||||
"type": "number",
|
||||
"default": "$n",
|
||||
"description": "the N2K instance id for the BME280 Temperature, Humidity, Pressure (PGN 130312,130313, 130314) ",
|
||||
"description": "the N2K instance id for the BME280 Temperature and Humidity ",
|
||||
"category": "iicsensors$b",
|
||||
"min": 0,
|
||||
"max": 253,
|
||||
@@ -532,17 +482,6 @@
|
||||
"BME280$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "BME280$isEnv",
|
||||
"label": "BME280$i send Env",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "also send PGN 130311",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"BME280$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "BME280$iintv",
|
||||
"label": "BME280-$i Interval",
|
||||
@@ -744,7 +683,7 @@
|
||||
"label": "BMP280-$i N2K iid",
|
||||
"type": "number",
|
||||
"default": "$n",
|
||||
"description": "the N2K instance id for the BMP280 Temperature/Pressure (PGN 130312,130314)",
|
||||
"description": "the N2K instance id for the BMP280 Temperature",
|
||||
"category": "iicsensors$b",
|
||||
"min": 0,
|
||||
"max": 253,
|
||||
@@ -753,17 +692,6 @@
|
||||
"BMP280$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "BMP280$isEnv",
|
||||
"label": "BMP280$i send Env",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "also send PGN 130311",
|
||||
"category": "iicsensors$b",
|
||||
"capabilities": {
|
||||
"BMP280$i": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "BMP280$iintv",
|
||||
"label": "BMP280-$i Interval",
|
||||
|
||||
@@ -11,17 +11,6 @@ build_flags=
|
||||
-D M5_CAN_KIT
|
||||
${env.build_flags}
|
||||
|
||||
[env:m5stack-atom-env4]
|
||||
extends = sensors
|
||||
board = m5stack-atom
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
${sensors.lib_deps}
|
||||
build_flags=
|
||||
-D M5_ENV4
|
||||
-D M5_CAN_KIT
|
||||
${env.build_flags}
|
||||
|
||||
|
||||
[env:m5stack-atom-bme280]
|
||||
extends = sensors
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
@@ -27,8 +27,6 @@ const double nmTom = 1.852 * 1000;
|
||||
|
||||
uint16_t DaysSince1970 = 0;
|
||||
|
||||
#define boolbit(b) (b?1:0)
|
||||
|
||||
class MyAisDecoder : public AIS::AisDecoder
|
||||
{
|
||||
public:
|
||||
@@ -84,24 +82,25 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
|
||||
SetN2kPGN129038(
|
||||
N2kMsg,
|
||||
_uMsgType,
|
||||
(tN2kAISRepeat)_Repeat,
|
||||
_uMmsi,
|
||||
_iPosLon/ 600000.0,
|
||||
_iPosLat / 600000.0,
|
||||
_bPosAccuracy,
|
||||
_Raim,
|
||||
_timestamp,
|
||||
decodeCog(_iCog),
|
||||
_uSog * knToms/10.0,
|
||||
tN2kAISTransceiverInformation::N2kaischannel_A_VDL_reception,
|
||||
decodeHeading(_iHeading),
|
||||
decodeRot(_iRot),
|
||||
(tN2kAISNavStatus)_uNavstatus,
|
||||
0xff
|
||||
);
|
||||
// PGN129038
|
||||
|
||||
N2kMsg.SetPGN(129038L);
|
||||
N2kMsg.Priority = 4;
|
||||
N2kMsg.AddByte((_Repeat & 0x03) << 6 | (_uMsgType & 0x3f));
|
||||
N2kMsg.Add4ByteUInt(_uMmsi);
|
||||
N2kMsg.Add4ByteDouble(_iPosLon / 600000.0, 1e-07);
|
||||
N2kMsg.Add4ByteDouble(_iPosLat / 600000.0, 1e-07);
|
||||
N2kMsg.AddByte((_timestamp & 0x3f) << 2 | (_Raim & 0x01) << 1 | (_bPosAccuracy & 0x01));
|
||||
N2kMsg.Add2ByteUDouble(decodeCog(_iCog), 1e-04);
|
||||
N2kMsg.Add2ByteUDouble(_uSog * knToms/10.0, 0.01);
|
||||
N2kMsg.AddByte(0x00); // Communication State (19 bits)
|
||||
N2kMsg.AddByte(0x00);
|
||||
N2kMsg.AddByte(0x00); // AIS transceiver information (5 bits)
|
||||
N2kMsg.Add2ByteUDouble(decodeHeading(_iHeading), 1e-04);
|
||||
N2kMsg.Add2ByteDouble(decodeRot(_iRot), 3.125E-05); // 1e-3/32.0
|
||||
N2kMsg.AddByte(0xF0 | (_uNavstatus & 0x0f));
|
||||
N2kMsg.AddByte(0xff); // Reserved
|
||||
N2kMsg.AddByte(0xff); // SID (NA)
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
@@ -256,40 +255,9 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
//mmsi, aidType, name + nameExt, posAccuracy, posLon, posLat, toBow, toStern, toPort, toStarboard
|
||||
virtual void onType21(unsigned int mmsi , unsigned int aidType , const std::string & name, bool accuracy, int posLon, int posLat, unsigned int toBow,
|
||||
unsigned int toStern, unsigned int toPort, unsigned int toStarboard,
|
||||
unsigned int repeat,unsigned int timestamp, bool raim, bool virtualAton, bool offPosition) override {
|
||||
|
||||
virtual void onType21(unsigned int , unsigned int , const std::string &, bool , int , int , unsigned int , unsigned int , unsigned int , unsigned int ) override {
|
||||
//Serial.println("21");
|
||||
//the name can be at most 120bit+88bit (35 byte) + termination -> 36 Byte
|
||||
//in principle we should use tN2kAISAtoNReportData to directly call the library
|
||||
//function for 129041. But this makes the conversion really complex.
|
||||
bool assignedMode=false;
|
||||
tN2kGNSStype gnssType=tN2kGNSStype::N2kGNSSt_GPS; //canboat considers 0 as undefined...
|
||||
tN2kAISTransceiverInformation transceiverInfo=tN2kAISTransceiverInformation::N2kaischannel_A_VDL_reception;
|
||||
tN2kMsg N2kMsg;
|
||||
N2kMsg.SetPGN(129041);
|
||||
N2kMsg.Priority=4;
|
||||
N2kMsg.AddByte((repeat & 0x03) << 6 | (21 & 0x3f));
|
||||
N2kMsg.Add4ByteUInt(mmsi); //N2kData.UserID
|
||||
N2kMsg.Add4ByteDouble(posLon / 600000.0, 1e-07);
|
||||
N2kMsg.Add4ByteDouble(posLat / 600000.0, 1e-07);
|
||||
N2kMsg.AddByte((timestamp & 0x3f)<<2 | boolbit(raim)<<1 | boolbit(accuracy));
|
||||
N2kMsg.Add2ByteUDouble(toBow+toStern, 0.1);
|
||||
N2kMsg.Add2ByteUDouble(toPort+toStarboard, 0.1);
|
||||
N2kMsg.Add2ByteUDouble(toStarboard, 0.1);
|
||||
N2kMsg.Add2ByteUDouble(toBow, 0.1);
|
||||
N2kMsg.AddByte(boolbit(assignedMode) << 7
|
||||
| boolbit(virtualAton) << 6
|
||||
| boolbit(offPosition) << 5
|
||||
| (aidType & 0x1f));
|
||||
N2kMsg.AddByte((gnssType & 0x0F) << 1 | 0xe0);
|
||||
N2kMsg.AddByte(N2kUInt8NA); //status
|
||||
N2kMsg.AddByte((transceiverInfo & 0x1f) | 0xe0);
|
||||
//bit offset 208 (see canboat/pgns.xml) -> 26 bytes from start
|
||||
//as MaxDataLen is 223 and the string can be at most 36 bytes + 2 byte heading - no further check here
|
||||
N2kMsg.AddVarStr(name.c_str());
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
virtual void onType24A(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi,
|
||||
|
||||
@@ -143,7 +143,7 @@ private:
|
||||
*/
|
||||
GwXDRFoundMapping getOtherFieldMapping(GwXDRFoundMapping &found, int field){
|
||||
if (found.empty) return GwXDRFoundMapping();
|
||||
return xdrMappings->getMapping(0,found.definition->category,
|
||||
return xdrMappings->getMapping(found.definition->category,
|
||||
found.definition->selector,
|
||||
field,
|
||||
found.instanceId);
|
||||
@@ -355,6 +355,7 @@ private:
|
||||
AppendN2kRouteWPInfo(n2kMsg,destinationId,rmb.destID,rmb.latitude,rmb.longitude);
|
||||
send(n2kMsg,msg.sourceId);
|
||||
}
|
||||
boatData->WPName->update(String(rmb.destID), msg.sourceId);
|
||||
}
|
||||
void convertRMC(const SNMEA0183Msg &msg)
|
||||
{
|
||||
|
||||
@@ -708,37 +708,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
//helper for converting the AIS transceiver info to talker/channel
|
||||
|
||||
void setTalkerChannel(tNMEA0183AISMsg &msg, tN2kAISTransceiverInformation &transceiver){
|
||||
bool channelA=true;
|
||||
bool own=false;
|
||||
switch (transceiver){
|
||||
case tN2kAISTransceiverInformation::N2kaischannel_A_VDL_reception:
|
||||
channelA=true;
|
||||
own=false;
|
||||
break;
|
||||
case tN2kAISTransceiverInformation::N2kaischannel_B_VDL_reception:
|
||||
channelA=false;
|
||||
own=false;
|
||||
break;
|
||||
case tN2kAISTransceiverInformation::N2kaischannel_A_VDL_transmission:
|
||||
channelA=true;
|
||||
own=true;
|
||||
break;
|
||||
case tN2kAISTransceiverInformation::N2kaischannel_B_VDL_transmission:
|
||||
channelA=false;
|
||||
own=true;
|
||||
break;
|
||||
}
|
||||
msg.SetChannelAndTalker(channelA,own);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// 129038 AIS Class A Position Report (Message 1, 2, 3)
|
||||
void HandleAISClassAPosReport(const tN2kMsg &N2kMsg)
|
||||
{
|
||||
|
||||
unsigned char SID;
|
||||
tN2kAISRepeat _Repeat;
|
||||
uint32_t _UserID; // MMSI
|
||||
double _Latitude =N2kDoubleNA;
|
||||
@@ -757,19 +732,64 @@ private:
|
||||
uint8_t _MessageType = 1;
|
||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||
|
||||
if (ParseN2kPGN129038(N2kMsg, _MessageType, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, _Seconds,
|
||||
if (ParseN2kPGN129038(N2kMsg, SID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, _Seconds,
|
||||
_COG, _SOG, _Heading, _ROT, _NavStatus,_AISTransceiverInformation,_SID))
|
||||
{
|
||||
|
||||
// Debug
|
||||
#ifdef SERIAL_PRINT_AIS_FIELDS
|
||||
Serial.println("–––––––––––––––––––––––– Msg 1 ––––––––––––––––––––––––––––––––");
|
||||
|
||||
const double pi = 3.1415926535897932384626433832795;
|
||||
const double radToDeg = 180.0 / pi;
|
||||
const double msTokn = 3600.0 / 1852.0;
|
||||
const double radsToDegMin = 60 * 360.0 / (2 * pi); // [rad/s -> degree/minute]
|
||||
Serial.print("Repeat: ");
|
||||
Serial.println(_Repeat);
|
||||
Serial.print("UserID: ");
|
||||
Serial.println(_UserID);
|
||||
Serial.print("Latitude: ");
|
||||
Serial.println(_Latitude);
|
||||
Serial.print("Longitude: ");
|
||||
Serial.println(_Longitude);
|
||||
Serial.print("Accuracy: ");
|
||||
Serial.println(_Accuracy);
|
||||
Serial.print("RAIM: ");
|
||||
Serial.println(_RAIM);
|
||||
Serial.print("Seconds: ");
|
||||
Serial.println(_Seconds);
|
||||
Serial.print("COG: ");
|
||||
Serial.println(_COG * radToDeg);
|
||||
Serial.print("SOG: ");
|
||||
Serial.println(_SOG * msTokn);
|
||||
Serial.print("Heading: ");
|
||||
Serial.println(_Heading * radToDeg);
|
||||
Serial.print("ROT: ");
|
||||
Serial.println(_ROT * radsToDegMin);
|
||||
Serial.print("NavStatus: ");
|
||||
Serial.println(_NavStatus);
|
||||
#endif
|
||||
|
||||
setTalkerChannel(NMEA0183AISMsg,_AISTransceiverInformation);
|
||||
if (_MessageType < 1 || _MessageType > 3) _MessageType=1; //only allow type 1...3 for 129038
|
||||
if (SetAISClassABMessage1(NMEA0183AISMsg, _MessageType, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy,
|
||||
_RAIM, _Seconds, _COG, _SOG, _Heading, _ROT, _NavStatus))
|
||||
{
|
||||
|
||||
SendMessage(NMEA0183AISMsg);
|
||||
|
||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
||||
// Debug Print AIS-NMEA
|
||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
||||
Serial.print(NMEA0183AISMsg.Sender());
|
||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
||||
{
|
||||
Serial.print(",");
|
||||
Serial.print(NMEA0183AISMsg.Field(i));
|
||||
}
|
||||
char buf[7];
|
||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
||||
Serial.print(buf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // end 129038 AIS Class A Position Report Message 1/3
|
||||
@@ -805,18 +825,84 @@ private:
|
||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,21,
|
||||
_AISversion, _GNSStype, _DTE, _AISinfo,_SID))
|
||||
{
|
||||
setTalkerChannel(NMEA0183AISMsg,_AISinfo);
|
||||
|
||||
#ifdef SERIAL_PRINT_AIS_FIELDS
|
||||
// Debug Print N2k Values
|
||||
Serial.println("––––––––––––––––––––––– Msg 5 –––––––––––––––––––––––––––––––––");
|
||||
Serial.print("MessageID: ");
|
||||
Serial.println(_MessageID);
|
||||
Serial.print("Repeat: ");
|
||||
Serial.println(_Repeat);
|
||||
Serial.print("UserID: ");
|
||||
Serial.println(_UserID);
|
||||
Serial.print("IMONumber: ");
|
||||
Serial.println(_IMONumber);
|
||||
Serial.print("Callsign: ");
|
||||
Serial.println(_Callsign);
|
||||
Serial.print("VesselType: ");
|
||||
Serial.println(_VesselType);
|
||||
Serial.print("Name: ");
|
||||
Serial.println(_Name);
|
||||
Serial.print("Length: ");
|
||||
Serial.println(_Length);
|
||||
Serial.print("Beam: ");
|
||||
Serial.println(_Beam);
|
||||
Serial.print("PosRefStbd: ");
|
||||
Serial.println(_PosRefStbd);
|
||||
Serial.print("PosRefBow: ");
|
||||
Serial.println(_PosRefBow);
|
||||
Serial.print("ETAdate: ");
|
||||
Serial.println(_ETAdate);
|
||||
Serial.print("ETAtime: ");
|
||||
Serial.println(_ETAtime);
|
||||
Serial.print("Draught: ");
|
||||
Serial.println(_Draught);
|
||||
Serial.print("Destination: ");
|
||||
Serial.println(_Destination);
|
||||
Serial.print("GNSStype: ");
|
||||
Serial.println(_GNSStype);
|
||||
Serial.print("DTE: ");
|
||||
Serial.println(_DTE);
|
||||
Serial.println("––––––––––––––––––––––– Msg 5 –––––––––––––––––––––––––––––––––");
|
||||
#endif
|
||||
|
||||
if (SetAISClassAMessage5(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _IMONumber, _Callsign, _Name, _VesselType,
|
||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,
|
||||
_GNSStype, _DTE,_AISversion))
|
||||
_GNSStype, _DTE))
|
||||
{
|
||||
if (NMEA0183AISMsg.BuildMsg5Part1()){
|
||||
SendMessage(NMEA0183AISMsg);
|
||||
}
|
||||
if (NMEA0183AISMsg.BuildMsg5Part2()){
|
||||
SendMessage(NMEA0183AISMsg);
|
||||
}
|
||||
|
||||
SendMessage(NMEA0183AISMsg.BuildMsg5Part1(NMEA0183AISMsg));
|
||||
|
||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
||||
// Debug Print AIS-NMEA Message Type 5, Part 1
|
||||
char buf[7];
|
||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
||||
Serial.print(NMEA0183AISMsg.Sender());
|
||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
||||
{
|
||||
Serial.print(",");
|
||||
Serial.print(NMEA0183AISMsg.Field(i));
|
||||
}
|
||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
||||
Serial.print(buf);
|
||||
#endif
|
||||
|
||||
SendMessage(NMEA0183AISMsg.BuildMsg5Part2(NMEA0183AISMsg));
|
||||
|
||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
||||
// Print AIS-NMEA Message Type 5, Part 2
|
||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
||||
Serial.print(NMEA0183AISMsg.Sender());
|
||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
||||
{
|
||||
Serial.print(",");
|
||||
Serial.print(NMEA0183AISMsg.Field(i));
|
||||
}
|
||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
||||
Serial.print(buf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -840,21 +926,35 @@ private:
|
||||
tN2kAISUnit _Unit;
|
||||
bool _Display, _DSC, _Band, _Msg22, _State;
|
||||
tN2kAISMode _Mode;
|
||||
tN2kAISTransceiverInformation _AISTransceiverInformation;
|
||||
tN2kAISTransceiverInformation _AISTranceiverInformation;
|
||||
uint8_t _SID;
|
||||
|
||||
if (ParseN2kPGN129039(N2kMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
||||
_Seconds, _COG, _SOG, _AISTransceiverInformation, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State,_SID))
|
||||
_Seconds, _COG, _SOG, _AISTranceiverInformation, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State,_SID))
|
||||
{
|
||||
|
||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||
setTalkerChannel(NMEA0183AISMsg,_AISTransceiverInformation);
|
||||
|
||||
if (SetAISClassBMessage18(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
||||
_Seconds, _COG, _SOG, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State))
|
||||
{
|
||||
|
||||
SendMessage(NMEA0183AISMsg);
|
||||
|
||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
||||
// Debug Print AIS-NMEA
|
||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
||||
Serial.print(NMEA0183AISMsg.Sender());
|
||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
||||
{
|
||||
Serial.print(",");
|
||||
Serial.print(NMEA0183AISMsg.Field(i));
|
||||
}
|
||||
char buf[7];
|
||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
||||
Serial.print(buf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -876,10 +976,8 @@ private:
|
||||
{
|
||||
|
||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||
setTalkerChannel(NMEA0183AISMsg,_AISInfo);
|
||||
if (SetAISClassBMessage24PartA(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Name))
|
||||
{
|
||||
SendMessage(NMEA0183AISMsg);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -907,51 +1005,77 @@ private:
|
||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID,_AISInfo,_SID))
|
||||
{
|
||||
|
||||
//
|
||||
#ifdef SERIAL_PRINT_AIS_FIELDS
|
||||
// Debug Print N2k Values
|
||||
Serial.println("––––––––––––––––––––––– Msg 24 ––––––––––––––––––––––––––––––––");
|
||||
Serial.print("MessageID: ");
|
||||
Serial.println(_MessageID);
|
||||
Serial.print("Repeat: ");
|
||||
Serial.println(_Repeat);
|
||||
Serial.print("UserID: ");
|
||||
Serial.println(_UserID);
|
||||
Serial.print("VesselType: ");
|
||||
Serial.println(_VesselType);
|
||||
Serial.print("Vendor: ");
|
||||
Serial.println(_Vendor);
|
||||
Serial.print("Callsign: ");
|
||||
Serial.println(_Callsign);
|
||||
Serial.print("Length: ");
|
||||
Serial.println(_Length);
|
||||
Serial.print("Beam: ");
|
||||
Serial.println(_Beam);
|
||||
Serial.print("PosRefStbd: ");
|
||||
Serial.println(_PosRefStbd);
|
||||
Serial.print("PosRefBow: ");
|
||||
Serial.println(_PosRefBow);
|
||||
Serial.print("MothershipID: ");
|
||||
Serial.println(_MothershipID);
|
||||
Serial.println("––––––––––––––––––––––– Msg 24 ––––––––––––––––––––––––––––––––");
|
||||
#endif
|
||||
|
||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||
setTalkerChannel(NMEA0183AISMsg,_AISInfo);
|
||||
if (SetAISClassBMessage24PartB(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor, _Callsign,
|
||||
|
||||
if (SetAISClassBMessage24(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor, _Callsign,
|
||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID))
|
||||
{
|
||||
SendMessage(NMEA0183AISMsg);
|
||||
|
||||
SendMessage(NMEA0183AISMsg.BuildMsg24PartA(NMEA0183AISMsg));
|
||||
|
||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
||||
// Debug Print AIS-NMEA
|
||||
char buf[7];
|
||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
||||
Serial.print(NMEA0183AISMsg.Sender());
|
||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
||||
{
|
||||
Serial.print(",");
|
||||
Serial.print(NMEA0183AISMsg.Field(i));
|
||||
}
|
||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
||||
Serial.print(buf);
|
||||
#endif
|
||||
|
||||
SendMessage(NMEA0183AISMsg.BuildMsg24PartB(NMEA0183AISMsg));
|
||||
|
||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
||||
Serial.print(NMEA0183AISMsg.Sender());
|
||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
||||
{
|
||||
Serial.print(",");
|
||||
Serial.print(NMEA0183AISMsg.Field(i));
|
||||
}
|
||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
||||
Serial.print(buf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// PGN 129041 Aton
|
||||
void HandleAISMessage21(const tN2kMsg &N2kMsg)
|
||||
{
|
||||
tN2kAISAtoNReportData data;
|
||||
if (ParseN2kPGN129041(N2kMsg,data)){
|
||||
tNMEA0183AISMsg nmea0183Msg;
|
||||
setTalkerChannel(nmea0183Msg,data.AISTransceiverInformation);
|
||||
if (SetAISMessage21(
|
||||
nmea0183Msg,
|
||||
data.Repeat,
|
||||
data.UserID,
|
||||
data.Latitude,
|
||||
data.Longitude,
|
||||
data.Accuracy,
|
||||
data.RAIM,
|
||||
data.Seconds,
|
||||
data.Length,
|
||||
data.Beam,
|
||||
data.PositionReferenceStarboard,
|
||||
data.PositionReferenceTrueNorth,
|
||||
data.AtoNType,
|
||||
data.OffPositionIndicator,
|
||||
data.VirtualAtoNFlag,
|
||||
data.AssignedModeFlag,
|
||||
data.GNSSType,
|
||||
data.AtoNStatus,
|
||||
data.AtoNName
|
||||
)){
|
||||
SendMessage(nmea0183Msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSystemTime(const tN2kMsg &msg){
|
||||
unsigned char sid=-1;
|
||||
uint16_t DaysSince1970=N2kUInt16NA;
|
||||
@@ -1147,12 +1271,12 @@ private:
|
||||
double Level=N2kDoubleNA;
|
||||
double Capacity=N2kDoubleNA;
|
||||
if (ParseN2kPGN127505(N2kMsg,Instance,FluidType,Level,Capacity)) {
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(Level,XDRFLUID,FluidType,0,Instance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRFLUID,FluidType,0,Instance);
|
||||
if (updateDouble(&mapping,Level)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found fluidlevel mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(Level));
|
||||
}
|
||||
mapping=xdrMappings->getMapping(Capacity, XDRFLUID,FluidType,1,Instance);
|
||||
mapping=xdrMappings->getMapping(XDRFLUID,FluidType,1,Instance);
|
||||
if (updateDouble(&mapping,Capacity)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found fluid capacity mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(Capacity));
|
||||
@@ -1170,19 +1294,19 @@ private:
|
||||
double BatteryTemperature=N2kDoubleNA;
|
||||
if (ParseN2kPGN127508(N2kMsg,BatteryInstance,BatteryVoltage,BatteryCurrent,BatteryTemperature,SID)) {
|
||||
int i=0;
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(BatteryVoltage, XDRBAT,0,0,BatteryInstance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRBAT,0,0,BatteryInstance);
|
||||
if (updateDouble(&mapping,BatteryVoltage)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryVoltage mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(BatteryVoltage));
|
||||
i++;
|
||||
}
|
||||
mapping=xdrMappings->getMapping(BatteryCurrent,XDRBAT,0,1,BatteryInstance);
|
||||
mapping=xdrMappings->getMapping(XDRBAT,0,1,BatteryInstance);
|
||||
if (updateDouble(&mapping,BatteryCurrent)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryCurrent mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(BatteryCurrent));
|
||||
i++;
|
||||
}
|
||||
mapping=xdrMappings->getMapping(BatteryTemperature,XDRBAT,0,2,BatteryInstance);
|
||||
mapping=xdrMappings->getMapping(XDRBAT,0,2,BatteryInstance);
|
||||
if (updateDouble(&mapping,BatteryTemperature)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryTemperature mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(BatteryTemperature));
|
||||
@@ -1214,13 +1338,13 @@ private:
|
||||
SendMessage(NMEA0183Msg);
|
||||
}
|
||||
int i=0;
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(OutsideAmbientAirTemperature, XDRTEMP,N2kts_OutsideTemperature,0,0);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,N2kts_OutsideTemperature,0,0);
|
||||
if (updateDouble(&mapping,OutsideAmbientAirTemperature)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(OutsideAmbientAirTemperature));
|
||||
i++;
|
||||
}
|
||||
mapping=xdrMappings->getMapping(AtmosphericPressure,XDRPRESSURE,N2kps_Atmospheric,0,0);
|
||||
mapping=xdrMappings->getMapping(XDRPRESSURE,N2kps_Atmospheric,0,0);
|
||||
if (updateDouble(&mapping,AtmosphericPressure)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(AtmosphericPressure));
|
||||
@@ -1255,19 +1379,19 @@ private:
|
||||
SendMessage(NMEA0183Msg);
|
||||
}
|
||||
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(Temperature, XDRTEMP,TempSource,0,0);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,TempSource,0,0);
|
||||
if (updateDouble(&mapping,Temperature)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(Temperature));
|
||||
i++;
|
||||
}
|
||||
mapping=xdrMappings->getMapping(Humidity, XDRHUMIDITY,HumiditySource,0,0);
|
||||
mapping=xdrMappings->getMapping(XDRHUMIDITY,HumiditySource,0,0);
|
||||
if (updateDouble(&mapping,Humidity)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(Humidity));
|
||||
i++;
|
||||
}
|
||||
mapping=xdrMappings->getMapping(AtmosphericPressure, XDRPRESSURE,N2kps_Atmospheric,0,0);
|
||||
mapping=xdrMappings->getMapping(XDRPRESSURE,N2kps_Atmospheric,0,0);
|
||||
if (updateDouble(&mapping,AtmosphericPressure)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(AtmosphericPressure));
|
||||
@@ -1302,12 +1426,12 @@ private:
|
||||
SendMessage(NMEA0183Msg);
|
||||
}
|
||||
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(Temperature, XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
||||
if (updateDouble(&mapping,Temperature)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(Temperature));
|
||||
}
|
||||
mapping=xdrMappings->getMapping(setTemperature, XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
||||
mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
||||
if (updateDouble(&mapping,setTemperature)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(setTemperature));
|
||||
@@ -1325,13 +1449,12 @@ private:
|
||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||
return;
|
||||
}
|
||||
GwXDRFoundMapping mapping;
|
||||
mapping=xdrMappings->getMapping(ActualHumidity, XDRHUMIDITY,(int)HumiditySource,0,HumidityInstance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRHUMIDITY,(int)HumiditySource,0,HumidityInstance);
|
||||
if (updateDouble(&mapping,ActualHumidity)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(ActualHumidity));
|
||||
}
|
||||
mapping=xdrMappings->getMapping(SetHumidity, XDRHUMIDITY,(int)HumiditySource,1,HumidityInstance);
|
||||
mapping=xdrMappings->getMapping(XDRHUMIDITY,(int)HumiditySource,1,HumidityInstance);
|
||||
if (updateDouble(&mapping,SetHumidity)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(SetHumidity));
|
||||
@@ -1349,7 +1472,7 @@ private:
|
||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||
return;
|
||||
}
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(ActualPressure, XDRPRESSURE,(int)PressureSource,0,PressureInstance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRPRESSURE,(int)PressureSource,0,PressureInstance);
|
||||
if (! updateDouble(&mapping,ActualPressure)) return;
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(ActualPressure));
|
||||
@@ -1367,12 +1490,12 @@ private:
|
||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||
}
|
||||
for (int i=0;i<8;i++){
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(values[i], XDRENGINE,0,i,instance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRENGINE,0,i,instance);
|
||||
if (! updateDouble(&mapping,values[i])) continue;
|
||||
addToXdr(mapping.buildXdrEntry(values[i]));
|
||||
}
|
||||
for (int i=0;i< 2;i++){
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(ivalues[i],XDRENGINE,0,i+8,instance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRENGINE,0,i+8,instance);
|
||||
if (! updateDouble(&mapping,ivalues[i])) continue;
|
||||
addToXdr(mapping.buildXdrEntry((double)ivalues[i]));
|
||||
}
|
||||
@@ -1388,7 +1511,7 @@ private:
|
||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||
}
|
||||
for (int i=0;i<3;i++){
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(values[i], XDRATTITUDE,0,i,instance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRATTITUDE,0,i,instance);
|
||||
if (! updateDouble(&mapping,values[i])) continue;
|
||||
addToXdr(mapping.buildXdrEntry(values[i]));
|
||||
}
|
||||
@@ -1402,15 +1525,15 @@ private:
|
||||
speed,pressure,tilt)){
|
||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||
}
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(speed, XDRENGINE,0,10,instance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRENGINE,0,10,instance);
|
||||
if (updateDouble(&mapping,speed)){
|
||||
addToXdr(mapping.buildXdrEntry(speed));
|
||||
}
|
||||
mapping=xdrMappings->getMapping(pressure, XDRENGINE,0,11,instance);
|
||||
mapping=xdrMappings->getMapping(XDRENGINE,0,11,instance);
|
||||
if (updateDouble(&mapping,pressure)){
|
||||
addToXdr(mapping.buildXdrEntry(pressure));
|
||||
}
|
||||
mapping=xdrMappings->getMapping(tilt, XDRENGINE,0,12,instance);
|
||||
mapping=xdrMappings->getMapping(XDRENGINE,0,12,instance);
|
||||
if (updateDouble(&mapping,tilt)){
|
||||
addToXdr(mapping.buildXdrEntry((double)tilt));
|
||||
}
|
||||
@@ -1436,12 +1559,12 @@ private:
|
||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||
return;
|
||||
}
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(Temperature, XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
||||
if (updateDouble(&mapping,Temperature)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(Temperature));
|
||||
}
|
||||
mapping=xdrMappings->getMapping(setTemperature, XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
||||
mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
||||
if (updateDouble(&mapping,setTemperature)){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||
addToXdr(mapping.buildXdrEntry(setTemperature));
|
||||
@@ -1491,7 +1614,6 @@ private:
|
||||
converters.registerConverter(129794UL, &N2kToNMEA0183Functions::HandleAISClassAMessage5); // AIS Class A Ship Static and Voyage related data, Message Type 5
|
||||
converters.registerConverter(129809UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24A); // AIS Class B "CS" Static Data Report, Part A
|
||||
converters.registerConverter(129810UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24B); // AIS Class B "CS" Static Data Report, Part B
|
||||
converters.registerConverter(129041UL, &N2kToNMEA0183Functions::HandleAISMessage21); // AIS Aton
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include "NMEA0183AISMessages.h"
|
||||
#include <NMEA0183AISMessages.h>
|
||||
#include <N2kTypes.h>
|
||||
#include <N2kMsg.h>
|
||||
#include <string.h>
|
||||
@@ -34,7 +34,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <math.h>
|
||||
#include "NMEA0183AISMsg.h"
|
||||
#include <NMEA0183AISMsg.h>
|
||||
|
||||
const double pi=3.1415926535897932384626433832795;
|
||||
const double kmhToms=1000.0/3600.0;
|
||||
@@ -47,15 +47,17 @@ const double nmTom=1.852*1000;
|
||||
const double mToFathoms=0.546806649;
|
||||
const double mToFeet=3.2808398950131;
|
||||
const double radsToDegMin = 60 * 360.0 / (2 * pi); // [rad/s -> degree/minute]
|
||||
const char Prefix='!';
|
||||
|
||||
std::vector<ship *> vships;
|
||||
|
||||
int numShips(){return vships.size();}
|
||||
// ************************ Helper for AIS ***********************************
|
||||
static bool AddMessageType(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType);
|
||||
static bool AddRepeat(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat);
|
||||
static bool AddUserID(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t UserID);
|
||||
static bool AddIMONumber(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t &IMONumber);
|
||||
static bool AddText(tNMEA0183AISMsg &NMEA0183AISMsg, char *FieldVal, uint8_t length);
|
||||
//static bool AddVesselType(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t VesselType);
|
||||
static bool AddDimensions(tNMEA0183AISMsg &NMEA0183AISMsg, double Length, double Beam, double PosRefStbd, double PosRefBow);
|
||||
static bool AddNavStatus(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t &NavStatus);
|
||||
static bool AddROT(tNMEA0183AISMsg &NMEA0183AISMsg, double &rot);
|
||||
@@ -79,8 +81,8 @@ static bool AddETADateTime(tNMEA0183AISMsg &NMEA0183AISMsg, uint16_t &ETAdate, d
|
||||
//
|
||||
// Got values from: ParseN2kPGN129038()
|
||||
bool SetAISClassABMessage1( tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType, uint8_t Repeat,
|
||||
uint32_t UserID, double Latitude, double Longitude, bool Accuracy, bool RAIM, uint8_t Seconds,
|
||||
double COG, double SOG, double Heading, double ROT, uint8_t NavStatus ) {
|
||||
uint32_t UserID, double Latitude, double Longitude, bool Accuracy, bool RAIM, uint8_t Seconds,
|
||||
double COG, double SOG, double Heading, double ROT, uint8_t NavStatus ) {
|
||||
|
||||
NMEA0183AISMsg.ClearAIS();
|
||||
if ( !AddMessageType(NMEA0183AISMsg, MessageType) ) return false; // 0 - 5 | 6 Message Type -> Constant: 1
|
||||
@@ -89,7 +91,7 @@ bool SetAISClassABMessage1( tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType
|
||||
if ( !AddNavStatus(NMEA0183AISMsg, NavStatus) ) return false; // 38-41 | 4 Navigational Status e.g.: "Under way sailing"
|
||||
if ( !AddROT(NMEA0183AISMsg, ROT) ) return false; // 42-49 | 8 Rate of Turn (ROT)
|
||||
if ( !AddSOG(NMEA0183AISMsg, SOG) ) return false; // 50-59 | 10 [m/s -> kts] SOG with one digit x10, 1023 = N/A
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy) ) return false;// 60 | 1 GPS Accuracy 1 oder 0, Default 0
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy, 1) ) return false;// 60 | 1 GPS Accuracy 1 oder 0, Default 0
|
||||
if ( !AddLongitude(NMEA0183AISMsg, Longitude) ) return false; // 61-88 | 28 Longitude in Minutes / 10000
|
||||
if ( !AddLatitude(NMEA0183AISMsg, Latitude) ) return false; // 89-115 | 27 Latitude in Minutes / 10000
|
||||
if ( !AddCOG(NMEA0183AISMsg, COG) ) return false; // 116-127 | 12 Course over ground will be 3600 (0xE10) if that data is not available.
|
||||
@@ -97,12 +99,17 @@ bool SetAISClassABMessage1( tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType
|
||||
if ( !AddSeconds(NMEA0183AISMsg, Seconds) ) return false; // 137-142 | 6 Seconds in UTC timestamp)
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 143-144 | 2 Maneuver Indicator: 0 (default) 1, 2 (not delivered within this PGN)
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 3) ) return false; // 145-147 | 3 Spare
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM) ) return false; // 148-148 | 1 RAIM flag 0 = RAIM not in use (default), 1 = RAIM in use
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM, 1) ) return false; // 148-148 | 1 RAIM flag 0 = RAIM not in use (default), 1 = RAIM in use
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 19) ) return false; // 149-167 | 19 Radio Status (-> 0 NOT SENT WITH THIS PGN!!!!!)
|
||||
if ( !NMEA0183AISMsg.InitAis()) return false;
|
||||
int padBits=0;
|
||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||
|
||||
if ( !NMEA0183AISMsg.Init("VDM","AI", Prefix) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
||||
if ( !NMEA0183AISMsg.AddEmptyField() ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("A") ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayload() ) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("0") ) return false; // Message 1,2,3 has always Zero Padding
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -114,16 +121,14 @@ bool SetAISClassAMessage5(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
||||
uint32_t UserID, uint32_t IMONumber, char *Callsign, char *Name,
|
||||
uint8_t VesselType, double Length, double Beam, double PosRefStbd,
|
||||
double PosRefBow, uint16_t ETAdate, double ETAtime, double Draught,
|
||||
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE,
|
||||
tN2kAISVersion AISversion) {
|
||||
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE ) {
|
||||
|
||||
// AIS Type 5 Message
|
||||
NMEA0183AISMsg.ClearAIS();
|
||||
if ( !AddMessageType(NMEA0183AISMsg, 5) ) return false; // 0 - 5 | 6 Message Type -> Constant: 5
|
||||
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin((uint32_t)AISversion, 2) )
|
||||
return false; // 38 - 39 | 2 AIS Version -> 0 oder 1 NOT DERIVED FROM N2k, Always 1!!!!
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(1, 2) ) return false; // 38 - 39 | 2 AIS Version -> 0 oder 1 NOT DERIVED FROM N2k, Always 1!!!!
|
||||
if ( !AddIMONumber(NMEA0183AISMsg, IMONumber) ) return false; // 40 - 69 | 30 IMO Number unisgned
|
||||
if ( !AddText(NMEA0183AISMsg, Callsign, 42) ) return false; // 70 - 111 | 42 Call Sign WDE4178 -> 7 6-bit characters -> Ascii lt. Table)
|
||||
if ( !AddText(NMEA0183AISMsg, Name, 120) ) return false; // 112-231 | 120 Vessel Name POINT FERMIN -> 20 6-bit characters -> Ascii lt. Table
|
||||
@@ -141,17 +146,15 @@ bool SetAISClassAMessage5(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
||||
|
||||
// ****************************************************************************
|
||||
// AIS position report (class B 129039) -> Type 18: Standard Class B CS Position Report
|
||||
// PGN129039
|
||||
// ParseN2kAISClassBPosition(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID,
|
||||
// ParseN2kPGN129039(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID,
|
||||
// double &Latitude, double &Longitude, bool &Accuracy, bool &RAIM,
|
||||
// uint8_t &Seconds, double &COG, double &SOG, tN2kAISTransceiverInformation &AISTransceiverInformation,
|
||||
// double &Heading, tN2kAISUnit &Unit, bool &Display, bool &DSC, bool &Band, bool &Msg22, tN2kAISMode &Mode,
|
||||
// bool &State)
|
||||
// uint8_t &Seconds, double &COG, double &SOG, double &Heading, tN2kAISUnit &Unit,
|
||||
// bool &Display, bool &DSC, bool &Band, bool &Msg22, tN2kAISMode &Mode, bool &State)
|
||||
// VDM, VDO (AIS VHF Data-link message 18)
|
||||
bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat, uint32_t UserID,
|
||||
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||
uint8_t Seconds, double COG, double SOG, double Heading, tN2kAISUnit Unit,
|
||||
bool Display, bool DSC, bool Band, bool Msg22, bool Mode, bool State) {
|
||||
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||
uint8_t Seconds, double COG, double SOG, double Heading, tN2kAISUnit Unit,
|
||||
bool Display, bool DSC, bool Band, bool Msg22, bool Mode, bool State) {
|
||||
//
|
||||
NMEA0183AISMsg.ClearAIS();
|
||||
if ( !AddMessageType(NMEA0183AISMsg, MessageID) ) return false; // 0 - 5 | 6 Message Type -> Constant: 18
|
||||
@@ -159,7 +162,7 @@ bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 8) ) return false; // 38-45 | 8 Regional Reserved
|
||||
if ( !AddSOG(NMEA0183AISMsg, SOG) ) return false; // 46-55 | 10 [m/s -> kts] SOG with one digit x10, 1023 = N/A
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy)) return false; // 56 | 1 GPS Accuracy 1 oder 0, Default 0
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy, 1)) return false; // 56 | 1 GPS Accuracy 1 oder 0, Default 0
|
||||
if ( !AddLongitude(NMEA0183AISMsg, Longitude) ) return false; // 57-84 | 28 Longitude in Minutes / 10000
|
||||
if ( !AddLatitude(NMEA0183AISMsg, Latitude) ) return false; // 85-111 | 27 Latitude in Minutes / 10000
|
||||
if ( !AddCOG(NMEA0183AISMsg, COG) ) return false; // 112-123 | 12 Course over ground will be 3600 (0xE10) if that data is not available.
|
||||
@@ -168,16 +171,20 @@ bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 139-140 | 2 Regional Reserved
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(Unit, 1) ) return false; // 141 | 1 0=Class B SOTDMA unit 1=Class B CS (Carrier Sense) unit
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(Display, 1) ) return false; // 142 | 1 0=No visual display, 1=Has display, (Probably not reliable).
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(DSC) ) return false; // 143 | 1 If 1, unit is attached to a VHF voice radio with DSC capability.
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Band) ) return false; // 144 | 1 If this flag is 1, the unit can use any part of the marine channel.
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Msg22)) return false; // 145 | 1 If 1, unit can accept a channel assignment via Message Type 22.
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Mode) ) return false; // 146 | 1 Assigned-mode flag: 0 = autonomous mode (default), 1 = assigned mode
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM) ) return false; // 147 | 1 as for Message Type 1,2,3
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(DSC, 1) ) return false; // 143 | 1 If 1, unit is attached to a VHF voice radio with DSC capability.
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Band, 1) ) return false; // 144 | 1 If this flag is 1, the unit can use any part of the marine channel.
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Msg22, 1) ) return false; // 145 | 1 If 1, unit can accept a channel assignment via Message Type 22.
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Mode, 1) ) return false; // 146 | 1 Assigned-mode flag: 0 = autonomous mode (default), 1 = assigned mode
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM, 1) ) return false; // 147 | 1 as for Message Type 1,2,3
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 20) ) return false; // 148-167 | 20 Radio Status not in PGN 129039
|
||||
if ( !NMEA0183AISMsg.InitAis()) return false;
|
||||
int padBits=0;
|
||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||
|
||||
if ( !NMEA0183AISMsg.Init("VDM","AI", Prefix) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
||||
if ( !NMEA0183AISMsg.AddEmptyField() ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("B") ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayload() ) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddStrField("0") ) return false; // Message 18, has always Zero Padding
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -202,7 +209,7 @@ bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
||||
//
|
||||
// PGN 129809 AIS Class B "CS" Static Data Report, Part A -> AIS VHF Data-link message 24
|
||||
// PGN 129810 AIS Class B "CS" Static Data Report, Part B -> AIS VHF Data-link message 24
|
||||
// ParseN2kPGN129809 (const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID, char *Name) -> store to vector
|
||||
// ParseN2kPGN129809 (const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID, char *Name) -> store to vector
|
||||
// ParseN2kPGN129810(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID,
|
||||
// uint8_t &VesselType, char *Vendor, char *Callsign, double &Length, double &Beam,
|
||||
// double &PosRefStbd, double &PosRefBow, uint32_t &MothershipID);
|
||||
@@ -210,28 +217,41 @@ bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
||||
// Part A: MessageID, Repeat, UserID, ShipName -> store in vector to call on Part B arrivals!!!
|
||||
// Part B: MessageID, Repeat, UserID, VesselType (5), Callsign (5), Length & Beam, PosRefBow,.. (5)
|
||||
bool SetAISClassBMessage24PartA(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat, uint32_t UserID, char *Name) {
|
||||
// AIS Type 24 Message
|
||||
NMEA0183AISMsg.ClearAIS();
|
||||
// Common for PART A AND Part B Bit 0 - 39 / len 40
|
||||
if ( !AddMessageType(NMEA0183AISMsg, 24) ) return false; // 0 - 5 | 6 Message Type -> Constant: 24
|
||||
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 38-39 | 2 Part Number 0-1 ->
|
||||
// Part A: 40 + 128 = len 168
|
||||
if ( !AddText(NMEA0183AISMsg, Name, 120) ) return false; // 40-159 | 120 Vessel Name 20 6-bit characters -> Ascii Table
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 8) ) return false; // 160-167 | 8 Spare
|
||||
if ( !NMEA0183AISMsg.InitAis() ) return false;
|
||||
int padBits=0;
|
||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < vships.size(); i++) {
|
||||
if ( vships[i]->_userID == UserID ) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! found ) {
|
||||
std::string nm;
|
||||
nm+= Name;
|
||||
vships.push_back(new ship(UserID, nm));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ***************************************************************************************************************
|
||||
bool SetAISClassBMessage24PartB(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
||||
bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
||||
uint32_t UserID, uint8_t VesselType, char *VendorID, char *Callsign,
|
||||
double Length, double Beam, double PosRefStbd, double PosRefBow, uint32_t MothershipID ) {
|
||||
|
||||
uint8_t PartNr = 0; // Identifier for the message part number; always 0 for Part A
|
||||
char *ShipName = (char*)" "; // get from vector to look up for sent Messages Part A
|
||||
|
||||
uint8_t i;
|
||||
for ( i = 0; i < vships.size(); i++) {
|
||||
if ( vships[i]->_userID == UserID ) {
|
||||
ShipName = const_cast<char*>( vships[i]->_shipName.c_str() );
|
||||
}
|
||||
}
|
||||
if ( i > MAX_SHIP_IN_VECTOR ) {
|
||||
std::vector<ship *>::iterator it=vships.begin();
|
||||
delete *it;
|
||||
vships.erase(it);
|
||||
}
|
||||
|
||||
// AIS Type 24 Message
|
||||
NMEA0183AISMsg.ClearAIS();
|
||||
@@ -239,7 +259,11 @@ bool SetAISClassBMessage24PartB(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Messag
|
||||
if ( !AddMessageType(NMEA0183AISMsg, 24) ) return false; // 0 - 5 | 6 Message Type -> Constant: 24
|
||||
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(1, 2) ) return false; // 38-39 | 2 Part Number 0-1 ->
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(PartNr, 2) ) return false; // 38-39 | 2 Part Number 0-1 ->
|
||||
|
||||
// Part A: 40 + 128 = len 168
|
||||
if ( !AddText(NMEA0183AISMsg, ShipName, 120) ) return false; // 40-159 | 120 Vessel Name 20 6-bit characters -> Ascii Table
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 8) ) return false; // 160-167 | 8 Spare
|
||||
|
||||
// https://www.navcen.uscg.gov/?pageName=AISMessagesB
|
||||
// PART B: 40 + 128 = len 168
|
||||
@@ -248,59 +272,6 @@ bool SetAISClassBMessage24PartB(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Messag
|
||||
if ( !AddText(NMEA0183AISMsg, Callsign, 42) ) return false; // 218-259 | 90-131 | 42 Call Sign WDE4178 -> 7 6-bit characters, as in Msg Type 5
|
||||
if ( !AddDimensions(NMEA0183AISMsg, Length, Beam, PosRefStbd, PosRefBow) ) return false; // 260-289 | 132-161 | 30 Dimensions
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 6) ) return false; // 290-295 | 162-167 | 6 Spare
|
||||
if ( !NMEA0183AISMsg.InitAis() ) return false;
|
||||
int padBits=0;
|
||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// AIS ATON report (129041) -> Type 21: Position and status report for aids-to-navigation
|
||||
// PGN129041
|
||||
|
||||
bool SetAISMessage21(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat, uint32_t UserID,
|
||||
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||
uint8_t Seconds, double Length, double Beam, double PositionReferenceStarboard,
|
||||
double PositionReferenceTrueNord, tN2kAISAtoNType Type, bool OffPositionIndicator,
|
||||
bool VirtualAtoNFlag, bool AssignedModeFlag, tN2kGNSStype GNSSType, uint8_t AtoNStatus,
|
||||
char * atonName ) {
|
||||
//
|
||||
NMEA0183AISMsg.ClearAIS();
|
||||
if ( !AddMessageType(NMEA0183AISMsg, 21) ) return false; // 0 - 5 | 6 Message Type -> Constant: 18
|
||||
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||
if ( ! NMEA0183AISMsg.AddIntToPayloadBin(Type,5)) return false; // | 5 aid type
|
||||
//the name must be split:
|
||||
//if it's > 120 bits the rest goes to the last parameter
|
||||
if ( !NMEA0183AISMsg.AddEncodedCharToPayloadBin(atonName,120))
|
||||
return false; // | 120 name
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy) ) return false; // | 1 accuracy
|
||||
if ( !AddLongitude(NMEA0183AISMsg,Longitude)) return false; // | 28 lon
|
||||
if ( !AddLatitude(NMEA0183AISMsg,Latitude)) return false; // | 27 lat
|
||||
if ( !AddDimensions(NMEA0183AISMsg, Length, Beam,
|
||||
PositionReferenceStarboard, PositionReferenceTrueNord)) return false; // | 30 dim
|
||||
if ( !AddEPFDFixType(NMEA0183AISMsg,GNSSType)) return false; // | 4 fix type
|
||||
if ( !AddSeconds(NMEA0183AISMsg,Seconds)) return false; // | 6 second
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(OffPositionIndicator))
|
||||
return false; // | 1 off
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0,8)) return false; // | 8 reserverd
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM)) return false; // | 1 raim
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(VirtualAtoNFlag))
|
||||
return false; // | 1 virt
|
||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(AssignedModeFlag))
|
||||
return false; // | 1 assigned
|
||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0,1)) return false; // | 1 spare
|
||||
size_t l=strlen(atonName);
|
||||
if (l >=20){
|
||||
uint8_t bitlen=(l-20)*6;
|
||||
if (bitlen > 88) bitlen=88;
|
||||
if ( !NMEA0183AISMsg.AddEncodedCharToPayloadBin(atonName+20,bitlen)) return false; // | name
|
||||
}
|
||||
if ( !NMEA0183AISMsg.InitAis() ) return false;
|
||||
int padBits=0;
|
||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayload(padBits) ) ) return false;
|
||||
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -354,6 +325,7 @@ bool AddIMONumber(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t &IMONumber) {
|
||||
// 120bit Name or Destination
|
||||
bool AddText(tNMEA0183AISMsg &NMEA0183AISMsg, char *FieldVal, uint8_t length) {
|
||||
uint8_t len = length/6;
|
||||
|
||||
if ( strlen(FieldVal) > len ) FieldVal[len] = 0;
|
||||
if ( !NMEA0183AISMsg.AddEncodedCharToPayloadBin(FieldVal, length) ) return false;
|
||||
return true;
|
||||
@@ -375,26 +347,29 @@ bool AddDimensions(tNMEA0183AISMsg &NMEA0183AISMsg, double Length, double Beam,
|
||||
uint16_t _PosRefStbd = 0;
|
||||
uint16_t _PosRefPort = 0;
|
||||
|
||||
if ( PosRefBow >= 0.0 && PosRefBow <= 511.0 ) {
|
||||
_PosRefBow = ceil(PosRefBow);
|
||||
if (PosRefBow < 0) PosRefBow=0; //could be N2kIsNA
|
||||
if ( PosRefBow <= 511.0 ) {
|
||||
_PosRefBow = round(PosRefBow);
|
||||
} else {
|
||||
_PosRefBow = 511;
|
||||
}
|
||||
|
||||
if ( PosRefStbd >= 0.0 && PosRefStbd <= 63.0 ) {
|
||||
_PosRefStbd = ceil(PosRefStbd);
|
||||
if (PosRefStbd < 0 ) PosRefStbd=0; //could be N2kIsNA
|
||||
if (PosRefStbd <= 63.0 ) {
|
||||
_PosRefStbd = round(PosRefStbd);
|
||||
} else {
|
||||
_PosRefStbd = 63;
|
||||
}
|
||||
|
||||
if ( !N2kIsNA(Length) ) {
|
||||
_PosRefStern = ceil( Length ) - _PosRefBow;
|
||||
if ( _PosRefStern < 0 ) _PosRefStern = 0;
|
||||
if (Length >= PosRefBow){
|
||||
_PosRefStern=round(Length - PosRefBow);
|
||||
}
|
||||
if ( _PosRefStern > 511 ) _PosRefStern = 511;
|
||||
}
|
||||
if ( !N2kIsNA(Beam) ) {
|
||||
_PosRefPort = ceil( Beam ) - _PosRefStbd;
|
||||
if ( _PosRefPort < 0 ) _PosRefPort = 0;
|
||||
if (Beam >= PosRefStbd){
|
||||
_PosRefPort = round( Beam - PosRefStbd);
|
||||
}
|
||||
if ( _PosRefPort > 63 ) _PosRefPort = 63;
|
||||
}
|
||||
|
||||
@@ -597,5 +572,3 @@ bool AddETADateTime(tNMEA0183AISMsg &NMEA0183AISMsg, uint16_t &ETAdate, double &
|
||||
if ( ! NMEA0183AISMsg.AddIntToPayloadBin(minute, 6) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,21 +27,29 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#ifndef _tNMEA0183AISMessages_H_
|
||||
#define _tNMEA0183AISMessages_H_
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <N2kTypes.h>
|
||||
#include "NMEA0183AISMsg.h"
|
||||
#include <NMEA0183AISMsg.h>
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#define MAX_SHIP_IN_VECTOR 200
|
||||
class ship {
|
||||
public:
|
||||
uint32_t _userID;
|
||||
std::string _shipName;
|
||||
|
||||
ship(uint32_t UserID, std::string ShipName) : _userID(UserID), _shipName(ShipName) {}
|
||||
};
|
||||
|
||||
|
||||
// Types 1, 2 and 3: Position Report Class A or B
|
||||
bool SetAISClassABMessage1(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType, uint8_t Repeat,
|
||||
uint32_t UserID, double Latitude, double Longitude, bool Accuracy, bool RAIM, uint8_t Seconds,
|
||||
double COG, double SOG, double Heading, double ROT, uint8_t NavStatus);
|
||||
uint32_t UserID, double Latitude, double Longitude, bool Accuracy, bool RAIM, uint8_t Seconds,
|
||||
double COG, double SOG, double Heading, double ROT, uint8_t NavStatus);
|
||||
|
||||
//*****************************************************************************
|
||||
// AIS Class A Static and Voyage Related Data Message Type 5
|
||||
@@ -49,15 +57,14 @@ bool SetAISClassAMessage5(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, ui
|
||||
uint32_t UserID, uint32_t IMONumber, char *Callsign, char *Name,
|
||||
uint8_t VesselType, double Length, double Beam, double PosRefStbd,
|
||||
double PosRefBow, uint16_t ETAdate, double ETAtime, double Draught,
|
||||
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE,
|
||||
tN2kAISVersion AISversion);
|
||||
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE );
|
||||
|
||||
//*****************************************************************************
|
||||
// AIS position report (class B 129039) -> Standard Class B CS Position Report Message Type 18 Part B
|
||||
bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat, uint32_t UserID,
|
||||
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||
uint8_t Seconds, double COG, double SOG, double Heading, tN2kAISUnit Unit,
|
||||
bool Display, bool DSC, bool Band, bool Msg22, bool Mode, bool State);
|
||||
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||
uint8_t Seconds, double COG, double SOG, double Heading, tN2kAISUnit Unit,
|
||||
bool Display, bool DSC, bool Band, bool Msg22, bool Mode, bool State);
|
||||
|
||||
//*****************************************************************************
|
||||
// Static Data Report Class B, Message Type 24
|
||||
@@ -66,19 +73,11 @@ bool SetAISClassBMessage24PartA(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Message
|
||||
|
||||
//*****************************************************************************
|
||||
// Static Data Report Class B, Message Type 24
|
||||
bool SetAISClassBMessage24PartB(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
||||
bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
||||
uint32_t UserID, uint8_t VesselType, char *VendorID, char *Callsign,
|
||||
double Length, double Beam, double PosRefStbd, double PosRefBow, uint32_t MothershipID );
|
||||
|
||||
//*****************************************************************************
|
||||
// Aton class 21
|
||||
bool SetAISMessage21(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat, uint32_t UserID,
|
||||
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||
uint8_t Seconds, double Length, double Beam, double PositionReferenceStarboard,
|
||||
double PositionReferenceTrueNord, tN2kAISAtoNType Type, bool OffPositionIndicator,
|
||||
bool VirtualAtoNFlag, bool AssignedModeFlag, tN2kGNSStype GNSSType, uint8_t AtoNStatus,
|
||||
char * atonName );
|
||||
|
||||
int numShips();
|
||||
inline int32_t aRoundToInt(double x) {
|
||||
return x >= 0
|
||||
? (int32_t) floor(x + 0.5)
|
||||
|
||||
@@ -25,7 +25,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "NMEA0183AISMsg.h"
|
||||
#include <NMEA0183Msg.h>
|
||||
//#include <Arduino.h>
|
||||
#include <Arduino.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -43,37 +43,52 @@ tNMEA0183AISMsg::tNMEA0183AISMsg() {
|
||||
//*****************************************************************************
|
||||
void tNMEA0183AISMsg::ClearAIS() {
|
||||
|
||||
PayloadBin[0]=0;
|
||||
Payload[0]=0;
|
||||
PayloadBin.reset();
|
||||
iAddPldBin=0;
|
||||
iAddPld=0;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Add 6bit with no data.
|
||||
bool tNMEA0183AISMsg::AddEmptyFieldToPayloadBin(uint8_t iBits) {
|
||||
|
||||
if ( (iAddPldBin + iBits * 6) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
||||
|
||||
for (uint8_t i=0;i<iBits;i++) {
|
||||
strncpy(PayloadBin+iAddPldBin, EmptyAISField, 6);
|
||||
iAddPldBin+=6;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
bool tNMEA0183AISMsg::AddIntToPayloadBin(int32_t ival, uint16_t countBits) {
|
||||
|
||||
if ( (iAddPldBin + countBits ) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
||||
|
||||
bset = ival;
|
||||
AISBitSet bset(ival);
|
||||
|
||||
PayloadBin[iAddPldBin]=0;
|
||||
uint16_t iAdd=iAddPldBin;
|
||||
|
||||
for(int i = countBits-1; i >= 0 ; i--) {
|
||||
PayloadBin[iAdd]=bset [i];
|
||||
PayloadBin[iAdd] = bset[i]?'1':'0';
|
||||
iAdd++;
|
||||
}
|
||||
|
||||
iAddPldBin += countBits;
|
||||
PayloadBin[iAddPldBin]=0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//****************************************************************************
|
||||
bool tNMEA0183AISMsg::AddBoolToPayloadBin(bool &bval) {
|
||||
if ( (iAddPldBin + 1 ) >= AIS_BIN_MAX_LEN ) return false;
|
||||
PayloadBin[iAddPldBin]=bval;
|
||||
iAddPldBin++;
|
||||
// ****************************************************************************
|
||||
bool tNMEA0183AISMsg::AddBoolToPayloadBin(bool &bval, uint8_t size) {
|
||||
int8_t iTemp;
|
||||
(bval == true)? iTemp = 1 : iTemp = 0;
|
||||
if ( ! AddIntToPayloadBin(iTemp, size) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -84,11 +99,13 @@ bool tNMEA0183AISMsg::AddEncodedCharToPayloadBin(char *sval, size_t countBits) {
|
||||
|
||||
if ( (iAddPldBin + countBits ) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
||||
|
||||
const char * ptr;
|
||||
PayloadBin[iAddPldBin]=0;
|
||||
std::bitset<6> bs;
|
||||
char * ptr;
|
||||
size_t len = strlen(sval); // e.g.: should be 7 for Callsign
|
||||
if ( len * 6 > countBits ) len = countBits / 6;
|
||||
|
||||
for (size_t i = 0; i<len; i++) {
|
||||
for (int i = 0; i<len; i++) {
|
||||
|
||||
ptr = strchr(AsciiChar, sval[i]);
|
||||
if ( ptr ) {
|
||||
@@ -100,44 +117,37 @@ bool tNMEA0183AISMsg::AddEncodedCharToPayloadBin(char *sval, size_t countBits) {
|
||||
AddIntToPayloadBin(0, 6);
|
||||
}
|
||||
}
|
||||
|
||||
PayloadBin[iAddPldBin+1]=0;
|
||||
|
||||
// fill up with "@", also covers empty sval
|
||||
if ( len * 6 < countBits ) {
|
||||
for (size_t i=0;i<(countBits/6-len);i++) {
|
||||
for (int i=0;i<(countBits/6-len);i++) {
|
||||
AddIntToPayloadBin(0, 6);
|
||||
}
|
||||
}
|
||||
PayloadBin[iAddPldBin]=0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
template <unsigned int S>
|
||||
int tNMEA0183AISMsg::ConvertBinaryAISPayloadBinToAscii(std::bitset<S> &src,uint16_t maxSize,uint16_t bitSize,uint16_t stoffset) {
|
||||
Payload[0]='\0';
|
||||
uint16_t slen=maxSize;
|
||||
if (stoffset >= slen) return 0;
|
||||
slen-=stoffset;
|
||||
uint16_t bitLen=bitSize > 0?bitSize:slen;
|
||||
uint16_t len= bitLen / 6;
|
||||
if ((len * 6) < bitLen) len+=1;
|
||||
uint16_t padBits=0;
|
||||
// *****************************************************************************
|
||||
bool tNMEA0183AISMsg::ConvertBinaryAISPayloadBinToAscii(const char *payloadbin) {
|
||||
uint16_t len;
|
||||
|
||||
len = strlen( payloadbin ) / 6; // 28
|
||||
uint32_t offset;
|
||||
std::bitset<6> s;
|
||||
char s[7];
|
||||
uint8_t dec;
|
||||
int i;
|
||||
for ( i=0; i<len; i++ ) {
|
||||
offset = i * 6;
|
||||
int k = 5;
|
||||
for (uint32_t j=offset; j<offset+6; j++ ) {
|
||||
if (j < slen){
|
||||
s[k] = src[stoffset+j];
|
||||
}
|
||||
else{
|
||||
s[k] = 0;
|
||||
padBits++;
|
||||
}
|
||||
k--;
|
||||
int k = 0;
|
||||
for (int j=offset; j<offset+6; j++ ) {
|
||||
s[k] = payloadbin[j];
|
||||
k++;
|
||||
}
|
||||
dec = s.to_ulong();
|
||||
s[k]=0;
|
||||
dec = strtoull (s, NULL, 2); //binToDec
|
||||
|
||||
if (dec < 40 ) dec += 48;
|
||||
else dec += 56;
|
||||
@@ -146,56 +156,142 @@ int tNMEA0183AISMsg::ConvertBinaryAISPayloadBinToAscii(std::bitset<S> &src,uint1
|
||||
}
|
||||
Payload[i]=0;
|
||||
|
||||
return padBits;
|
||||
}
|
||||
|
||||
void tNMEA0183AISMsg::SetChannelAndTalker(bool channelA,bool own){
|
||||
channel[0]=channelA?'A':'B';
|
||||
strcpy(talker,own?"VDO":"VDM");
|
||||
return true;
|
||||
}
|
||||
|
||||
//********************** BUILD 2-parted AIS Sentences ************************
|
||||
bool tNMEA0183AISMsg::InitAis(int max,int number,int sequence){
|
||||
if ( !Init(talker,"AI", '!') ) return false;
|
||||
if ( !AddUInt32Field(max) ) return false;
|
||||
if ( !AddUInt32Field(number) ) return false;
|
||||
if (sequence >= 0){
|
||||
if ( !AddUInt32Field(sequence) ) return false;
|
||||
}
|
||||
else{
|
||||
if ( !AddEmptyField() ) return false;
|
||||
}
|
||||
if ( !AddStrField(channel) ) return false;
|
||||
return true;
|
||||
}
|
||||
bool tNMEA0183AISMsg::BuildMsg5Part1() {
|
||||
if ( iAddPldBin != 424 ) return false;
|
||||
InitAis(2,1,5);
|
||||
int padBits=0;
|
||||
AddStrField( GetPayload(padBits,0,336));
|
||||
AddUInt32Field(padBits);
|
||||
return true;
|
||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg5Part1(tNMEA0183AISMsg &AISMsg) {
|
||||
|
||||
Init("VDM", "AI", '!');
|
||||
AddStrField("2");
|
||||
AddStrField("1");
|
||||
AddStrField("5");
|
||||
AddStrField("A");
|
||||
AddStrField( GetPayloadType5_Part1() );
|
||||
AddStrField("0");
|
||||
|
||||
return AISMsg;
|
||||
}
|
||||
|
||||
bool tNMEA0183AISMsg::BuildMsg5Part2() {
|
||||
if ( iAddPldBin != 424 ) return false;
|
||||
InitAis(2,2,5);
|
||||
int padBits=0;
|
||||
AddStrField( GetPayload(padBits,336,88) );
|
||||
AddUInt32Field(padBits);
|
||||
return true;
|
||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg5Part2(tNMEA0183AISMsg &AISMsg) {
|
||||
|
||||
Init("VDM", "AI", '!');
|
||||
AddStrField("2");
|
||||
AddStrField("2");
|
||||
AddStrField("5");
|
||||
AddStrField("A");
|
||||
AddStrField( GetPayloadType5_Part2() );
|
||||
AddStrField("2"); // Message 5, Part 2 has always 2 Padding Zeros
|
||||
|
||||
return AISMsg;
|
||||
}
|
||||
|
||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg24PartA(tNMEA0183AISMsg &AISMsg) {
|
||||
|
||||
Init("VDM", "AI", '!');
|
||||
AddStrField("1");
|
||||
AddStrField("1");
|
||||
AddEmptyField();
|
||||
AddStrField("A");
|
||||
AddStrField( GetPayloadType24_PartA() );
|
||||
AddStrField("0");
|
||||
|
||||
return AISMsg;
|
||||
}
|
||||
|
||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg24PartB(tNMEA0183AISMsg &AISMsg) {
|
||||
|
||||
Init("VDM", "AI", '!');
|
||||
AddStrField("1");
|
||||
AddStrField("1");
|
||||
AddEmptyField();
|
||||
AddStrField("A");
|
||||
AddStrField( GetPayloadType24_PartB() );
|
||||
AddStrField("0"); // Message 24, both parts have always Zero Padding
|
||||
|
||||
return AISMsg;
|
||||
}
|
||||
|
||||
//******************************* AIS PAYLOADS *********************************
|
||||
//******************************************************************************
|
||||
// get converted Payload for Message 1, 2, 3 & 18, always Length 168
|
||||
const char *tNMEA0183AISMsg::GetPayloadFix(int &padBits,uint16_t fixLen){
|
||||
uint16_t lenbin = iAddPldBin;
|
||||
if ( lenbin != fixLen ) return nullptr;
|
||||
return GetPayload(padBits,0,0);
|
||||
}
|
||||
const char *tNMEA0183AISMsg::GetPayload(int &padBits,uint16_t offset,uint16_t bitLen) {
|
||||
padBits=ConvertBinaryAISPayloadBinToAscii<AIS_BIN_MAX_LEN>(PayloadBin,iAddPldBin, bitLen,offset );
|
||||
const char *tNMEA0183AISMsg::GetPayload() {
|
||||
|
||||
uint16_t lenbin = strlen( PayloadBin);
|
||||
if ( lenbin != 168 ) return nullptr;
|
||||
|
||||
if ( !ConvertBinaryAISPayloadBinToAscii( PayloadBin ) ) return nullptr;
|
||||
return Payload;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// get converted Part 1 of Payload for Message 5
|
||||
const char *tNMEA0183AISMsg::GetPayloadType5_Part1() {
|
||||
|
||||
uint16_t lenbin = strlen( PayloadBin);
|
||||
if ( lenbin != 424 ) return nullptr;
|
||||
|
||||
char to[337];
|
||||
strncpy(to, PayloadBin, 336); // First Part is always 336 Length
|
||||
to[336]=0;
|
||||
|
||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
||||
|
||||
return Payload;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// get converted Part 2 of Payload for Message 5
|
||||
const char *tNMEA0183AISMsg::GetPayloadType5_Part2() {
|
||||
|
||||
uint16_t lenbin = strlen( PayloadBin);
|
||||
if ( lenbin != 424 ) return nullptr;
|
||||
|
||||
lenbin = 88; // Second Part is always 424 - 336 + 2 padding Zeros in Length
|
||||
char to[91];
|
||||
strncpy(to, PayloadBin + 336, lenbin);
|
||||
to[88]='0'; to[89]='0'; to[90]=0;
|
||||
|
||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
||||
return Payload;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// get converted Part A of Payload for Message 24
|
||||
// Bit 0.....167, len 168
|
||||
// In PayloadBin is Part A and Part B chained together with Length 296
|
||||
const char *tNMEA0183AISMsg::GetPayloadType24_PartA() {
|
||||
uint16_t lenbin = strlen( PayloadBin);
|
||||
if ( lenbin != 296 ) return nullptr; // too short for Part A
|
||||
|
||||
char to[169]; // Part A has Length 168
|
||||
*to = '\0';
|
||||
for (int i=0; i<168; i++){
|
||||
to[i] = PayloadBin[i];
|
||||
}
|
||||
to[168]=0;
|
||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
||||
return Payload;
|
||||
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// get converted Part B of Payload for Message 24
|
||||
// Bit 0.....38 + bit39='1' (part number) + bit 168........295 296='\0' of total PayloadBin
|
||||
// binary part B: len 40 + 128 = len 168
|
||||
const char *tNMEA0183AISMsg::GetPayloadType24_PartB() {
|
||||
uint16_t lenbin = strlen( PayloadBin);
|
||||
if ( lenbin != 296 ) return nullptr; // too short for Part B
|
||||
char to[169]; // Part B has Length 168
|
||||
*to = '\0';
|
||||
for (int i=0; i<39; i++){
|
||||
to[i] = PayloadBin[i];
|
||||
}
|
||||
to[39] = 49; // part number 1
|
||||
for (int i=40; i<168; i++) {
|
||||
to[i] = PayloadBin[i+128];
|
||||
}
|
||||
to[168]=0;
|
||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
||||
return Payload;
|
||||
}
|
||||
|
||||
@@ -45,48 +45,43 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#define BITSET_LENGTH 120
|
||||
|
||||
typedef std::bitset<BITSET_LENGTH> AISBitSet;
|
||||
class tNMEA0183AISMsg : public tNMEA0183Msg {
|
||||
|
||||
protected: // AIS-NMEA
|
||||
std::bitset<BITSET_LENGTH> bset;
|
||||
static const char *EmptyAISField; // 6bits 0 not used yet.....
|
||||
static const char *AsciChar;
|
||||
|
||||
uint16_t iAddPldBin;
|
||||
char Payload[AIS_MSG_MAX_LEN];
|
||||
uint8_t iAddPld;
|
||||
char talker[4]="VDM";
|
||||
char channel[2]="A";
|
||||
std::bitset<AIS_BIN_MAX_LEN> PayloadBin;
|
||||
|
||||
public:
|
||||
char PayloadBin[AIS_BIN_MAX_LEN];
|
||||
char PayloadBin2[AIS_BIN_MAX_LEN];
|
||||
// Clear message
|
||||
void ClearAIS();
|
||||
|
||||
public:
|
||||
tNMEA0183AISMsg();
|
||||
const char *GetPayloadFix(int &padBits,uint16_t fixLen=168);
|
||||
const char *GetPayload(int &padBits,uint16_t offset=0,uint16_t bitLen=0);
|
||||
const char *GetPayload();
|
||||
const char *GetPayloadType5_Part1();
|
||||
const char *GetPayloadType5_Part2();
|
||||
const char *GetPayloadType24_PartA();
|
||||
const char *GetPayloadType24_PartB();
|
||||
const char *GetPayloadBin() const { return PayloadBin; }
|
||||
|
||||
bool BuildMsg5Part1();
|
||||
bool BuildMsg5Part2();
|
||||
bool InitAis(int max=1,int number=1,int sequence=-1);
|
||||
const tNMEA0183AISMsg& BuildMsg5Part1(tNMEA0183AISMsg &AISMsg);
|
||||
const tNMEA0183AISMsg& BuildMsg5Part2(tNMEA0183AISMsg &AISMsg);
|
||||
const tNMEA0183AISMsg& BuildMsg24PartA(tNMEA0183AISMsg &AISMsg);
|
||||
const tNMEA0183AISMsg& BuildMsg24PartB(tNMEA0183AISMsg &AISMsg);
|
||||
|
||||
// Generally Used
|
||||
bool AddIntToPayloadBin(int32_t ival, uint16_t countBits);
|
||||
bool AddBoolToPayloadBin(bool &bval);
|
||||
bool AddBoolToPayloadBin(bool &bval, uint8_t size);
|
||||
bool AddEncodedCharToPayloadBin(char *sval, size_t Length);
|
||||
/**
|
||||
* @param channelA - if set A, otherwise B
|
||||
* @param own - if set VDO, else VDM
|
||||
*/
|
||||
void SetChannelAndTalker(bool channelA,bool own=false);
|
||||
/**
|
||||
* convert the payload to ascii
|
||||
* return the number of padding bits
|
||||
* @param bitSize the number of bits to be used, 0 - use all bits
|
||||
*/
|
||||
template <unsigned int SZ>
|
||||
int ConvertBinaryAISPayloadBinToAscii(std::bitset<SZ> &src,uint16_t maxSize, uint16_t bitSize,uint16_t offset=0);
|
||||
bool AddEmptyFieldToPayloadBin(uint8_t iBits);
|
||||
bool ConvertBinaryAISPayloadBinToAscii(const char *payloadbin);
|
||||
|
||||
// AIS Helper functions
|
||||
protected:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# NMEA2000 to NMEA0183 AIS Converter
|
||||
# NMEA2000 -> NMEA0183 AIS converter v1.0.0
|
||||
|
||||
Import from https://github.com/ronzeiller/NMEA0183-AIS
|
||||
|
||||
NMEA0183 AIS library © Ronnie Zeiller, www.zeiller.eu
|
||||
|
||||
Addendum for NMEA2000 and NMEA0183 Library from Timo Lappalainen https://github.com/ttlappalainen
|
||||
|
||||
to get NMEA0183 AIS data from N2k-bus
|
||||
|
||||
## Conversions:
|
||||
|
||||
@@ -15,33 +15,6 @@ to get NMEA0183 AIS data from N2k-bus
|
||||
- NMEA2000 PGN 129809 => AIS Class B "CS" Static Data Report, making a list of UserID (MMSI) and Ship Names used for Message 24 Part A
|
||||
- NMEA2000 PGN 129810 => AIS Class B "CS" Static Data Report, Message 24 Part A+B
|
||||
|
||||
### Versions
|
||||
1.0.6 2024-03-25
|
||||
- fixed to work with Timo´s NMEA2000 v4.21.3
|
||||
|
||||
1.0.5 2023-12-02
|
||||
- removed VDO remote print statements
|
||||
|
||||
1.0.4 2023-12-02
|
||||
- merged @Isoltero master with fixed memory over run, added VDO remote print statements Thanks to Luis Soltero
|
||||
- fixed example, thanks to @arduinomnomnom
|
||||
|
||||
1.0.3 2022-05-01
|
||||
- Update Examples: AISTransceiverInformation in ParseN2kPGN129039 for changes in NMEA2000 library: https://github.com/ttlappalainen/NMEA2000
|
||||
|
||||
|
||||
1.0.2 2022-04-30
|
||||
- bugfix: malloc without free. Thanks to Luis Soltero (Issue https://github.com/ronzeiller/NMEA0183-AIS/issues/3)
|
||||
|
||||
1.0.1 2022-03-15
|
||||
- bugfix: buffer overrun missing space for termination. Thanks to Luis Soltero (Issue https://github.com/ronzeiller/NMEA0183-AIS/issues/2)
|
||||
|
||||
2020-12-25
|
||||
- corrected Navigational Status 0. Thanks to Li-Ren (Issue https://github.com/ronzeiller/NMEA0183-AIS/issues/1)
|
||||
|
||||
1.0.0 2019-11-24
|
||||
- initial upload
|
||||
|
||||
### Remarks
|
||||
1. Message Type could be set to 1 or 3 (identical messages) on demand
|
||||
2. Maneuver Indicator (not part of NMEA2000 PGN 129038) => will be set to 0 (default)
|
||||
@@ -60,14 +33,17 @@ To use this library you need also:
|
||||
|
||||
## License
|
||||
|
||||
MIT license
|
||||
|
||||
Copyright (c) 2019-2022 Ronnie Zeiller, www.zeiller.eu
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
190
lib/obp60task/BoatDataCalibration.cpp
Normal file
190
lib/obp60task/BoatDataCalibration.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#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 == "---") {
|
||||
logger->logDebug(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;
|
||||
logger->logDebug(GwLog::LOG, "calibration data: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(),
|
||||
calibMap[instance].offset, calibMap[instance].slope, calibMap[instance].smooth);
|
||||
}
|
||||
logger->logDebug(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()) {
|
||||
logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: %s not in calibration 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();
|
||||
logger->logDebug(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
|
||||
|
||||
logger->logDebug(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()) {
|
||||
logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: smooth factor for %s not found in calibration 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
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
33
lib/obp60task/BoatDataCalibration.h
Normal file
33
lib/obp60task/BoatDataCalibration.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// Functions lib for data instance calibration
|
||||
|
||||
#ifndef _BOATDATACALIBRATION_H
|
||||
#define _BOATDATACALIBRATION_H
|
||||
|
||||
#include "GwApi.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
|
||||
204
lib/obp60task/ConfigMenu.cpp
Normal file
204
lib/obp60task/ConfigMenu.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
Menu system for online configuration
|
||||
*/
|
||||
#include "ConfigMenu.h"
|
||||
|
||||
ConfigMenuItem::ConfigMenuItem(String itemtype, String itemlabel, uint16_t itemval, String itemunit) {
|
||||
if (! (itemtype == "int" or itemtype == "bool")) {
|
||||
valtype = "int";
|
||||
} else {
|
||||
valtype = itemtype;
|
||||
}
|
||||
label = itemlabel;
|
||||
min = 0;
|
||||
max = std::numeric_limits<uint16_t>::max();
|
||||
value = itemval;
|
||||
unit = itemunit;
|
||||
}
|
||||
|
||||
void ConfigMenuItem::setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> valsteps) {
|
||||
min = valmin;
|
||||
max = valmax;
|
||||
steps = valsteps;
|
||||
};
|
||||
|
||||
bool ConfigMenuItem::checkRange(uint16_t checkval) {
|
||||
return (checkval >= min) and (checkval <= max);
|
||||
}
|
||||
|
||||
String ConfigMenuItem::getLabel() {
|
||||
return label;
|
||||
};
|
||||
|
||||
uint16_t ConfigMenuItem::getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
bool ConfigMenuItem::setValue(uint16_t newval) {
|
||||
if (valtype == "int") {
|
||||
if (newval >= min and newval <= max) {
|
||||
value = newval;
|
||||
return true;
|
||||
}
|
||||
return false; // out of range
|
||||
} else if (valtype == "bool") {
|
||||
value = (newval != 0) ? 1 : 0;
|
||||
return true;
|
||||
}
|
||||
return false; // invalid type
|
||||
};
|
||||
|
||||
void ConfigMenuItem::incValue() {
|
||||
// increase value by step
|
||||
if (valtype == "int") {
|
||||
if (value + step < max) {
|
||||
value += step;
|
||||
} else {
|
||||
value = max;
|
||||
}
|
||||
} else if (valtype == "bool") {
|
||||
value = !value;
|
||||
}
|
||||
};
|
||||
|
||||
void ConfigMenuItem::decValue() {
|
||||
// decrease value by step
|
||||
if (valtype == "int") {
|
||||
if (value - step > min) {
|
||||
value -= step;
|
||||
} else {
|
||||
value = min;
|
||||
}
|
||||
} else if (valtype == "bool") {
|
||||
value = !value;
|
||||
}
|
||||
};
|
||||
|
||||
String ConfigMenuItem::getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
uint16_t ConfigMenuItem::getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
void ConfigMenuItem::setStep(uint16_t newstep) {
|
||||
if (std::find(steps.begin(), steps.end(), newstep) == steps.end()) {
|
||||
return; // invalid step: not in list of possible steps
|
||||
}
|
||||
step = newstep;
|
||||
}
|
||||
|
||||
int8_t ConfigMenuItem::getPos() {
|
||||
return position;
|
||||
};
|
||||
|
||||
void ConfigMenuItem::setPos(int8_t newpos) {
|
||||
position = newpos;
|
||||
};
|
||||
|
||||
String ConfigMenuItem::getType() {
|
||||
return valtype;
|
||||
}
|
||||
|
||||
ConfigMenu::ConfigMenu(String menutitle, uint16_t menu_x, uint16_t menu_y) {
|
||||
title = menutitle;
|
||||
x = menu_x;
|
||||
y = menu_y;
|
||||
};
|
||||
|
||||
ConfigMenuItem* ConfigMenu::addItem(String key, String label, String valtype, uint16_t val, String valunit) {
|
||||
if (items.find(key) != items.end()) {
|
||||
// duplicate keys not allowed
|
||||
return nullptr;
|
||||
}
|
||||
ConfigMenuItem *itm = new ConfigMenuItem(valtype, label, val, valunit);
|
||||
items.insert(std::pair<String, ConfigMenuItem*>(key, itm));
|
||||
// Append key to index, index starting with 0
|
||||
int8_t ix = items.size() - 1;
|
||||
index[ix] = key;
|
||||
itm->setPos(ix);
|
||||
return itm;
|
||||
};
|
||||
|
||||
void ConfigMenu::setItemDimension(uint16_t itemwidth, uint16_t itemheight) {
|
||||
w = itemwidth;
|
||||
h = itemheight;
|
||||
};
|
||||
|
||||
void ConfigMenu::setItemActive(String key) {
|
||||
if (items.find(key) != items.end()) {
|
||||
activeitem = items[key]->getPos();
|
||||
} else {
|
||||
activeitem = -1;
|
||||
}
|
||||
};
|
||||
|
||||
int8_t ConfigMenu::getActiveIndex() {
|
||||
return activeitem;
|
||||
}
|
||||
|
||||
ConfigMenuItem* ConfigMenu::getActiveItem() {
|
||||
if (activeitem < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return items[index[activeitem]];
|
||||
};
|
||||
|
||||
ConfigMenuItem* ConfigMenu::getItemByIndex(uint8_t ix) {
|
||||
if (ix > index.size() - 1) {
|
||||
return nullptr;
|
||||
}
|
||||
return items[index[ix]];
|
||||
};
|
||||
|
||||
ConfigMenuItem* ConfigMenu::getItemByKey(String key) {
|
||||
if (items.find(key) == items.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return items[key];
|
||||
};
|
||||
|
||||
uint8_t ConfigMenu::getItemCount() {
|
||||
return items.size();
|
||||
};
|
||||
|
||||
void ConfigMenu::goPrev() {
|
||||
if (activeitem == 0) {
|
||||
activeitem = items.size() - 1;
|
||||
} else {
|
||||
activeitem--;
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigMenu::goNext() {
|
||||
if (activeitem == items.size() - 1) {
|
||||
activeitem = 0;
|
||||
} else {
|
||||
activeitem++;
|
||||
}
|
||||
}
|
||||
|
||||
Point ConfigMenu::getXY() {
|
||||
return {static_cast<double>(x), static_cast<double>(y)};
|
||||
}
|
||||
|
||||
Rect ConfigMenu::getRect() {
|
||||
return {static_cast<double>(x), static_cast<double>(y),
|
||||
static_cast<double>(w), static_cast<double>(h)};
|
||||
}
|
||||
|
||||
Rect ConfigMenu::getItemRect(int8_t index) {
|
||||
return {static_cast<double>(x), static_cast<double>(y + index * h),
|
||||
static_cast<double>(w), static_cast<double>(h)};
|
||||
}
|
||||
|
||||
void ConfigMenu::setCallback(void (*callback)()) {
|
||||
fptrCallback = callback;
|
||||
}
|
||||
|
||||
void ConfigMenu::storeValues() {
|
||||
if (fptrCallback) {
|
||||
fptrCallback();
|
||||
}
|
||||
}
|
||||
66
lib/obp60task/ConfigMenu.h
Normal file
66
lib/obp60task/ConfigMenu.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "Graphics.h" // for Point and Rect
|
||||
|
||||
class ConfigMenuItem {
|
||||
private:
|
||||
String label;
|
||||
uint16_t value;
|
||||
String unit;
|
||||
String valtype; // "int" | "bool"
|
||||
uint16_t min;
|
||||
uint16_t max;
|
||||
std::vector<uint16_t> steps;
|
||||
uint16_t step;
|
||||
int8_t position; // counted fom 0
|
||||
|
||||
public:
|
||||
ConfigMenuItem(String itemtype, String itemlabel, uint16_t itemval, String itemunit);
|
||||
void setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> steps);
|
||||
bool checkRange(uint16_t checkval);
|
||||
String getLabel();
|
||||
uint16_t getValue();
|
||||
bool setValue(uint16_t newval);
|
||||
void incValue();
|
||||
void decValue();
|
||||
String getUnit();
|
||||
uint16_t getStep();
|
||||
void setStep(uint16_t newstep);
|
||||
int8_t getPos();
|
||||
void setPos(int8_t newpos);
|
||||
String getType();
|
||||
};
|
||||
|
||||
class ConfigMenu {
|
||||
private:
|
||||
String title;
|
||||
std::map <String,ConfigMenuItem*> items;
|
||||
std::map <uint8_t,String> index;
|
||||
int8_t activeitem = -1; // refers to position of item
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t w;
|
||||
uint16_t h;
|
||||
void (*fptrCallback)();
|
||||
|
||||
public:
|
||||
ConfigMenu(String title, uint16_t menu_x, uint16_t menu_y);
|
||||
ConfigMenuItem* addItem(String key, String label, String valtype, uint16_t val, String valunit);
|
||||
void setItemDimension(uint16_t itemwidth, uint16_t itemheight);
|
||||
int8_t getActiveIndex();
|
||||
void setItemActive(String key);
|
||||
ConfigMenuItem* getActiveItem();
|
||||
ConfigMenuItem* getItemByIndex(uint8_t index);
|
||||
ConfigMenuItem* getItemByKey(String key);
|
||||
uint8_t getItemCount();
|
||||
void goPrev();
|
||||
void goNext();
|
||||
Point getXY();
|
||||
Rect getRect();
|
||||
Rect getItemRect(int8_t index);
|
||||
void setCallback(void (*callback)());
|
||||
void storeValues();
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "ImageDecoder.h"
|
||||
#include <mbedtls/base64.h>
|
||||
|
||||
// Decoder for Base64 content
|
||||
bool ImageDecoder::decodeBase64(const String& base64, uint8_t* outBuffer, size_t outSize, size_t& decodedSize) {
|
||||
int ret = mbedtls_base64_decode(
|
||||
outBuffer,
|
||||
outSize,
|
||||
&decodedSize,
|
||||
(const unsigned char*)base64.c_str(),
|
||||
base64.length()
|
||||
);
|
||||
return (ret == 0);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <vector>
|
||||
|
||||
class ImageDecoder {
|
||||
public:
|
||||
bool decodeBase64(const String& base64, uint8_t* outBuffer, size_t outSize, size_t& decodedSize);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <FreeRTOS.h>
|
||||
#include "LedSpiTask.h"
|
||||
#include "GwHardware.h"
|
||||
@@ -14,6 +15,30 @@ https://controllerstech.com/ws2812-leds-using-spi/
|
||||
|
||||
*/
|
||||
|
||||
String Color::toHex() {
|
||||
char hexColor[8];
|
||||
sprintf(hexColor, "#%02X%02X%02X", r, g, b);
|
||||
return String(hexColor);
|
||||
}
|
||||
|
||||
String Color::toName() {
|
||||
static std::map<int, String> const names = {
|
||||
{0xff0000, "Red"},
|
||||
{0x00ff00, "Green"},
|
||||
{0x0000ff, "Blue",},
|
||||
{0xff9900, "Orange"},
|
||||
{0xffff00, "Yellow"},
|
||||
{0x3366ff, "Aqua"},
|
||||
{0xff0066, "Violet"},
|
||||
{0xffffff, "White"}
|
||||
};
|
||||
int color = (r << 16) + (g << 8) + b;
|
||||
auto it = names.find(color);
|
||||
if (it == names.end()) {
|
||||
return toHex();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
static uint8_t mulcolor(uint8_t f1, uint8_t f2){
|
||||
uint16_t rt=f1;
|
||||
@@ -22,11 +47,9 @@ static uint8_t mulcolor(uint8_t f1, uint8_t f2){
|
||||
}
|
||||
|
||||
Color setBrightness(const Color &color,uint8_t brightness){
|
||||
if (brightness > 100) brightness = 100;
|
||||
|
||||
uint16_t br255=brightness*255;
|
||||
br255=br255/100;
|
||||
//Very simple for now
|
||||
//very simple for now
|
||||
Color rt=color;
|
||||
rt.g=mulcolor(rt.g,br255);
|
||||
rt.b=mulcolor(rt.b,br255);
|
||||
@@ -61,12 +84,12 @@ static size_t ledsToBuffer(int numLeds,const Color *leds,uint8_t *buffer){
|
||||
bool prepareGpio(GwLog *logger, uint8_t pin){
|
||||
esp_err_t err=gpio_set_direction((gpio_num_t)pin,GPIO_MODE_OUTPUT);
|
||||
if (err != ESP_OK){
|
||||
LOG_DEBUG(GwLog::ERROR,"unable to set gpio mode for %d: %d",pin,(int)err);
|
||||
logger->logDebug(GwLog::ERROR, "unable to set gpio mode for %d: %d", pin, (int)err);
|
||||
return false;
|
||||
}
|
||||
err=gpio_set_level((gpio_num_t)pin,0);
|
||||
if (err != ESP_OK){
|
||||
LOG_DEBUG(GwLog::ERROR,"unable to set gpio level for %d: %d",pin,(int)err);
|
||||
logger->logDebug(GwLog::ERROR, "unable to set gpio level for %d: %d", pin, (int)err);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -92,8 +115,8 @@ bool prepareSpi(GwLog *logger,spi_host_device_t bus,spi_device_handle_t *device)
|
||||
};
|
||||
esp_err_t err=spi_bus_initialize(bus,&buscfg,SPI_DMA_CH_AUTO);
|
||||
if (err != ESP_OK){
|
||||
LOG_DEBUG(GwLog::ERROR,"unable to initialize SPI bus %d,mosi=%d, error=%d",
|
||||
(int)bus,-1,(int)err);
|
||||
logger->logDebug(GwLog::ERROR, "unable to initialize SPI bus %d,mosi=%d, error=%d",
|
||||
(int)bus, -1, (int)err);
|
||||
return false;
|
||||
}
|
||||
spi_device_interface_config_t devcfg = {
|
||||
@@ -111,16 +134,16 @@ bool prepareSpi(GwLog *logger,spi_host_device_t bus,spi_device_handle_t *device)
|
||||
};
|
||||
err=spi_bus_add_device(bus,&devcfg,device);
|
||||
if (err != ESP_OK){
|
||||
LOG_DEBUG(GwLog::ERROR,"unable to add device to SPI bus %d,mosi=%d, error=%d",
|
||||
(int)bus,-1,(int)err);
|
||||
logger->logDebug(GwLog::ERROR, "unable to add device to SPI bus %d,mosi=%d, error=%d",
|
||||
(int)bus, -1, (int)err);
|
||||
return false;
|
||||
}
|
||||
//slightly speed up the transactions
|
||||
//as we are the only ones using the bus we can safely acquire it forever
|
||||
err=spi_device_acquire_bus(*device,portMAX_DELAY);
|
||||
if (err != ESP_OK){
|
||||
LOG_DEBUG(GwLog::ERROR,"unable to acquire SPI bus %d,mosi=%d, error=%d",
|
||||
(int)bus,-1,(int)err);
|
||||
logger->logDebug(GwLog::ERROR,"unable to acquire SPI bus %d,mosi=%d, error=%d",
|
||||
(int)bus, -1, (int)err);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -150,7 +173,7 @@ bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_d
|
||||
buffer = (uint8_t *)heap_caps_malloc(bufferSize, MALLOC_CAP_DMA|MALLOC_CAP_32BIT);
|
||||
if (!buffer)
|
||||
{
|
||||
LOG_DEBUG(GwLog::ERROR, "unable to allocate %d bytes of DMA buffer", (int)bufferSize);
|
||||
logger->logDebug(GwLog::ERROR, "unable to allocate %d bytes of DMA buffer", (int)bufferSize);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -171,12 +194,12 @@ bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_d
|
||||
int64_t end = esp_timer_get_time();
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
LOG_DEBUG(GwLog::ERROR, "unable to send led data: %d", (int)ret);
|
||||
logger->logDebug(GwLog::ERROR, "unable to send led data: %d", (int)ret);
|
||||
rv = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG(GwLog::DEBUG, "successfully send led data for %d leds, %lld us", numLeds, end - now);
|
||||
logger->logDebug(GwLog::DEBUG, "successfully send led data for %d leds, %lld us", numLeds, end - now);
|
||||
}
|
||||
if (ownsBuffer)
|
||||
{
|
||||
@@ -189,10 +212,10 @@ bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_d
|
||||
void handleSpiLeds(void *param){
|
||||
LedTaskData *taskData=(LedTaskData*)param;
|
||||
GwLog *logger=taskData->api->getLogger();
|
||||
LOG_DEBUG(GwLog::ERROR,"spi led task initialized");
|
||||
logger->logDebug(GwLog::ERROR, "spi led task initialized");
|
||||
spi_host_device_t bus=SPI3_HOST;
|
||||
bool spiValid=false;
|
||||
LOG_DEBUG(GwLog::ERROR,"SpiLed task started");
|
||||
LOG_DEBUG(GwLog::ERROR, "SpiLed task started");
|
||||
|
||||
if (! prepareGpio(logger,OBP_FLASH_LED)){
|
||||
EXIT_TASK;
|
||||
@@ -211,15 +234,15 @@ void handleSpiLeds(void *param){
|
||||
LedInterface newLeds=taskData->getLedData();
|
||||
if (first || current.backlightChanged(newLeds) || current.flasChanged(newLeds)){
|
||||
first=false;
|
||||
LOG_DEBUG(GwLog::ERROR,"handle SPI leds");
|
||||
logger->logDebug(GwLog::ERROR, "handle SPI leds");
|
||||
if (current.backlightChanged(newLeds) || first){
|
||||
LOG_DEBUG(GwLog::ERROR,"setting backlight r=%02d,g=%02d,b=%02d",
|
||||
newLeds.backlight[0].r,newLeds.backlight[0].g,newLeds.backlight[0].b);
|
||||
logger->logDebug(GwLog::ERROR, "setting backlight r=%02d,g=%02d,b=%02d",
|
||||
newLeds.backlight[0].r,newLeds.backlight[0].g,newLeds.backlight[0].b);
|
||||
sendToLeds(logger,OBP_BACKLIGHT_LED,newLeds.backlightLen(),newLeds.backlight,bus,device);
|
||||
}
|
||||
if (current.flasChanged(newLeds) || first){
|
||||
LOG_DEBUG(GwLog::ERROR,"setting flashr=%02d,g=%02d,b=%02d",
|
||||
newLeds.flash[0].r,newLeds.flash[0].g,newLeds.flash[0].b);
|
||||
logger->logDebug(GwLog::ERROR, "setting flashr=%02d,g=%02d,b=%02d",
|
||||
newLeds.flash[0].r,newLeds.flash[0].g,newLeds.flash[0].b);
|
||||
sendToLeds(logger,OBP_FLASH_LED,newLeds.flashLen(),newLeds.flash,bus,device);
|
||||
}
|
||||
current=newLeds;
|
||||
@@ -229,6 +252,11 @@ void handleSpiLeds(void *param){
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void createSpiLedTask(LedTaskData *param){
|
||||
xTaskCreate(handleSpiLeds,"handleLeds",4000,param,3,NULL);
|
||||
}
|
||||
void createSpiLedTask(LedTaskData *param) {
|
||||
TaskHandle_t xHandle = NULL;
|
||||
GwLog *logger = param->api->getLogger();
|
||||
esp_err_t err = xTaskCreate(handleSpiLeds, "handleLeds", configMINIMAL_STACK_SIZE + 2048, param, 3, &xHandle);
|
||||
if (err != pdPASS) {
|
||||
logger->logDebug(GwLog::ERROR, "Failed to create spiled task! (err=%d)", err);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class Color{
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
Color():r(0),g(0),b(0){}
|
||||
Color(uint8_t cr, uint8_t cg,uint8_t cb):
|
||||
Color(uint8_t cr, uint8_t cg, uint8_t cb):
|
||||
b(cb),g(cg),r(cr){}
|
||||
Color(const Color &o):b(o.b),g(o.g),r(o.r){}
|
||||
bool equal(const Color &o) const{
|
||||
@@ -22,6 +22,8 @@ class Color{
|
||||
bool operator != (const Color &other) const{
|
||||
return ! equal(other);
|
||||
}
|
||||
String toHex();
|
||||
String toName();
|
||||
};
|
||||
|
||||
static Color COLOR_GREEN=Color(0,255,0);
|
||||
|
||||
@@ -1,939 +0,0 @@
|
||||
const unsigned char gImage_Logo_OBP_400x300_sw[15000] = { /* 0X00,0X01,0X90,0X01,0X2C,0X01, */
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,0X01,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
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,0X40,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,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,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF8,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,0X01,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X01,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X03,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X07,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X07,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X0F,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
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,0X1F,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,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,
|
||||
0X3F,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF8,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,0X3F,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X7F,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X01,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XFF,0XFF,0X00,0X03,0XFF,0XFF,0XF8,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XF8,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,0X03,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XF8,
|
||||
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,0X03,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X1F,0XFF,0XF8,0X00,0X00,0X00,0X07,0XFF,
|
||||
0XFF,0XF8,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,0X07,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X07,0XFF,0XF8,0X00,0X00,0X00,
|
||||
0X03,0XFF,0XFF,0XF8,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,0X0F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X03,0XFF,0XF8,0X00,
|
||||
0X00,0X00,0X01,0XFF,0XFF,0XF8,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,0X1F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0XFF,
|
||||
0XF8,0X00,0X00,0X00,0X00,0XFF,0XFF,0XF8,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,0X1F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFC,0X00,0X00,0X00,
|
||||
0X00,0X7F,0XF8,0X00,0X00,0X00,0X00,0X7F,0XFF,0XF8,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,0X3F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF8,0X00,
|
||||
0X00,0X00,0X00,0X7F,0XF8,0X00,0X00,0X00,0X00,0X7F,0XFF,0XF8,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,0X7F,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XF0,0X00,0X00,0X00,0X00,0X3F,0XF8,0X00,0X00,0X00,0X00,0X3F,0XFF,0XF8,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,0X7F,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X1F,0XF8,0X00,0X1E,0X00,0X00,0X3F,0XFF,0XF8,
|
||||
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,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XE0,0X00,0X0F,0XC0,0X00,0X1F,0XF8,0X00,0X1F,0XE0,0X00,0X3F,
|
||||
0XFF,0XF8,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,0X01,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X3F,0XF0,0X00,0X0F,0XF8,0X00,0X1F,0XF0,
|
||||
0X00,0X3F,0XFF,0XF8,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,
|
||||
0X01,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X7F,0XF8,0X00,0X0F,0XF8,0X00,
|
||||
0X1F,0XF8,0X00,0X3F,0XFF,0XF8,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,0X03,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0XFF,0XFC,0X00,0X07,
|
||||
0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,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,0X07,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,0XFF,0XFE,
|
||||
0X00,0X07,0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,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,0X0F,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,
|
||||
0XFF,0XFE,0X00,0X07,0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,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,0X0F,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0X80,0X01,0XFF,0XFF,0X00,0X07,0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,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,0X1F,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X1F,0XF0,0X00,0X3F,0XFF,0XF8,
|
||||
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,0X3F,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X1F,0XE0,0X00,0X3F,
|
||||
0XFF,0XF8,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,0X3F,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,
|
||||
0X00,0X3F,0XFF,0XF8,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,
|
||||
0X7F,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,
|
||||
0X00,0X00,0X00,0X7F,0XFF,0XF8,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,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,
|
||||
0XF8,0X00,0X00,0X00,0X00,0X7F,0XFF,0XF8,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,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,
|
||||
0X00,0X03,0XF8,0X00,0X00,0X00,0X00,0XFF,0XFF,0XF8,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,0X01,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,
|
||||
0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X01,0XFF,0XFF,0XF8,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,0X03,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X03,0XFF,0XFF,0XF8,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,0X03,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X07,0XFF,0XFF,0XF8,
|
||||
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,0X07,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X0F,0XFF,
|
||||
0XFF,0XF8,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,0X0F,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,
|
||||
0X7F,0XFF,0XFF,0XF8,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,0X1F,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X07,0XF8,0X00,
|
||||
0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X1F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,0XFF,0XFE,0X00,0X07,
|
||||
0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X3F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,0XFF,0XFE,
|
||||
0X00,0X07,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X7F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X00,
|
||||
0XFF,0XFC,0X00,0X07,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X7F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XC0,0X00,0XFF,0XFC,0X00,0X0F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XC0,0X00,0X3F,0XF8,0X00,0X0F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
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,0X01,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XE0,0X00,0X1F,0XE0,0X00,0X1F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,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,0X03,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X1F,0XF8,0X00,0X1F,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF8,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,0X03,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X3F,0XF8,0X00,
|
||||
0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,
|
||||
0X07,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X3F,
|
||||
0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X0F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF8,0X00,0X00,0X00,
|
||||
0X00,0X7F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X0F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFC,0X00,
|
||||
0X00,0X00,0X00,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X1F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XFE,0X00,0X00,0X00,0X01,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X3F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X00,0X03,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
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,0X3F,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X0F,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,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,0X7F,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X3F,0XFF,0XF8,0X00,0X1F,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF8,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,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFE,0X00,0X01,0XFF,0XFF,0XF8,0X00,
|
||||
0X3F,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X01,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
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,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,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,0X1F,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF8,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,0X1F,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X3F,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X1F,0XFF,0XF8,
|
||||
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X0F,
|
||||
0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,
|
||||
0X00,0X07,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
|
||||
0X03,0XFE,0X00,0X03,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
|
||||
0X00,0X00,0X03,0XFE,0X00,0X03,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X01,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0XFF,0XF0,0X00,0X7F,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0X7F,0XF0,
|
||||
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,
|
||||
0X3F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,
|
||||
0X00,0X00,0X3F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,
|
||||
0XFF,0XFE,0X00,0X00,0X1F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,
|
||||
0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X0F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X0F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X07,0XF0,0X00,0X7F,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X03,0XF0,0X00,0X7F,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X03,0XF0,
|
||||
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X00,
|
||||
0X01,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,
|
||||
0X00,0X00,0X00,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
|
||||
0X07,0XFE,0X00,0X00,0X00,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
|
||||
0X00,0X00,0X07,0XFE,0X00,0X00,0X00,0X70,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X00,0X00,0X30,0X00,0X7F,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X08,0X00,0X30,0X00,0X7F,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X0C,0X00,0X10,0X00,0X7F,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X0C,0X00,0X00,
|
||||
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X0E,
|
||||
0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,
|
||||
0X00,0X0F,0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,
|
||||
0XFF,0XFE,0X00,0X0F,0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,
|
||||
0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0X80,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XC0,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XC0,0X00,0X00,0X7F,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XE0,0X00,0X00,0X7F,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XF0,0X00,
|
||||
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,
|
||||
0XF8,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0XFF,0XFF,0XFF,0XFE,
|
||||
0X00,0X0F,0XF8,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
|
||||
0X01,0XFE,0X00,0X0F,0XFC,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
|
||||
0X00,0X00,0X01,0XFE,0X00,0X0F,0XFE,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFE,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFF,0X00,0X00,0X7F,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFF,0X80,0X00,0X7F,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFF,0X80,
|
||||
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,
|
||||
0XFF,0XC0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,
|
||||
0X00,0X0F,0XFF,0XE0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
|
||||
0X01,0XFE,0X00,0X0F,0XFF,0XE0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
|
||||
0X00,0X00,0X01,0XFE,0X00,0X1F,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
|
||||
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0X80,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XC0,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,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,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,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,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,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,
|
||||
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,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,0X03,
|
||||
0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,0X00,0X0F,0XFF,0XE0,0X00,0X00,
|
||||
0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X02,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X03,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XC0,0X00,0X0F,0XFF,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X0E,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X07,0XC0,0X00,0X0F,
|
||||
0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X3E,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X0F,0XC0,
|
||||
0X00,0X0F,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,
|
||||
0X0F,0XC0,0X00,0X0F,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X1F,0XE0,0X00,0X00,0X00,
|
||||
0X00,0X00,0X0F,0XC0,0X00,0X0F,0XE0,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,0XE0,0X03,
|
||||
0XE0,0X00,0X3F,0XE0,0X1F,0XC0,0X00,0X0F,0XE0,0X7F,0X00,0X0E,0X00,0X7E,0X00,0X00,
|
||||
0X00,0X3F,0X00,0X01,0XFC,0X00,0XFE,0X00,0X3F,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,
|
||||
0XC0,0X1F,0XFC,0X00,0XFF,0XF8,0X7F,0XFC,0X00,0X0F,0XE0,0X7F,0X1F,0X9F,0X83,0XFF,
|
||||
0X80,0X7E,0X01,0XFF,0XE0,0X07,0XFF,0X03,0XFF,0XE0,0XFF,0XF0,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,
|
||||
0XF8,0X1F,0XC0,0X3F,0XFE,0X03,0XFF,0XFC,0X7F,0XFC,0X00,0X0F,0XE0,0X7F,0X1F,0XFF,
|
||||
0X07,0XFF,0XE0,0X7E,0X03,0XFF,0XF0,0X1F,0XFF,0XC3,0XFF,0XE1,0XFF,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X03,0XFF,0XFF,0X80,0X7F,0XFF,0X83,0XFF,0XFE,0X7F,0XFC,0X00,0X0F,0XE0,0XFF,
|
||||
0X1F,0XFF,0X0F,0XFF,0XF0,0X7E,0X07,0XFF,0XF8,0X3F,0XFF,0XE3,0XFF,0XE3,0XFF,0XFC,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X03,0XFF,0XFF,0X00,0XFF,0XFF,0X87,0XF8,0XFE,0X7F,0XFC,0X00,0X0F,
|
||||
0XFF,0XFE,0X1F,0XFE,0X1F,0XFF,0XF0,0X7E,0X0F,0XE3,0XF8,0X3F,0XFF,0XE3,0XFF,0XE3,
|
||||
0XE1,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0X01,0XFE,0X3F,0XC7,0XF0,0X7E,0X1F,0XC0,
|
||||
0X00,0X0F,0XFF,0XFE,0X1F,0XF2,0X1F,0XC3,0XF8,0X7E,0X0F,0XC1,0XFC,0X7F,0X87,0XF0,
|
||||
0XFE,0X07,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XC1,0XFC,0X1F,0XC0,0X00,0XFE,
|
||||
0X0F,0XC0,0X00,0X0F,0XFF,0XFC,0X1F,0XE0,0X3F,0X83,0XF8,0X7E,0X1F,0XC0,0XFC,0X7F,
|
||||
0X03,0X80,0XFE,0X03,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE1,0XFC,0X0F,0XC0,
|
||||
0X07,0XFE,0X0F,0XC0,0X00,0X0F,0XFF,0XF8,0X1F,0XC0,0X3F,0X81,0XF8,0X7E,0X1F,0XC0,
|
||||
0XFC,0X7E,0X00,0X00,0XFE,0X03,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,0XE1,0XF8,
|
||||
0X0F,0XC0,0XFF,0XFE,0X0F,0XC0,0X00,0X0F,0XFF,0XE0,0X1F,0XC0,0X3F,0X81,0XF8,0X7E,
|
||||
0X1F,0XFF,0XFE,0X7E,0X00,0X00,0XFE,0X01,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,
|
||||
0XF1,0XF8,0X0F,0XC3,0XFF,0XFE,0X0F,0XC0,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X3F,0X01,
|
||||
0XFC,0X7E,0X1F,0XFF,0XFE,0X7E,0X00,0X00,0XFE,0X00,0XFF,0XFC,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,
|
||||
0XF8,0X0F,0XF1,0XF8,0X0F,0XC7,0XFC,0X7E,0X0F,0XC0,0X00,0X0F,0XE0,0X00,0X1F,0XC0,
|
||||
0X3F,0X81,0XF8,0X7E,0X1F,0XFF,0XFE,0X7E,0X00,0X00,0XFE,0X00,0X3F,0XFC,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X03,0XF8,0X0F,0XF1,0XFC,0X1F,0XC7,0XF0,0X7E,0X0F,0XC0,0X00,0X0F,0XE0,0X00,
|
||||
0X1F,0XC0,0X3F,0X81,0XF8,0X7E,0X1F,0XC0,0X00,0X7F,0X03,0XC0,0XFE,0X00,0X01,0XFE,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X03,0XFC,0X3F,0XF1,0XFC,0X1F,0XC7,0XE0,0X7E,0X0F,0XC0,0X00,0X0F,
|
||||
0XE0,0X00,0X1F,0XC0,0X1F,0X83,0XF8,0X7E,0X1F,0XC0,0X00,0X7F,0X07,0XF0,0XFE,0X00,
|
||||
0X60,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE0,0XFF,0X3F,0X87,0XE0,0XFE,0X0F,0XFC,
|
||||
0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X1F,0XE7,0XF0,0X7E,0X0F,0XE1,0XFC,0X7F,0XCF,0XF0,
|
||||
0X7F,0XC7,0XF0,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE0,0XFF,0XFF,0X87,0XFF,0XFE,
|
||||
0X0F,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X0F,0XFF,0XF0,0X7E,0X0F,0XFF,0XF8,0X3F,
|
||||
0XFF,0XE0,0X7F,0XC7,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XC0,0X7F,0XFF,0X07,
|
||||
0XFF,0XFE,0X0F,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X07,0XFF,0XE0,0X7E,0X07,0XFF,
|
||||
0XF0,0X1F,0XFF,0XC0,0X7F,0XE3,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0X80,0X1F,
|
||||
0XFE,0X03,0XFF,0X3F,0X07,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X03,0XFF,0XC0,0X7E,
|
||||
0X03,0XFF,0XE0,0X0F,0XFF,0X80,0X3F,0XE1,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XF8,
|
||||
0X00,0X07,0XF8,0X00,0XFC,0X3F,0X03,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X00,0XFF,
|
||||
0X00,0X7E,0X00,0XFF,0X80,0X03,0XFE,0X00,0X1F,0XE0,0X7F,0XC0,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,0XFE,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,0X03,0XFE,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,0X03,0XFE,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,0X07,0XFE,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,0X07,0XFC,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,0X07,0XFC,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,0X01,0XE0,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,};
|
||||
@@ -1,939 +0,0 @@
|
||||
const unsigned char gImage_MFD_OBP60_400x300_sw[15000] = { /* 0X00,0X01,0X90,0X01,0X2C,0X01, */
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
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,0X1F,0XE0,0X3F,
|
||||
0XC0,0X00,0X00,0X7E,0X00,0X40,0XFC,0X07,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X08,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XE0,0X0F,0XC0,0X00,0X00,0X00,
|
||||
0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
|
||||
0XF0,0X3F,0XC0,0X00,0X00,0X7E,0X01,0XC0,0XFC,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X38,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XF8,0X0F,0XC0,0X00,
|
||||
0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X1F,0XF0,0X7F,0XC0,0X00,0X00,0X7E,0X07,0XC0,0XFC,0X1F,0XF0,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0XF8,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFC,0X0F,
|
||||
0XC0,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X1F,0XF0,0X7F,0XC0,0X00,0X00,0X7E,0X0F,0XC0,0XFC,0X3F,0XE0,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X01,0XF8,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,
|
||||
0XFE,0X0F,0XC0,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X1F,0XF0,0X7F,0XC0,0X00,0X00,0X7E,0X0F,0XC0,0X00,0X3F,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X07,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XF8,0X7F,0XC0,0X00,0X00,0X7E,0X0F,0XC0,
|
||||
0X00,0X3F,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XF8,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X07,0XF0,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XF8,0XFF,0XC3,0XE0,0XF8,0X7E,
|
||||
0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XF8,0XF8,0X01,0XFC,0X07,0XFF,0X1F,0X80,0X7F,
|
||||
0X00,0XF8,0XF8,0X00,0X07,0XF0,0X7F,0X0F,0XC0,0X7F,0X80,0XF9,0XF0,0X1F,0X80,0XFF,
|
||||
0X83,0XF0,0X3F,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X78,0XF7,0XC3,0XE0,
|
||||
0XF8,0X7E,0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XFB,0XFC,0X07,0XFF,0X07,0XFF,0X1F,
|
||||
0X81,0XFF,0XC0,0XFB,0XFC,0X00,0X07,0XF0,0X3F,0X0F,0XC1,0XFF,0XE0,0XFB,0XFC,0X1F,
|
||||
0X83,0XFF,0XE1,0XF8,0X3E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X78,0XF7,
|
||||
0XC3,0XE0,0XF8,0X7E,0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XFF,0XFE,0X0F,0XFF,0XC7,
|
||||
0XFF,0X1F,0X83,0XFF,0XE0,0XFF,0XFE,0X00,0X07,0XF0,0X3F,0X0F,0XC3,0XFF,0XF0,0XFF,
|
||||
0XFE,0X1F,0X87,0XFF,0XF1,0XF8,0X3E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
|
||||
0X7C,0XF7,0XC3,0XE0,0XF8,0X7E,0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XFF,0XFE,0X1F,
|
||||
0XFF,0XC7,0XFF,0X1F,0X87,0XFF,0XF0,0XFF,0XFE,0X00,0X07,0XF0,0X3F,0X8F,0XC3,0XE3,
|
||||
0XF0,0XFF,0XFE,0X1F,0X87,0XFF,0XF0,0XF8,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X1F,0X3D,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XC1,0XF0,0XFF,
|
||||
0XFE,0X1F,0X87,0XE1,0XF8,0X1F,0X87,0XE3,0XF0,0XFF,0XFE,0X00,0X07,0XF0,0X3F,0X8F,
|
||||
0XC3,0XE1,0X80,0XFC,0X7F,0X1F,0X87,0XC1,0XF0,0XFC,0X7C,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X1F,0X3D,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XC1,
|
||||
0XF0,0XFC,0X7E,0X3F,0X07,0X01,0XF8,0X1F,0X8F,0XC1,0XF8,0XFC,0X7E,0X00,0X07,0XF0,
|
||||
0X3F,0X8F,0XC3,0XFC,0X00,0XFC,0X3F,0X1F,0X80,0X07,0XF0,0X7C,0X7C,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X1F,0X3F,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,
|
||||
0X07,0XC1,0XF0,0XFC,0X3E,0X3F,0X00,0X01,0XF8,0X1F,0X8F,0XC1,0XF8,0XFC,0X3E,0X00,
|
||||
0X07,0XF0,0X3F,0X0F,0XC3,0XFF,0XE0,0XF8,0X3F,0X1F,0X80,0X7F,0XF0,0X7C,0XF8,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X3F,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,
|
||||
0XFC,0X3F,0X07,0XC1,0XF0,0XF8,0X3E,0X3F,0X00,0X01,0XF8,0X1F,0X8F,0XC1,0XF8,0XF8,
|
||||
0X3E,0X00,0X07,0XF0,0X3F,0X0F,0XC1,0XFF,0XF0,0XF8,0X3F,0X1F,0X83,0XFF,0XF0,0X7C,
|
||||
0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0XC7,0XC3,0XE1,0XF8,0X7E,
|
||||
0X0F,0XC0,0XFC,0X3F,0X07,0XC3,0XF0,0XF8,0X3E,0X3F,0X00,0X01,0XF8,0X1F,0X8F,0XC1,
|
||||
0XF8,0XF8,0X3E,0X00,0X07,0XF0,0X3F,0X0F,0XC0,0X7F,0XF8,0XF8,0X3F,0X1F,0X87,0XF1,
|
||||
0XF0,0X3E,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0XC7,0XC3,0XF1,
|
||||
0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XE3,0XF0,0XF8,0X3E,0X3F,0X03,0X01,0XF8,0X1F,
|
||||
0X8F,0XC1,0XF8,0XF8,0X3E,0X00,0X07,0XF0,0X7F,0X0F,0XC0,0X03,0XF8,0XFC,0X3F,0X1F,
|
||||
0X8F,0XC1,0XF0,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0XC7,
|
||||
0XC3,0XFF,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XFF,0XF0,0XF8,0X3E,0X1F,0X87,0XE1,
|
||||
0XF8,0X1F,0X87,0XE3,0XF0,0XF8,0X3E,0X00,0X07,0XFF,0XFE,0X0F,0XC0,0XE0,0XF8,0XFC,
|
||||
0X7F,0X1F,0X8F,0XC3,0XF0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
|
||||
0X1F,0XC7,0XC3,0XFF,0XF8,0X7E,0X0F,0XF8,0XFC,0X3F,0X07,0XFF,0XF0,0XF8,0X3E,0X1F,
|
||||
0XFF,0XC1,0XFF,0X1F,0X87,0XFF,0XF0,0XF8,0X3E,0X00,0X07,0XFF,0XFE,0X0F,0XC7,0XE1,
|
||||
0XF8,0XFF,0XFE,0X1F,0X8F,0XFF,0XF0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X1F,0X0F,0X87,0XC3,0XFF,0XF8,0X7E,0X0F,0XF8,0XFC,0X3F,0X07,0XFF,0XF0,0XF8,
|
||||
0X3E,0X0F,0XFF,0XC1,0XFF,0X1F,0X83,0XFF,0XE0,0XF8,0X3E,0X00,0X07,0XFF,0XFC,0X0F,
|
||||
0XC3,0XFF,0XF0,0XFF,0XFE,0X1F,0X8F,0XFF,0XF0,0X1F,0XE0,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X1F,0X0F,0X87,0XC1,0XFE,0XF8,0X7E,0X07,0XF8,0XFC,0X3F,0X03,0XFD,
|
||||
0XF0,0XF8,0X3E,0X07,0XFF,0X80,0XFF,0X1F,0X81,0XFF,0XC0,0XF8,0X3E,0X00,0X07,0XFF,
|
||||
0XF8,0X0F,0XC3,0XFF,0XE0,0XFF,0XFC,0X1F,0X87,0XFD,0XF0,0X0F,0XE0,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X1F,0X0F,0X87,0XC0,0XF8,0XF8,0X7E,0X03,0XF8,0XFC,0X3F,
|
||||
0X01,0XF1,0XF0,0XF8,0X3E,0X01,0XFE,0X00,0X7F,0X1F,0X80,0X7F,0X00,0XF8,0X3E,0X00,
|
||||
0X07,0XFF,0XC0,0X0F,0XC0,0X7F,0X80,0XF9,0XF0,0X1F,0X81,0XF0,0XF8,0X0F,0XC0,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,0XF8,0X00,0X00,0X00,0X00,0X00,0X0F,
|
||||
0XC0,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,0XF8,0X00,0X00,0X00,0X00,
|
||||
0X00,0X0F,0XC0,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,0XF8,0X00,0X00,
|
||||
0X00,0X00,0X01,0XFF,0X80,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,0XF8,
|
||||
0X00,0X00,0X00,0X00,0X01,0XFF,0X80,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,0XF8,0X00,0X00,0X00,0X00,0X01,0XFF,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,0XF8,0X00,0X00,0X00,0X00,0X00,0XFC,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,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,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,
|
||||
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,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,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,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,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,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,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,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,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
|
||||
0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XF8,0X01,0XFF,0XFC,0X03,0XFF,0XF0,0X00,0XFC,
|
||||
0X00,0X3F,0X80,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,0X1F,0XFE,0X01,0XFF,0XFF,0X03,0XFF,0XFC,
|
||||
0X03,0XFF,0X00,0XFF,0XE0,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,0X7F,0XFF,0X81,0XFF,0XFF,0X83,
|
||||
0XFF,0XFE,0X07,0XFF,0X81,0XFF,0XF0,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,0X7F,0XFF,0XC1,0XFF,
|
||||
0XFF,0X83,0XFF,0XFE,0X0F,0XFF,0XC3,0XFF,0XF0,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,0XFF,0XFF,
|
||||
0XC1,0XFF,0XFF,0XC3,0XFF,0XFE,0X1F,0X8F,0XC3,0XF1,0XF8,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,0X01,
|
||||
0XFE,0X1F,0XE1,0XFC,0X1F,0XC3,0XF0,0X7F,0X1F,0X87,0X83,0XE0,0XF8,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,0X01,0XFC,0X0F,0XE1,0XFC,0X1F,0X83,0XF0,0X3F,0X1F,0X00,0X07,0XE0,0XF8,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,0X01,0XF8,0X07,0XE1,0XFC,0X1F,0X83,0XF0,0X3F,0X3F,0X3E,0X07,0XE0,
|
||||
0XFC,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,0X03,0XF8,0X07,0XF1,0XFF,0XFF,0X03,0XF0,0X7F,0X3F,0X7F,
|
||||
0X87,0XE0,0XFC,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,0X03,0XF8,0X07,0XF1,0XFF,0XFE,0X03,0XFF,0XFE,
|
||||
0X3F,0XFF,0XC7,0XE0,0XFC,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,0X03,0XF8,0X07,0XF1,0XFF,0XFF,0X03,
|
||||
0XFF,0XFE,0X3F,0XFF,0XC7,0XE0,0XFC,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,0X03,0XF8,0X07,0XF1,0XFF,
|
||||
0XFF,0X83,0XFF,0XFC,0X3F,0X87,0XE7,0XE0,0XFC,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,0X03,0XF8,0X07,
|
||||
0XF1,0XFF,0XFF,0XC3,0XFF,0XF8,0X3F,0X07,0XE7,0XE0,0XFC,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,0X01,
|
||||
0XF8,0X07,0XE1,0XFC,0X0F,0XC3,0XFF,0XE0,0X3F,0X03,0XE7,0XE0,0XFC,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,0X01,0XFC,0X0F,0XE1,0XFC,0X0F,0XE3,0XF0,0X00,0X1F,0X03,0XE3,0XE0,0XFC,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,0X01,0XFE,0X1F,0XE1,0XFC,0X0F,0XE3,0XF0,0X00,0X1F,0X07,0XE3,0XE0,
|
||||
0XF8,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,0XFF,0XFF,0XC1,0XFF,0XFF,0XC3,0XF0,0X00,0X1F,0X87,
|
||||
0XE3,0XF1,0XF8,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,0X7F,0XFF,0XC1,0XFF,0XFF,0XC3,0XF0,0X00,
|
||||
0X0F,0XFF,0XC1,0XFF,0XF8,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,0X7F,0XFF,0X81,0XFF,0XFF,0X83,
|
||||
0XF0,0X00,0X07,0XFF,0X81,0XFF,0XF0,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,0X1F,0XFE,0X01,0XFF,
|
||||
0XFF,0X83,0XF0,0X00,0X03,0XFF,0X00,0XFF,0XE0,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,0X07,0XF8,
|
||||
0X01,0XFF,0XFC,0X03,0XF0,0X00,0X00,0XFC,0X00,0X3F,0X80,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X40,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,
|
||||
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,0X01,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF0,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,0X01,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF0,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,0X03,0XC0,0X07,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X07,0XC0,0X07,
|
||||
0XFF,0XFC,0X07,0XFF,0X00,0X07,0XFF,0XF0,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,0X07,
|
||||
0XC0,0X07,0XFF,0XE0,0X00,0XFF,0X00,0X00,0XFF,0XF0,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,0X0F,0XC0,0X07,0XFF,0XC0,0X00,0X7F,0X00,0X00,0X7F,0XF0,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,0X1F,0XC0,0X07,0XFF,0X80,0X00,0X3F,0X00,0X00,0X3F,0XF0,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,0X1F,0XC0,0X07,0XFF,0X00,0X00,0X1F,0X00,0X00,0X1F,0XF0,
|
||||
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,0X3F,0XC0,0X07,0XFE,0X00,0XC0,0X0F,0X01,0XE0,
|
||||
0X1F,0XF0,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,0X7F,0XC0,0X07,0XFE,0X03,0XF0,0X0F,
|
||||
0X01,0XF0,0X1F,0XF0,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,0XFF,0XC0,0X07,0XFC,0X03,
|
||||
0XF8,0X0F,0X01,0XF0,0X1F,0XF0,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,0XFF,0XC0,0X07,
|
||||
0XFC,0X07,0XF8,0X07,0X01,0XF0,0X1F,0XF0,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,0X01,0XFF,
|
||||
0XC0,0X07,0XFC,0X07,0XFC,0X07,0X01,0XE0,0X1F,0XF0,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,
|
||||
0X03,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,0X3F,0XF0,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,0X03,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,0X3F,0XF0,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,0X07,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,0X7F,0XF0,
|
||||
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,0X0F,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,
|
||||
0XFF,0XF0,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,0X0F,0XFF,0XC0,0X07,0XFC,0X07,0XF8,0X07,
|
||||
0X01,0XDF,0XFF,0XF0,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,0X1F,0XFF,0XC0,0X07,0XFC,0X07,
|
||||
0XF8,0X0F,0X01,0XFF,0XFF,0XF0,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,0X3F,0XFF,0XC0,0X07,
|
||||
0XFE,0X03,0XF8,0X0F,0X01,0XFF,0XFF,0XF0,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,0X7F,0XFF,
|
||||
0XC0,0X07,0XFE,0X00,0XE0,0X0F,0X01,0XFF,0XFF,0XF0,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,
|
||||
0X7F,0XFF,0XC0,0X07,0XFF,0X00,0X00,0X1F,0X01,0XFF,0XFF,0XF0,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,0XFF,0XFF,0XC0,0X07,0XFF,0X00,0X00,0X3F,0X01,0XFF,0XFF,0XF0,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,0X01,0XFF,0XFF,0XC0,0X07,0XFF,0X80,0X00,0X7F,0X01,0XFF,0XFF,0XF0,
|
||||
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,0X01,0XFF,0XFF,0XC0,0X07,0XFF,0XE0,0X00,0XFF,0X01,0XFF,
|
||||
0XFF,0XF0,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,0X03,0XFF,0XFF,0XC0,0X07,0XFF,0XF8,0X03,0XFF,
|
||||
0X01,0XFF,0XFF,0XF0,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,0X07,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X07,0XFF,0XFF,0XC0,0X07,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X0F,0XFF,0XFF,
|
||||
0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X1F,
|
||||
0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X3F,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X3F,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,
|
||||
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,0X7F,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF0,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,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,
|
||||
0X0F,0XF0,0X3F,0XF0,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,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,
|
||||
0X00,0X78,0X07,0XF0,0X3F,0XF0,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,0X01,0XFF,0XFF,0XFF,0XC0,0X07,
|
||||
0XFE,0X00,0X00,0X78,0X07,0XF0,0X3F,0XF0,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,0X03,0XFF,0XFF,0XFF,
|
||||
0XC0,0X07,0XFE,0X00,0X00,0X78,0X03,0XF0,0X3F,0XF0,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,0X03,0XFF,
|
||||
0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,0X01,0XF0,0X3F,0XF0,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,
|
||||
0X07,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X01,0XF0,0X3F,0XF0,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,0X0F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X00,0XF0,0X3F,0XF0,
|
||||
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,0X1F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X00,0X70,
|
||||
0X3F,0XF0,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,0X1F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0XF8,
|
||||
0X00,0X70,0X3F,0XF0,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,0X3F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,
|
||||
0X00,0XF8,0X00,0X30,0X3F,0XF0,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,0X7F,0XFF,0XFF,0XFF,0XC0,0X07,
|
||||
0XFE,0X00,0X00,0XF8,0X00,0X10,0X3F,0XF0,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,0X7F,0XFF,0XFF,0XFF,
|
||||
0XC0,0X07,0XFE,0X00,0X00,0XF8,0X00,0X10,0X3F,0XF0,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,0XFF,0XFF,
|
||||
0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0XF8,0X08,0X00,0X3F,0XF0,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,0X01,
|
||||
0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X0C,0X00,0X3F,0XF0,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,0X01,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X0E,0X00,0X3F,0XF0,
|
||||
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,0X03,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X0E,0X00,
|
||||
0X3F,0XF0,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,0X07,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,
|
||||
0X0F,0X00,0X3F,0XF0,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,0X0F,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,
|
||||
0X00,0X78,0X0F,0X80,0X3F,0XF0,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,0X0F,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,
|
||||
0XFE,0X00,0X00,0X78,0X0F,0X80,0X3F,0XF0,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,0X1F,0XFF,0XFF,0XFF,0XFF,
|
||||
0XC0,0X07,0XFE,0X00,0X00,0X78,0X0F,0XC0,0X3F,0XF0,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,0X3F,0XFF,0XFF,
|
||||
0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,0X0F,0XE0,0X3F,0XF0,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,0X3F,
|
||||
0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,0X0F,0XE0,0X3F,0XF0,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,0X7F,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,
|
||||
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,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XF0,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,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XF0,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,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,
|
||||
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,
|
||||
0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,0X07,0XFF,0XFF,0XFF,
|
||||
0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,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,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,
|
||||
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,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,0X07,0XF8,0X00,0X00,0X00,0X20,0X0F,0XE0,
|
||||
0X00,0X00,0X38,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,0X07,0XFC,0X00,0X00,0X00,0X60,
|
||||
0X0F,0XF8,0X00,0X00,0X38,0X00,0X00,0X01,0X80,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,0X07,0XFE,0X00,0X00,
|
||||
0X00,0XE0,0X0F,0XF8,0X00,0X00,0X00,0X00,0X00,0X03,0X80,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,0X07,0X0E,
|
||||
0X06,0X00,0XC0,0XE0,0X0E,0X3C,0X08,0X38,0X00,0X18,0X03,0X03,0X81,0XC0,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,
|
||||
0X07,0X1E,0X1F,0X87,0XFB,0XF8,0X0E,0X3C,0XDC,0XFE,0X38,0X7F,0X0F,0XE7,0XE7,0XF0,
|
||||
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,0X07,0XFC,0X3F,0XCF,0X3B,0XF8,0X0F,0XF8,0XF9,0XFF,0X38,0XE7,0X1F,0XE7,
|
||||
0XE6,0X38,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,0X07,0XFE,0X78,0XE0,0X38,0XE0,0X0F,0XF8,0XE1,0XC7,0X39,0XE3,
|
||||
0XBC,0X03,0X87,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,0X07,0X0E,0X70,0XE3,0XF8,0XE0,0X0F,0XE0,0XE1,0XC7,
|
||||
0X39,0XFF,0XB8,0X03,0X87,0XF0,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,0X07,0X0F,0X70,0XEF,0X38,0XE0,0X0E,0X00,
|
||||
0XE1,0XC7,0X39,0XFF,0XB8,0X03,0X81,0XF8,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,0X07,0X1E,0X39,0XEE,0X38,0XE0,
|
||||
0X0E,0X00,0XE1,0XC7,0X38,0XE0,0X3C,0XF3,0X80,0X38,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,0X07,0XFE,0X3F,0XCF,
|
||||
0XF8,0XF0,0X0E,0X00,0XE0,0XFF,0X38,0XFF,0X1F,0XE3,0XEF,0X78,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,0X07,0XFC,
|
||||
0X1F,0X87,0XD8,0XF8,0X0E,0X00,0XE0,0X7C,0X38,0X7E,0X0F,0XC1,0XE7,0XF0,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,0X38,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,0X78,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,0XF8,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,
|
||||
0X20,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,};
|
||||
@@ -1,181 +0,0 @@
|
||||
#include "NetworkClient.h"
|
||||
|
||||
extern "C" {
|
||||
#include "puff.h"
|
||||
}
|
||||
|
||||
// Constructor
|
||||
NetworkClient::NetworkClient(size_t reserveSize)
|
||||
: _doc(reserveSize),
|
||||
_valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Skip GZIP Header an goto DEFLATE content
|
||||
int NetworkClient::skipGzipHeader(const uint8_t* data, size_t len) {
|
||||
if (len < 10) return -1;
|
||||
|
||||
if (data[0] != 0x1F || data[1] != 0x8B || data[2] != 8) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t pos = 10;
|
||||
uint8_t flags = data[3];
|
||||
|
||||
if (flags & 4) {
|
||||
if (pos + 2 > len) return -1;
|
||||
uint16_t xlen = data[pos] | (data[pos+1] << 8);
|
||||
pos += 2 + xlen;
|
||||
}
|
||||
|
||||
if (flags & 8) {
|
||||
while (pos < len && data[pos] != 0) pos++;
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (flags & 16) {
|
||||
while (pos < len && data[pos] != 0) pos++;
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (flags & 2) pos += 2;
|
||||
|
||||
if (pos >= len) return -1;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
// HTTP GET + GZIP Decompression (reading in chunks)
|
||||
bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& outLen) {
|
||||
|
||||
const size_t capacity = READLIMIT; // Read limit for data (can be adjusted in NetworkClient.h)
|
||||
uint8_t* buffer = (uint8_t*)malloc(capacity);
|
||||
|
||||
if (!buffer) {
|
||||
if (DEBUG) {Serial.println("Malloc failed (buffer");}
|
||||
return false;
|
||||
}
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
// Timeouts to prevent hanging connections
|
||||
http.setConnectTimeout(CONNECTIONTIMEOUT); // Connect timeout in ms (can be adjusted in NetworkClient.h)
|
||||
http.setTimeout(TCPREADTIMEOUT); // Read timeout in ms (can be adjusted in NetworkClient.h)
|
||||
|
||||
http.begin(url);
|
||||
http.addHeader("Accept-Encoding", "gzip");
|
||||
|
||||
int code = http.GET();
|
||||
if (code != HTTP_CODE_OK) {
|
||||
Serial.printf("HTTP ERROR: %d\n", code);
|
||||
|
||||
// Hard reset HTTP + socket
|
||||
WiFiClient* tmp = http.getStreamPtr();
|
||||
if (tmp) tmp->stop(); // Force close TCP socket
|
||||
http.end();
|
||||
|
||||
free(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
WiFiClient* stream = http.getStreamPtr();
|
||||
|
||||
size_t len = 0;
|
||||
uint32_t lastData = millis();
|
||||
const uint32_t READ_TIMEOUT = READDATATIMEOUT; // Timeout for reading data (can be adjusted in NetworkClient.h)
|
||||
|
||||
bool complete = false;
|
||||
|
||||
while (http.connected() && !complete) {
|
||||
|
||||
size_t avail = stream->available();
|
||||
|
||||
if (avail == 0) {
|
||||
if (millis() - lastData > READ_TIMEOUT) {
|
||||
Serial.println("TIMEOUT waiting for data!");
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len + avail > capacity)
|
||||
avail = capacity - len;
|
||||
|
||||
int read = stream->readBytes(buffer + len, avail);
|
||||
len += read;
|
||||
lastData = millis();
|
||||
|
||||
if (DEBUG) {Serial.printf("Read chunk: %d (total: %d)\n", read, (int)len);}
|
||||
|
||||
if (len < 20) continue; // Not enough data for header
|
||||
|
||||
int headerOffset = skipGzipHeader(buffer, len);
|
||||
if (headerOffset < 0) continue;
|
||||
|
||||
unsigned long testLen = len * 8; // Dynamic expansion
|
||||
uint8_t* test = (uint8_t*)malloc(testLen);
|
||||
|
||||
if (!test) continue;
|
||||
|
||||
unsigned long srcLen = len - headerOffset;
|
||||
|
||||
int res = puff(test, &testLen, buffer + headerOffset, &srcLen);
|
||||
if (res == 0) {
|
||||
if (DEBUG) {Serial.printf("Decompress OK! Size: %lu bytes\n", testLen);}
|
||||
outData = test;
|
||||
outLen = testLen;
|
||||
complete = true;
|
||||
break;
|
||||
}
|
||||
|
||||
free(test);
|
||||
}
|
||||
|
||||
// --- Added: Force-close connection in all cases to avoid stuck TCP sockets ---
|
||||
if (stream) stream->stop();
|
||||
|
||||
http.end();
|
||||
free(buffer);
|
||||
|
||||
if (!complete) {
|
||||
Serial.println("Failed to complete decompress.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decompress JSON
|
||||
bool NetworkClient::fetchAndDecompressJson(const String& url) {
|
||||
|
||||
_valid = false;
|
||||
|
||||
uint8_t* raw = nullptr;
|
||||
size_t rawLen = 0;
|
||||
|
||||
if (!httpGetGzip(url, raw, rawLen)) {
|
||||
Serial.println("GZIP download/decompress failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
DeserializationError err = deserializeJson(_doc, raw, rawLen);
|
||||
free(raw);
|
||||
|
||||
if (err) {
|
||||
Serial.printf("JSON ERROR: %s\n", err.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {Serial.println("JSON OK!");}
|
||||
_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
JsonDocument& NetworkClient::json() {
|
||||
return _doc;
|
||||
}
|
||||
|
||||
bool NetworkClient::isValid() const {
|
||||
return _valid;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
#include <ArduinoJson.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#define DEBUG false // Debug flag for NetworkClient for more live information
|
||||
#define READLIMIT 200000 // HTTP read limit in byte for gzip content (can be adjusted)
|
||||
#define CONNECTIONTIMEOUT 3000 // Timeout in ms for HTTP connection
|
||||
#define TCPREADTIMEOUT 2000 // Timeout in ms for read HTTP client stack
|
||||
#define READDATATIMEOUT 2000 // Timeout in ms for read data
|
||||
|
||||
class NetworkClient {
|
||||
public:
|
||||
NetworkClient(size_t reserveSize = 0);
|
||||
|
||||
bool fetchAndDecompressJson(const String& url);
|
||||
JsonDocument& json();
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
DynamicJsonDocument _doc;
|
||||
bool _valid;
|
||||
|
||||
int skipGzipHeader(const uint8_t* data, size_t len);
|
||||
bool httpGetGzip(const String& url, uint8_t*& outData, size_t& outLen);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <PCF8574.h> // Driver for PCF8574 output modul from Horter
|
||||
#include <Wire.h> // I2C
|
||||
#include <RTClib.h> // Driver for DS1388 RTC
|
||||
#include <PCF8574.h> // PCF8574 modules from Horter
|
||||
#include "SunRise.h" // Lib for sunrise and sunset calculation
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Hardware.h"
|
||||
@@ -24,40 +25,32 @@
|
||||
#include "fonts/Ubuntu_Bold20pt8b.h"
|
||||
#include "fonts/Ubuntu_Bold32pt8b.h"
|
||||
#include "fonts/Atari16px8b.h" // Key label font
|
||||
#include "fonts/IBM8x8px.h"
|
||||
#include "fonts/Atari6px8b.h" // Very small (6x6) font
|
||||
|
||||
// E-Ink Display
|
||||
// Definition for e-paper width an height refer OBP60Hardware.h
|
||||
#define GxEPD_WIDTH 400 // Display width
|
||||
#define GxEPD_HEIGHT 300 // Display height
|
||||
|
||||
#ifdef DISPLAY_GDEW042T2
|
||||
// Set display type and SPI pins for display
|
||||
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> display(GxEPD2_420(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
|
||||
// Export display in new funktion
|
||||
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay(){return display;}
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_GDEY042T81
|
||||
// Set display type and SPI pins for display
|
||||
GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> display(GxEPD2_420_GDEY042T81(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
|
||||
// Export display in new funktion
|
||||
GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> & getdisplay(){return display;}
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_GYE042A87
|
||||
// Set display type and SPI pins for display
|
||||
GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> display(GxEPD2_420_GYE042A87(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
|
||||
// Export display in new funktion
|
||||
GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay(){return display;}
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_SE0420NQ04
|
||||
// Set display type and SPI pins for display
|
||||
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> display(GxEPD2_420_SE0420NQ04(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
|
||||
// Export display in new funktion
|
||||
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(){return display;}
|
||||
#endif
|
||||
gxepd2display *epd = &display;
|
||||
|
||||
// Horter I2C moduls
|
||||
PCF8574 pcf8574_Modul1(PCF8574_I2C_ADDR1); // First digital IO modul PCF8574 from Horter
|
||||
PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter
|
||||
|
||||
// FRAM
|
||||
Adafruit_FRAM_I2C fram;
|
||||
@@ -70,6 +63,7 @@ sdmmc_card_t *sdcard;
|
||||
bool hasSDCard = false;
|
||||
|
||||
// Global vars
|
||||
bool heartbeat = false; // Heartbeat indicator with two different states
|
||||
bool blinkingLED = false; // Enable / disable blinking flash LED
|
||||
bool statusLED = false; // Actual status of flash LED on/off
|
||||
bool statusBacklightLED = false;// Actual status of flash LED on/off
|
||||
@@ -88,11 +82,10 @@ void hardwareInit(GwApi *api)
|
||||
|
||||
Wire.begin();
|
||||
// Init PCF8574 digital outputs
|
||||
Wire.setClock(I2C_SPEED_LOW); // Set I2C clock on 10 kHz
|
||||
if(pcf8574_Modul1.begin()){ // Initialize PCF8574
|
||||
pcf8574_Modul1.write8(255); // Clear all outputs (low activ)
|
||||
Wire.setClock(I2C_SPEED); // Set I2C clock as defined
|
||||
if(pcf8574_Out.begin()){ // Initialize PCF8574
|
||||
pcf8574_Out.write8(255); // Clear all outputs
|
||||
}
|
||||
Wire.setClock(I2C_SPEED); // Set I2C clock on 100 kHz
|
||||
fram = Adafruit_FRAM_I2C();
|
||||
if (esp_reset_reason() == ESP_RST_POWERON) {
|
||||
// help initialize FRAM
|
||||
@@ -193,28 +186,6 @@ void powerInit(String powermode) {
|
||||
}
|
||||
}
|
||||
|
||||
void setPCF8574PortPinModul1(uint8_t pin, uint8_t value)
|
||||
{
|
||||
static bool firstRunFinished;
|
||||
static uint8_t port1; // Retained data for port bits
|
||||
// If fisrt run then set all outputs to low
|
||||
if(firstRunFinished == false){
|
||||
port1 = 255; // Low active
|
||||
firstRunFinished = true;
|
||||
}
|
||||
if (pin > 7) return;
|
||||
Wire.setClock(I2C_SPEED_LOW); // Set I2C clock on 10 kHz for longer wires
|
||||
// Set bit
|
||||
if (pcf8574_Modul1.begin(port1)) // Check module availability and start it
|
||||
{
|
||||
if (value == LOW) port1 &= ~(1 << pin); // Set bit
|
||||
else port1 |= (1 << pin);
|
||||
pcf8574_Modul1.write8(port1); // Write byte
|
||||
}
|
||||
Wire.setClock(I2C_SPEED); // Set I2C clock on 100 kHz
|
||||
}
|
||||
|
||||
|
||||
void setPortPin(uint pin, bool value){
|
||||
pinMode(pin, OUTPUT);
|
||||
digitalWrite(pin, value);
|
||||
@@ -242,17 +213,17 @@ void deepSleep(CommonData &common){
|
||||
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
|
||||
epd->setFullWindow(); // Set full Refresh
|
||||
epd->fillScreen(common.bgcolor); // Clear screen
|
||||
epd->setTextColor(common.fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(85, 150);
|
||||
epd->print("Sleep Mode");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(65, 175);
|
||||
epd->print("To wake up press key and wait 5s");
|
||||
epd->nextPage(); // Update display contents
|
||||
epd->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
|
||||
@@ -266,18 +237,18 @@ void deepSleep(CommonData &common){
|
||||
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
|
||||
epd->setFullWindow(); // Set full Refresh
|
||||
//epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
epd->fillScreen(common.bgcolor); // Clear screen
|
||||
epd->setTextColor(common.fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(85, 150);
|
||||
epd->print("Sleep Mode");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(65, 175);
|
||||
epd->print("To wake up press wheel and wait 5s");
|
||||
epd->nextPage(); // Partial update
|
||||
epd->powerOff(); // Display power off
|
||||
setPortPin(OBP_POWER_EPD, false); // Power off ePaper display
|
||||
setPortPin(OBP_POWER_SD, false); // Power off SD card
|
||||
// Stop system
|
||||
@@ -322,65 +293,31 @@ void setBacklightLED(uint brightness, const Color &color){
|
||||
ledTaskData->setLedData(current);
|
||||
}
|
||||
|
||||
void toggleBacklightLED(uint brightness, const Color &color){
|
||||
void toggleBacklightLED(uint brightness, const Color &color) {
|
||||
if (ledTaskData == nullptr) return;
|
||||
statusBacklightLED = !statusBacklightLED;
|
||||
Color nv=setBrightness(statusBacklightLED?color:COLOR_BLACK,brightness);
|
||||
LedInterface current=ledTaskData->getLedData();
|
||||
Color nv = setBrightness(statusBacklightLED ? color : COLOR_BLACK, brightness);
|
||||
LedInterface current = ledTaskData->getLedData();
|
||||
current.setBacklight(nv);
|
||||
ledTaskData->setLedData(current);
|
||||
}
|
||||
|
||||
void stepsBacklightLED(uint brightness, const Color &color){
|
||||
static uint step = 0;
|
||||
uint actBrightness = 0;
|
||||
// Different brightness steps
|
||||
if(step == 0){
|
||||
actBrightness = brightness; // 100% from brightess
|
||||
statusBacklightLED = true;
|
||||
}
|
||||
if(step == 1){
|
||||
actBrightness = brightness * 0.5; // 50% from brightess
|
||||
statusBacklightLED = true;
|
||||
}
|
||||
if(step == 2){
|
||||
actBrightness = brightness * 0.2; // 20% from brightess
|
||||
statusBacklightLED = true;
|
||||
}
|
||||
if(step == 3){
|
||||
actBrightness = 0; // 0%
|
||||
statusBacklightLED = false;
|
||||
}
|
||||
if(actBrightness < 5){ // Limiter if values too low
|
||||
actBrightness = 5;
|
||||
}
|
||||
step = step + 1; // Increment step counter
|
||||
if(step == 4){ // Reset counter
|
||||
step = 0;
|
||||
}
|
||||
void setFlashLED(bool status) {
|
||||
if (ledTaskData == nullptr) return;
|
||||
Color nv=setBrightness(statusBacklightLED?color:COLOR_BLACK,actBrightness);
|
||||
LedInterface current=ledTaskData->getLedData();
|
||||
current.setBacklight(nv);
|
||||
ledTaskData->setLedData(current);
|
||||
}
|
||||
|
||||
void setFlashLED(bool status){
|
||||
if (ledTaskData == nullptr) return;
|
||||
Color c=status?COLOR_RED:COLOR_BLACK;
|
||||
LedInterface current=ledTaskData->getLedData();
|
||||
Color c = status ? COLOR_RED : COLOR_BLACK;
|
||||
LedInterface current = ledTaskData->getLedData();
|
||||
current.setFlash(c);
|
||||
ledTaskData->setLedData(current);
|
||||
}
|
||||
|
||||
void blinkingFlashLED(){
|
||||
if(blinkingLED == true){
|
||||
void blinkingFlashLED() {
|
||||
if (blinkingLED == true) {
|
||||
statusLED = !statusLED; // Toggle LED for each run
|
||||
setFlashLED(statusLED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setBlinkingLED(bool status){
|
||||
void setBlinkingLED(bool status) {
|
||||
blinkingLED = status;
|
||||
}
|
||||
|
||||
@@ -410,26 +347,29 @@ void setBuzzerPower(uint power){
|
||||
buzzerpower = power;
|
||||
}
|
||||
|
||||
// Delete xdr prefix from string
|
||||
String xdrDelete(String input){
|
||||
if(input.substring(0,3) == "xdr"){
|
||||
// Delete xdr prefix from string and optional limit length
|
||||
String xdrDelete(String input, uint8_t maxlen) {
|
||||
if (input.substring(0, 3) == "xdr") {
|
||||
input = input.substring(3, input.length());
|
||||
}
|
||||
if (maxlen > 0) {
|
||||
return input.substring(0, maxlen);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
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);
|
||||
epd->fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
|
||||
epd->fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
|
||||
}
|
||||
|
||||
void drawPoly(const std::vector<Point>& points, uint16_t color) {
|
||||
size_t polysize = points.size();
|
||||
for (size_t i = 0; i < polysize - 1; i++) {
|
||||
getdisplay().drawLine(points[i].x, points[i].y, points[i+1].x, points[i+1].y, color);
|
||||
epd->drawLine(points[i].x, points[i].y, points[i+1].x, points[i+1].y, color);
|
||||
}
|
||||
// close path
|
||||
getdisplay().drawLine(points[polysize-1].x, points[polysize-1].y, points[0].x, points[0].y, color);
|
||||
epd->drawLine(points[polysize-1].x, points[polysize-1].y, points[0].x, points[0].y, color);
|
||||
}
|
||||
|
||||
// Split string into words, whitespace separated
|
||||
@@ -479,73 +419,51 @@ std::vector<String> wordwrap(String &line, uint16_t maxwidth) {
|
||||
void drawTextCenter(int16_t cx, int16_t cy, String text) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
|
||||
getdisplay().setCursor(cx - w / 2, cy + h / 2);
|
||||
getdisplay().print(text);
|
||||
}
|
||||
|
||||
// Draw centered botton with centered text
|
||||
void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, uint16_t fg, uint16_t bg, bool inverted) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
uint16_t color;
|
||||
|
||||
getdisplay().getTextBounds(text, cx, cy, &x1, &y1, &w, &h); // Find text center
|
||||
getdisplay().setCursor(cx - w/2, cy + h/2); // Set cursor to center
|
||||
//getdisplay().drawPixel(cx, cy, fg); // Debug pixel for center position
|
||||
if (inverted) {
|
||||
getdisplay().fillRoundRect(cx - sx / 2, cy - sy / 2, sx, sy, 5, fg); // Draw button
|
||||
getdisplay().setTextColor(bg);
|
||||
getdisplay().print(text); // Draw text
|
||||
}
|
||||
else{
|
||||
getdisplay().drawRoundRect(cx - sx / 2, cy - sy / 2, sx, sy, 5, fg); // Draw button
|
||||
getdisplay().setTextColor(fg);
|
||||
getdisplay().print(text); // Draw text
|
||||
}
|
||||
epd->getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
|
||||
epd->setCursor(cx - w / 2, cy + h / 2);
|
||||
epd->print(text);
|
||||
}
|
||||
|
||||
// Draw right aligned text
|
||||
void drawTextRalign(int16_t x, int16_t y, String text) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
|
||||
getdisplay().setCursor(x - w - 1, y); // '-1' required since some strings wrap around w/o it
|
||||
getdisplay().print(text);
|
||||
epd->getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
|
||||
epd->setCursor(x - w, y);
|
||||
epd->print(text);
|
||||
}
|
||||
|
||||
// Draw text inside box, normal or inverted
|
||||
void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border) {
|
||||
if (inverted) {
|
||||
getdisplay().fillRect(box.x, box.y, box.w, box.h, fg);
|
||||
getdisplay().setTextColor(bg);
|
||||
epd->fillRect(box.x, box.y, box.w, box.h, fg);
|
||||
epd->setTextColor(bg);
|
||||
} else {
|
||||
if (border) {
|
||||
getdisplay().fillRect(box.x + 1, box.y + 1, box.w - 2, box.h - 2, bg);
|
||||
getdisplay().drawRect(box.x, box.y, box.w, box.h, fg);
|
||||
epd->fillRect(box.x + 1, box.y + 1, box.w - 2, box.h - 2, bg);
|
||||
epd->drawRect(box.x, box.y, box.w, box.h, fg);
|
||||
}
|
||||
getdisplay().setTextColor(fg);
|
||||
epd->setTextColor(fg);
|
||||
}
|
||||
uint16_t border_offset = box.h / 4; // 25% of box height
|
||||
getdisplay().setCursor(box.x + border_offset, box.y + box.h - border_offset);
|
||||
getdisplay().print(text);
|
||||
getdisplay().setTextColor(fg);
|
||||
epd->setCursor(box.x + border_offset, box.y + box.h - border_offset);
|
||||
epd->print(text);
|
||||
epd->setTextColor(fg);
|
||||
}
|
||||
|
||||
// Show a triangle for trend direction high (x, y is the left edge)
|
||||
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){
|
||||
getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color);
|
||||
epd->fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color);
|
||||
}
|
||||
|
||||
// Show a triangle for trend direction low (x, y is the left edge)
|
||||
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color){
|
||||
getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y+size*2, color);
|
||||
epd->fillTriangle(x, y, x+size*2, y, x+size, y+size*2, color);
|
||||
}
|
||||
|
||||
// Show header informations
|
||||
void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop){
|
||||
void displayHeader(CommonData &commonData, bool symbolmode, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop){
|
||||
|
||||
static bool heartbeat = false;
|
||||
static unsigned long usbRxOld = 0;
|
||||
static unsigned long usbTxOld = 0;
|
||||
static unsigned long serRxOld = 0;
|
||||
@@ -557,31 +475,65 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
||||
static unsigned long n2kRxOld = 0;
|
||||
static unsigned long n2kTxOld = 0;
|
||||
|
||||
uint16_t symbol_x = 2;
|
||||
static const uint16_t symbol_offset = 20;
|
||||
|
||||
// TODO invert and get rid of the if
|
||||
if(commonData.config->getBool(commonData.config->statusLine) == true){
|
||||
|
||||
// Show status info
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(0, 15);
|
||||
if(commonData.status.wifiApOn){
|
||||
getdisplay().print(" AP ");
|
||||
epd->setTextColor(commonData.fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(0, 15);
|
||||
if (commonData.status.wifiApOn) {
|
||||
if (symbolmode) {
|
||||
epd->drawXBitmap(symbol_x, 1, iconmap["AP"], icon_width, icon_height, commonData.fgcolor);
|
||||
symbol_x += symbol_offset;
|
||||
} else {
|
||||
epd->print(" AP ");
|
||||
}
|
||||
}
|
||||
// If receive new telegram data then display bus name
|
||||
if(commonData.status.tcpClRx != tcpClRxOld || commonData.status.tcpClTx != tcpClTxOld || commonData.status.tcpSerRx != tcpSerRxOld || commonData.status.tcpSerTx != tcpSerTxOld){
|
||||
getdisplay().print("TCP ");
|
||||
if (symbolmode) {
|
||||
epd->drawXBitmap(symbol_x, 1, iconmap["TCP"], icon_width, icon_height, commonData.fgcolor);
|
||||
symbol_x += symbol_offset;
|
||||
} else {
|
||||
epd->print("TCP ");
|
||||
}
|
||||
}
|
||||
if(commonData.status.n2kRx != n2kRxOld || commonData.status.n2kTx != n2kTxOld){
|
||||
getdisplay().print("N2K ");
|
||||
if (symbolmode) {
|
||||
epd->drawXBitmap(symbol_x, 1, iconmap["N2K"], icon_width, icon_height, commonData.fgcolor);
|
||||
symbol_x += symbol_offset;
|
||||
} else {
|
||||
epd->print("N2K ");
|
||||
}
|
||||
}
|
||||
if(commonData.status.serRx != serRxOld || commonData.status.serTx != serTxOld){
|
||||
getdisplay().print("183 ");
|
||||
if (symbolmode) {
|
||||
epd->drawXBitmap(symbol_x, 1, iconmap["0183"], icon_width, icon_height, commonData.fgcolor);
|
||||
symbol_x += symbol_offset;
|
||||
} else {
|
||||
epd->print("183 ");
|
||||
}
|
||||
}
|
||||
if(commonData.status.usbRx != usbRxOld || commonData.status.usbTx != usbTxOld){
|
||||
getdisplay().print("USB ");
|
||||
if (symbolmode) {
|
||||
epd->drawXBitmap(symbol_x, 1, iconmap["USB"], icon_width, icon_height, commonData.fgcolor);
|
||||
symbol_x += symbol_offset;
|
||||
} else {
|
||||
epd->print("USB ");
|
||||
}
|
||||
}
|
||||
double gpshdop = formatValue(hdop, commonData).value;
|
||||
double gpshdop = commonData.fmt->formatValue(hdop, commonData).value;
|
||||
if(commonData.config->getString(commonData.config->useGPS) != "off" && gpshdop <= commonData.config->getInt(commonData.config->hdopAccuracy) && hdop->valid == true){
|
||||
getdisplay().print("GPS");
|
||||
if (symbolmode) {
|
||||
epd->drawXBitmap(symbol_x, 1, iconmap["GPS"], icon_width, icon_height, commonData.fgcolor);
|
||||
symbol_x += symbol_offset;
|
||||
} else {
|
||||
epd->print("GPS");
|
||||
}
|
||||
}
|
||||
// Save old telegram counter
|
||||
tcpClRxOld = commonData.status.tcpClRx;
|
||||
@@ -598,26 +550,26 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
||||
#ifdef HARDWARE_V21
|
||||
// Display key lock status
|
||||
if (commonData.keylock) {
|
||||
getdisplay().drawXBitmap(170, 1, lock_bits, icon_width, icon_height, commonData.fgcolor);
|
||||
epd->drawXBitmap(170, 1, lock_bits, icon_width, icon_height, commonData.fgcolor);
|
||||
} else {
|
||||
getdisplay().drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor);
|
||||
epd->drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor);
|
||||
}
|
||||
#endif
|
||||
#ifdef LIPO_ACCU_1200
|
||||
if (commonData.data.BatteryChargeStatus == 1) {
|
||||
getdisplay().drawXBitmap(170, 1, battery_loading_bits, battery_width, battery_height, commonData.fgcolor);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->drawXBitmap(170, 1, battery_100_bits, battery_width, battery_height, commonData.fgcolor);
|
||||
}
|
||||
#endif // VOLTAGE_SENSOR
|
||||
}
|
||||
@@ -625,33 +577,33 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
||||
|
||||
// Heartbeat as page number
|
||||
if (heartbeat) {
|
||||
getdisplay().setTextColor(commonData.bgcolor);
|
||||
getdisplay().fillRect(201, 0, 23, 19, commonData.fgcolor);
|
||||
epd->setTextColor(commonData.bgcolor);
|
||||
epd->fillRect(201, 0, 23, 19, commonData.fgcolor);
|
||||
} else {
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
getdisplay().drawRect(201, 0, 23, 19, commonData.fgcolor);
|
||||
epd->setTextColor(commonData.fgcolor);
|
||||
epd->drawRect(201, 0, 23, 19, commonData.fgcolor);
|
||||
}
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
drawTextCenter(211, 9, String(commonData.data.actpage));
|
||||
heartbeat = !heartbeat;
|
||||
|
||||
// Date and time
|
||||
String fmttype = commonData.config->getString(commonData.config->dateFormat);
|
||||
fmtDate fmttype = commonData.fmt->getDateFormat(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().setCursor(230, 15);
|
||||
epd->setTextColor(commonData.fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->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");
|
||||
epd->print(formatTime(fmtTime::MMHH, local_tm->tm_hour, local_tm->tm_min, 0));
|
||||
epd->print(" ");
|
||||
epd->print(formatDate(fmttype, local_tm->tm_year + 1900, local_tm->tm_mon + 1, local_tm->tm_mday));
|
||||
epd->print(" ");
|
||||
epd->print(tz == 0 ? "UTC" : "LOT");
|
||||
} else {
|
||||
drawTextRalign(396, 15, "RTC invalid");
|
||||
}
|
||||
@@ -659,18 +611,18 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
||||
else if (timesource == "GPS") {
|
||||
// Show date and time if date present
|
||||
if(date->valid == true){
|
||||
String acttime = formatValue(time, commonData).svalue;
|
||||
String acttime = commonData.fmt->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");
|
||||
String actdate = commonData.fmt->formatValue(date, commonData).svalue;
|
||||
epd->print(acttime);
|
||||
epd->print(" ");
|
||||
epd->print(actdate);
|
||||
epd->print(" ");
|
||||
epd->print(tz == 0 ? "UTC" : "LOT");
|
||||
}
|
||||
else{
|
||||
if(commonData.config->getBool(commonData.config->useSimuData) == true){
|
||||
getdisplay().print("12:00 01.01.2024 LOT");
|
||||
epd->print("12:00 01.01.2024 LOT");
|
||||
}
|
||||
else{
|
||||
drawTextRalign(396, 15, "No GPS data");
|
||||
@@ -678,15 +630,15 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
||||
}
|
||||
} // timesource == "GPS"
|
||||
else {
|
||||
getdisplay().print("No time source");
|
||||
epd->print("No time source");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayFooter(CommonData &commonData) {
|
||||
|
||||
getdisplay().setFont(&Atari16px);
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
epd->setFont(&Atari16px);
|
||||
epd->setTextColor(commonData.fgcolor);
|
||||
|
||||
#ifdef HARDWARE_V21
|
||||
// Frame around key icon area
|
||||
@@ -695,14 +647,14 @@ void displayFooter(CommonData &commonData) {
|
||||
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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->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;
|
||||
@@ -713,7 +665,7 @@ void displayFooter(CommonData &commonData) {
|
||||
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);
|
||||
epd->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;
|
||||
@@ -728,8 +680,8 @@ void displayFooter(CommonData &commonData) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getdisplay().setCursor(65, 295);
|
||||
getdisplay().print("Press 1 and 6 fast to unlock keys");
|
||||
epd->setCursor(65, 295);
|
||||
epd->print("Press 1 and 6 fast to unlock keys");
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
@@ -740,21 +692,21 @@ void displayFooter(CommonData &commonData) {
|
||||
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);
|
||||
epd->fillCircle(x0 + i * (r * 2 + space), 290, r, commonData.fgcolor);
|
||||
} else {
|
||||
getdisplay().drawCircle(x0 + i * (r * 2 + space), 290, r, commonData.fgcolor);
|
||||
epd->drawCircle(x0 + i * (r * 2 + space), 290, r, commonData.fgcolor);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
epd->drawLine(0, 280, 10, 280, commonData.fgcolor);
|
||||
epd->drawLine(55, 280, 65, 280, commonData.fgcolor);
|
||||
epd->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);
|
||||
epd->drawLine(390, 280, 399, 280, commonData.fgcolor);
|
||||
epd->drawLine(335, 280, 345, 280, commonData.fgcolor);
|
||||
epd->drawLine(335, 280, 335, 399, commonData.fgcolor);
|
||||
drawTextCenter(366, 291, commonData.keydata[1].label);
|
||||
#endif
|
||||
}
|
||||
@@ -767,31 +719,31 @@ void displayAlarm(CommonData &commonData) {
|
||||
const uint16_t w = 300;
|
||||
const uint16_t h = 150;
|
||||
|
||||
getdisplay().setFont(&Atari16px);
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
epd->setFont(&Atari16px);
|
||||
epd->setTextColor(commonData.fgcolor);
|
||||
|
||||
// overlay
|
||||
getdisplay().drawRect(x, y, w, h, commonData.fgcolor);
|
||||
getdisplay().fillRect(x + 1, y + 1, w - 1, h - 1, commonData.bgcolor);
|
||||
getdisplay().drawRect(x + 3, y + 3, w - 5, h - 5, commonData.fgcolor);
|
||||
epd->drawRect(x, y, w, h, commonData.fgcolor);
|
||||
epd->fillRect(x + 1, y + 1, w - 1, h - 1, commonData.bgcolor);
|
||||
epd->drawRect(x + 3, y + 3, w - 5, h - 5, commonData.fgcolor);
|
||||
|
||||
// exclamation icon in left top corner
|
||||
getdisplay().drawXBitmap(x + 16, y + 16, exclamation_bits, exclamation_width, exclamation_height, commonData.fgcolor);
|
||||
epd->drawXBitmap(x + 16, y + 16, exclamation_bits, exclamation_width, exclamation_height, commonData.fgcolor);
|
||||
|
||||
// title
|
||||
getdisplay().setCursor(x + 64, y + 30);
|
||||
getdisplay().print("A L A R M");
|
||||
getdisplay().setCursor(x + 64, y + 48);
|
||||
getdisplay().print("#" + commonData.alarm.id);
|
||||
getdisplay().print(" from ");
|
||||
getdisplay().print(commonData.alarm.source);
|
||||
epd->setCursor(x + 64, y + 30);
|
||||
epd->print("A L A R M");
|
||||
epd->setCursor(x + 64, y + 48);
|
||||
epd->print("#" + commonData.alarm.id);
|
||||
epd->print(" from ");
|
||||
epd->print(commonData.alarm.source);
|
||||
|
||||
// message, but maximum 4 lines
|
||||
std::vector<String> lines = wordwrap (commonData.alarm.message, w - 16 - 8 / 8);
|
||||
int n = 0;
|
||||
for (const auto& l : lines) {
|
||||
getdisplay().setCursor(x + 16, y + 80 + n);
|
||||
getdisplay().print(l);
|
||||
epd->setCursor(x + 16, y + 80 + n);
|
||||
epd->print(l);
|
||||
n += 16;
|
||||
if (n > 64) {
|
||||
break;
|
||||
@@ -884,20 +836,20 @@ void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor){
|
||||
}
|
||||
// Battery corpus 100x80 with fill level
|
||||
int level = int((100.0 - percent) * (80-(2*t)) / 100.0);
|
||||
getdisplay().fillRect(xb, yb, 100, 80, pcolor);
|
||||
epd->fillRect(xb, yb, 100, 80, pcolor);
|
||||
if(percent < 99){
|
||||
getdisplay().fillRect(xb+t, yb+t, 100-(2*t), level, bcolor);
|
||||
epd->fillRect(xb+t, yb+t, 100-(2*t), level, bcolor);
|
||||
}
|
||||
// Plus pol 20x15
|
||||
int xp = xb + 20;
|
||||
int yp = yb - 15 + t;
|
||||
getdisplay().fillRect(xp, yp, 20, 15, pcolor);
|
||||
getdisplay().fillRect(xp+t, yp+t, 20-(2*t), 15-(2*t), bcolor);
|
||||
epd->fillRect(xp, yp, 20, 15, pcolor);
|
||||
epd->fillRect(xp+t, yp+t, 20-(2*t), 15-(2*t), bcolor);
|
||||
// Minus pol 20x15
|
||||
int xm = xb + 60;
|
||||
int ym = yb -15 + t;
|
||||
getdisplay().fillRect(xm, ym, 20, 15, pcolor);
|
||||
getdisplay().fillRect(xm+t, ym+t, 20-(2*t), 15-(2*t), bcolor);
|
||||
epd->fillRect(xm, ym, 20, 15, pcolor);
|
||||
epd->fillRect(xm+t, ym+t, 20-(2*t), 15-(2*t), bcolor);
|
||||
}
|
||||
|
||||
// Solar graphic with fill level
|
||||
@@ -909,17 +861,17 @@ void solarGraphic(uint x, uint y, int pcolor, int bcolor){
|
||||
int percent = 0;
|
||||
// Solar corpus 100x80
|
||||
int level = int((100.0 - percent) * (80-(2*t)) / 100.0);
|
||||
getdisplay().fillRect(xb, yb, 100, 80, pcolor);
|
||||
epd->fillRect(xb, yb, 100, 80, pcolor);
|
||||
if(percent < 99){
|
||||
getdisplay().fillRect(xb+t, yb+t, 100-(2*t), level, bcolor);
|
||||
epd->fillRect(xb+t, yb+t, 100-(2*t), level, bcolor);
|
||||
}
|
||||
// Draw horizontel lines
|
||||
getdisplay().fillRect(xb, yb+28-t, 100, t, pcolor);
|
||||
getdisplay().fillRect(xb, yb+54-t, 100, t, pcolor);
|
||||
epd->fillRect(xb, yb+28-t, 100, t, pcolor);
|
||||
epd->fillRect(xb, yb+54-t, 100, t, pcolor);
|
||||
// Draw vertical lines
|
||||
getdisplay().fillRect(xb+19+t, yb, t, 80, pcolor);
|
||||
getdisplay().fillRect(xb+39+2*t, yb, t, 80, pcolor);
|
||||
getdisplay().fillRect(xb+59+3*t, yb, t, 80, pcolor);
|
||||
epd->fillRect(xb+19+t, yb, t, 80, pcolor);
|
||||
epd->fillRect(xb+39+2*t, yb, t, 80, pcolor);
|
||||
epd->fillRect(xb+59+3*t, yb, t, 80, pcolor);
|
||||
|
||||
}
|
||||
|
||||
@@ -931,13 +883,13 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
|
||||
int t = 4; // Line thickness
|
||||
|
||||
// Generator corpus with radius 45
|
||||
getdisplay().fillCircle(xb, yb, 45, pcolor);
|
||||
getdisplay().fillCircle(xb, yb, 41, bcolor);
|
||||
epd->fillCircle(xb, yb, 45, pcolor);
|
||||
epd->fillCircle(xb, yb, 41, bcolor);
|
||||
// Insert G
|
||||
getdisplay().setTextColor(pcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold32pt8b);
|
||||
getdisplay().setCursor(xb-22, yb+20);
|
||||
getdisplay().print("G");
|
||||
epd->setTextColor(pcolor);
|
||||
epd->setFont(&Ubuntu_Bold32pt8b);
|
||||
epd->setCursor(xb-22, yb+20);
|
||||
epd->print("G");
|
||||
}
|
||||
|
||||
// Function to handle HTTP image request
|
||||
@@ -951,7 +903,7 @@ void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUM
|
||||
|
||||
logger->logDebug(GwLog::LOG,"handle image request [%s]: %s", imgformat, filename);
|
||||
|
||||
uint8_t *fb = getdisplay().getBuffer(); // EPD framebuffer
|
||||
uint8_t *fb = epd->getBuffer(); // EPD framebuffer
|
||||
std::vector<uint8_t> imageBuffer; // image in webserver transferbuffer
|
||||
String mimetype;
|
||||
|
||||
@@ -974,37 +926,11 @@ void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUM
|
||||
createPBM(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
|
||||
}
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, mimetype, (const uint8_t*)imageBuffer.data(), imageBuffer.size());
|
||||
AsyncWebServerResponse *response = request->beginResponse(200, mimetype, (const uint8_t*)imageBuffer.data(), imageBuffer.size());
|
||||
response->addHeader("Content-Disposition", "inline; filename=" + filename);
|
||||
request->send(response);
|
||||
|
||||
imageBuffer.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Calculate the distance between two Geo coordinates
|
||||
double distanceBetweenCoordinates(double lat1, double lon1, double lat2, double lon2) {
|
||||
// Grad → Radiant
|
||||
double lat1Rad = lat1 * DEG_TO_RAD;
|
||||
double lon1Rad = lon1 * DEG_TO_RAD;
|
||||
double lat2Rad = lat2 * DEG_TO_RAD;
|
||||
double lon2Rad = lon2 * DEG_TO_RAD;
|
||||
|
||||
// Differenzen
|
||||
double dLat = lat2Rad - lat1Rad;
|
||||
double dLon = lon2Rad - lon1Rad;
|
||||
|
||||
// Haversine-Formel
|
||||
double a = sin(dLat / 2.0) * sin(dLat / 2.0) +
|
||||
cos(lat1Rad) * cos(lat2Rad) *
|
||||
sin(dLon / 2.0) * sin(dLon / 2.0);
|
||||
|
||||
double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a));
|
||||
|
||||
// Abstand in Metern
|
||||
return double(EARTH_RADIUS) * c;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#ifndef _OBP60EXTENSIONPORT_H
|
||||
#define _OBP60EXTENSIONPORT_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "OBP60Hardware.h"
|
||||
#include "OBP60Formatter.h"
|
||||
#include "LedSpiTask.h"
|
||||
#include "Graphics.h"
|
||||
#include <GxEPD2_BW.h> // E-paper lib V2
|
||||
#include <Adafruit_FRAM_I2C.h> // I2C FRAM
|
||||
#include <math.h>
|
||||
|
||||
#ifdef BOARD_OBP40S3
|
||||
#include "esp_vfs_fat.h"
|
||||
@@ -31,9 +32,6 @@
|
||||
#define FRAM_BAROGRAPH_START 0x0400
|
||||
#define FRAM_BAROGRAPH_END 0x13FF
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define EARTH_RADIUS 6371000.0
|
||||
|
||||
extern Adafruit_FRAM_I2C fram;
|
||||
extern bool hasFRAM;
|
||||
extern bool hasSDCard;
|
||||
@@ -41,6 +39,8 @@ extern bool hasSDCard;
|
||||
extern sdmmc_card_t *sdcard;
|
||||
#endif
|
||||
|
||||
extern bool heartbeat;
|
||||
|
||||
// Fonts declarations for display (#includes see OBP60Extensions.cpp)
|
||||
extern const GFXfont DSEG7Classic_BoldItalic16pt7b;
|
||||
extern const GFXfont DSEG7Classic_BoldItalic20pt7b;
|
||||
@@ -55,24 +55,22 @@ extern const GFXfont Ubuntu_Bold16pt8b;
|
||||
extern const GFXfont Ubuntu_Bold20pt8b;
|
||||
extern const GFXfont Ubuntu_Bold32pt8b;
|
||||
extern const GFXfont Atari16px;
|
||||
extern const GFXfont IBM8x8px;
|
||||
extern const GFXfont Atari6px;
|
||||
|
||||
// Global functions
|
||||
#ifdef DISPLAY_GDEW042T2
|
||||
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay();
|
||||
typedef GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> gxepd2display;
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_GDEY042T81
|
||||
GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> & getdisplay();
|
||||
typedef GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> gxepd2display;
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_GYE042A87
|
||||
GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay();
|
||||
typedef GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> gxepd2display;
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_SE0420NQ04
|
||||
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
|
||||
typedef GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> gxepd2display;
|
||||
#endif
|
||||
extern gxepd2display *epd;
|
||||
|
||||
// Page display return values
|
||||
#define PAGE_OK 0 // all ok, do nothing
|
||||
@@ -89,14 +87,13 @@ uint8_t getLastPage();
|
||||
void hardwareInit(GwApi *api);
|
||||
void powerInit(String powermode);
|
||||
|
||||
void setPCF8574PortPinModul1(uint8_t pin, uint8_t value);// Set PCF8574 port pin
|
||||
void setPortPin(uint pin, bool value); // Set port pin for extension port
|
||||
|
||||
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
|
||||
void stepsBacklightLED(uint brightness, const Color &color);// Set backlight LEDs in 4 steps (100%, 50%, 10%, 0%)
|
||||
BacklightMode backlightMapping(const String &backlightString);// Configuration string to value
|
||||
|
||||
void setFlashLED(bool status); // Set flash LED
|
||||
@@ -106,17 +103,16 @@ void setBlinkingLED(bool on); // Set blinking flash LED active
|
||||
void buzzer(uint frequency, uint duration); // Buzzer function
|
||||
void setBuzzerPower(uint power); // Set buzzer power
|
||||
|
||||
String xdrDelete(String input); // Delete xdr prefix from string
|
||||
String xdrDelete(String input, uint8_t maxlen = 0); // Delete xdr prefix from string and optional limit length
|
||||
|
||||
void drawTextCenter(int16_t cx, int16_t cy, String text);
|
||||
void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, uint16_t fg, uint16_t bg, bool inverted);
|
||||
void drawTextRalign(int16_t x, int16_t y, String text);
|
||||
void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border);
|
||||
|
||||
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 displayHeader(CommonData &commonData, bool symbolmode, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop); // Draw display header
|
||||
void displayFooter(CommonData &commonData);
|
||||
void displayAlarm(CommonData &commonData);
|
||||
|
||||
@@ -164,24 +160,62 @@ static unsigned char fram_bits[] PROGMEM = {
|
||||
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[] PROGMEM = {
|
||||
// Header symbols
|
||||
|
||||
static unsigned char ap_bits[] PROGMEM= {
|
||||
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 = {
|
||||
static unsigned char gps_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 unsigned char nmea_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0x22, 0x21, 0x26, 0x33, 0x26, 0x33, 0x2a, 0x2d, 0x32, 0x2d,
|
||||
0x32, 0x21, 0x22, 0x21, 0x00, 0x00, 0x3c, 0x0c, 0x04, 0x0c, 0x04, 0x12,
|
||||
0x3c, 0x12, 0x04, 0x1e, 0x04, 0x21, 0x3c, 0x21 };
|
||||
|
||||
static unsigned char n2k_bits[] PROGMEM = {
|
||||
0xe0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x02, 0x40, 0x32, 0x4c, 0x31, 0x8c,
|
||||
0x01, 0x80, 0x81, 0x81, 0x81, 0x81, 0x01, 0x80, 0x31, 0x8c, 0x32, 0x4c,
|
||||
0x02, 0x40, 0x04, 0x20, 0x98, 0x19, 0xe0, 0x07 };
|
||||
|
||||
static unsigned char tcp_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0xe0, 0x03, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xe0, 0x03,
|
||||
0x80, 0x00, 0x80, 0x00, 0xff, 0xff, 0x08, 0x10, 0x08, 0x10, 0x3e, 0x7c,
|
||||
0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x3e, 0x7c };
|
||||
|
||||
static unsigned char usb_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0x92, 0x39, 0x52, 0x4a, 0x52, 0x48, 0x92, 0x39, 0x12, 0x4a,
|
||||
0x52, 0x4a, 0x8c, 0x39, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x04, 0x20,
|
||||
0xf4, 0x2f, 0x04, 0x20, 0xf8, 0x1f, 0x00, 0x00 };
|
||||
|
||||
static unsigned char sdcard_bits[] PROGMEM = {
|
||||
0xf8, 0x07, 0x0c, 0x08, 0x04, 0x08, 0xc4, 0x09, 0x24, 0x1a, 0xe4, 0x13,
|
||||
0x04, 0x20, 0x24, 0x21, 0xa4, 0x12, 0x44, 0x12, 0x04, 0x20, 0x04, 0x20,
|
||||
0xc4, 0x23, 0x34, 0x2c, 0xd8, 0x1b, 0x00, 0x00 };
|
||||
|
||||
static unsigned char bluetooth_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0x22, 0x21, 0x26, 0x33, 0x26, 0x33, 0x2a, 0x2d, 0x32, 0x2d,
|
||||
0x32, 0x21, 0x22, 0x21, 0x00, 0x00, 0x3c, 0x0c, 0x04, 0x0c, 0x04, 0x12,
|
||||
0x3c, 0x12, 0x04, 0x1e, 0x04, 0x21, 0x3c, 0x21 };
|
||||
|
||||
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}
|
||||
{"GPS", gps_bits},
|
||||
{"AP", ap_bits},
|
||||
{"0183", nmea_bits},
|
||||
{"N2K", n2k_bits},
|
||||
{"TCP", tcp_bits},
|
||||
{"USB", usb_bits},
|
||||
{"SDCARD", sdcard_bits},
|
||||
{"BLUE", bluetooth_bits}
|
||||
};
|
||||
|
||||
// Battery
|
||||
|
||||
@@ -3,115 +3,82 @@
|
||||
#include <Arduino.h>
|
||||
#include "GwApi.h"
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Formatter.h"
|
||||
|
||||
// ToDo
|
||||
// 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);
|
||||
Formatter::Formatter(GwConfigHandler *config) {
|
||||
// Load configuration values
|
||||
// TODO do not use strings but enums, see header file
|
||||
stimeZone = config->getString(config->timeZone);
|
||||
timeZone = stimeZone.toDouble();
|
||||
lengthFormat = config->getString(config->lengthFormat);
|
||||
distanceFormat = config->getString(config->distanceFormat);
|
||||
speedFormat = config->getString(config->speedFormat);
|
||||
windspeedFormat = config->getString(config->windspeedFormat);
|
||||
tempFormat = config->getString(config->tempFormat);
|
||||
dateFormat = config->getString(config->dateFormat);
|
||||
dateFmt = getDateFormat(dateFormat);
|
||||
usesimudata = config->getBool(config->useSimuData);
|
||||
precision = config->getString(config->valueprecision);
|
||||
|
||||
if (precision == "1") {
|
||||
fmt_dec_1 = "%3.1f";
|
||||
fmt_dec_10 = "%3.0f";
|
||||
fmt_dec_100 = "%3.0f";
|
||||
} else {
|
||||
fmt_dec_1 = "%3.2f";
|
||||
fmt_dec_10 = "%3.1f";
|
||||
fmt_dec_100 = "%3.0f";
|
||||
}
|
||||
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);
|
||||
fmtType Formatter::stringToFormat(const char* formatStr) {
|
||||
auto it = formatMap.find(formatStr);
|
||||
if (it != formatMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, 10, "%02d:%02d:%02d", hour, minute, second);
|
||||
return fmtType::XDR_G; // generic as default
|
||||
}
|
||||
|
||||
fmtDate Formatter::getDateFormat(String sformat) {
|
||||
if (sformat == "DE") {
|
||||
return fmtDate::DE;
|
||||
}
|
||||
return String(buffer);
|
||||
if (sformat == "GB") {
|
||||
return fmtDate::GB;
|
||||
}
|
||||
if (sformat == "US") {
|
||||
return fmtDate::US;
|
||||
}
|
||||
return fmtDate::ISO; // default
|
||||
}
|
||||
|
||||
String formatLatitude(double lat) {
|
||||
float degree = abs(int(lat));
|
||||
float minute = abs((lat - int(lat)) * 60);
|
||||
return String(degree, 0) + "\x90 " + String(minute, 4) + "' " + ((lat > 0) ? "N" : "S");
|
||||
fmtTime Formatter::getTimeFormat(String sformat) {
|
||||
if (sformat == "MMHH") {
|
||||
return fmtTime::MMHH;
|
||||
}
|
||||
if (sformat == "MMHHSS") {
|
||||
return fmtTime::MMHHSS;
|
||||
}
|
||||
return fmtTime::MMHH; // default
|
||||
}
|
||||
|
||||
String formatLongitude(double lon) {
|
||||
float degree = abs(int(lon));
|
||||
float minute = abs((lon - int(lon)) * 60);
|
||||
return String(degree, 0) + "\x90 " + String(minute, 4) + "' " + ((lon > 0) ? "E" : "W");
|
||||
}
|
||||
|
||||
// Convert and format boat value from SI to user defined format (definition for compatibility purposes)
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata) {
|
||||
|
||||
return formatValue(value, commondata, false); // call <formatValue> with standard handling of user setting for simulation data
|
||||
}
|
||||
|
||||
// Convert and format boat value from SI to user defined format
|
||||
// generate random simulation data; can be deselected to use conversion+formatting function even in simulation mode
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool ignoreSimuDataSetting){
|
||||
FormattedData Formatter::formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
||||
GwLog *logger = commondata.logger;
|
||||
FormattedData result;
|
||||
static int dayoffset = 0;
|
||||
double rawvalue = 0;
|
||||
|
||||
result.cvalue = value->value;
|
||||
|
||||
// Load configuration values
|
||||
String stimeZone = commondata.config->getString(commondata.config->timeZone); // [UTC -14.00...+12.00]
|
||||
double timeZone = stimeZone.toDouble();
|
||||
String lengthFormat = commondata.config->getString(commondata.config->lengthFormat); // [m|ft]
|
||||
String distanceFormat = commondata.config->getString(commondata.config->distanceFormat); // [m|km|nm]
|
||||
String speedFormat = commondata.config->getString(commondata.config->speedFormat); // [m/s|km/h|kn]
|
||||
String windspeedFormat = commondata.config->getString(commondata.config->windspeedFormat); // [m/s|km/h|kn|bft]
|
||||
String tempFormat = commondata.config->getString(commondata.config->tempFormat); // [K|°C|°F]
|
||||
String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US]
|
||||
String precision = commondata.config->getString(commondata.config->valueprecision); // [1|2]
|
||||
|
||||
bool usesimudata;
|
||||
if (ignoreSimuDataSetting){
|
||||
usesimudata = false; // ignore user setting for simulation data; we want to format the boat value passed to this function
|
||||
} else {
|
||||
usesimudata = commondata.config->getBool(commondata.config->useSimuData); // [on|off]
|
||||
}
|
||||
|
||||
// If boat value not valid
|
||||
if (! value->valid && !usesimudata){
|
||||
result.svalue = "---";
|
||||
result.svalue = placeholder;
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* fmt_dec_1;
|
||||
const char* fmt_dec_10;
|
||||
const char* fmt_dec_100;
|
||||
double limit_dec_10;
|
||||
double limit_dec_100;
|
||||
if (precision == "1") {
|
||||
//
|
||||
//All values are displayed using a DSEG7* font. In this font, ' ' is a very short space, and '.' takes up no space at all.
|
||||
//For a space that is as long as a number, '!' is used. For details see https://www.keshikan.net/fonts-e.html
|
||||
//
|
||||
fmt_dec_1 = "!%1.1f"; //insert a blank digit and then display a two-digit number
|
||||
fmt_dec_10 = "!%2.0f"; //insert a blank digit and then display a two-digit number
|
||||
fmt_dec_100 = "%3.0f"; //dispay a three digit number
|
||||
limit_dec_10=9.95; // use fmt_dec_1 below this number to avoid formatting 9.96 as 10.0 instead of 10
|
||||
limit_dec_100=99.5;
|
||||
} else {
|
||||
fmt_dec_1 = "%3.2f";
|
||||
fmt_dec_10 = "%3.1f";
|
||||
fmt_dec_100 = "%3.0f";
|
||||
limit_dec_10=9.995;
|
||||
limit_dec_100=99.95;
|
||||
}
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG,"formatValue init: getFormat: %s date->value: %f time->value: %f", value->getFormat(), commondata.date->value, commondata.time->value);
|
||||
static const int bsize = 30;
|
||||
char buffer[bsize+1];
|
||||
@@ -151,12 +118,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
else{
|
||||
snprintf(buffer, bsize, "01.01.2022");
|
||||
}
|
||||
if(timeZone == 0){
|
||||
result.unit = "UTC";
|
||||
}
|
||||
else{
|
||||
result.unit = "LOT";
|
||||
}
|
||||
result.unit = ((timeZone == 0) ? "UTC" : "LOT");
|
||||
}
|
||||
//########################################################
|
||||
else if(value->getFormat() == "formatTime"){
|
||||
@@ -175,7 +137,6 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
val = modf(val*3600.0/60.0, &intmin);
|
||||
modf(val*60.0,&intsec);
|
||||
snprintf(buffer, bsize, "%02.0f:%02.0f:%02.0f", inthr, intmin, intsec);
|
||||
result.cvalue = timeInSeconds;
|
||||
}
|
||||
else{
|
||||
static long sec;
|
||||
@@ -185,15 +146,9 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
}
|
||||
sec = sec % 60;
|
||||
snprintf(buffer, bsize, "11:36:%02i", int(sec));
|
||||
result.cvalue = sec;
|
||||
lasttime = millis();
|
||||
}
|
||||
if(timeZone == 0){
|
||||
result.unit = "UTC";
|
||||
}
|
||||
else{
|
||||
result.unit = "LOT";
|
||||
}
|
||||
result.unit = ((timeZone == 0) ? "UTC" : "LOT");
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatFixed0"){
|
||||
@@ -206,7 +161,6 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
snprintf(buffer, bsize, "%3.0f", rawvalue);
|
||||
}
|
||||
result.unit = "";
|
||||
result.cvalue = rawvalue;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatCourse" || value->getFormat() == "formatWind"){
|
||||
@@ -216,15 +170,14 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = value->value;
|
||||
}
|
||||
else {
|
||||
course = M_PI_2 + float(random(-17, 17) / 100.0); // create random course/wind values with 90° +/- 10°
|
||||
course = 2.53 + float(random(0, 10) / 100.0);
|
||||
rawvalue = course;
|
||||
}
|
||||
course = course * RAD_TO_DEG; // Unit conversion form rad to deg
|
||||
course = course * 57.2958; // Unit conversion form rad to deg
|
||||
|
||||
// Format 3 numbers with prefix zero
|
||||
snprintf(buffer,bsize,"%03.0f",course);
|
||||
result.unit = "Deg";
|
||||
result.cvalue = course;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW")){
|
||||
@@ -234,7 +187,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = value->value;
|
||||
}
|
||||
else{
|
||||
rawvalue = 4.0 + float(random(-30, 40) / 10.0); // create random speed values from [1..8] m/s
|
||||
rawvalue = 4.0 + float(random(0, 40));
|
||||
speed = rawvalue;
|
||||
}
|
||||
if (String(speedFormat) == "km/h"){
|
||||
@@ -249,16 +202,15 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
speed = speed; // Unit conversion form m/s to m/s
|
||||
result.unit = "m/s";
|
||||
}
|
||||
if(speed < limit_dec_10) {
|
||||
if(speed < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, speed);
|
||||
}
|
||||
else if (speed < limit_dec_100) {
|
||||
else if (speed < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, speed);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, speed);
|
||||
}
|
||||
result.cvalue = speed;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatKnots" && (value->getName() == "AWS" || value->getName() == "TWS" || value->getName() == "MaxAws" || value->getName() == "MaxTws")){
|
||||
@@ -268,7 +220,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = value->value;
|
||||
}
|
||||
else {
|
||||
rawvalue = 4.0 + float(random(0, 40) / 10.0); // create random wind speed values from [4..8] m/s
|
||||
rawvalue = 4.0 + float(random(0, 40));
|
||||
speed = rawvalue;
|
||||
}
|
||||
if (String(windspeedFormat) == "km/h"){
|
||||
@@ -329,17 +281,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
snprintf(buffer, bsize, "%2.0f", speed);
|
||||
}
|
||||
else{
|
||||
if (speed < limit_dec_10){
|
||||
if (speed < 10){
|
||||
snprintf(buffer, bsize, fmt_dec_1, speed);
|
||||
}
|
||||
else if (speed < limit_dec_100){
|
||||
else if (speed < 100){
|
||||
snprintf(buffer, bsize, fmt_dec_10, speed);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, speed);
|
||||
}
|
||||
}
|
||||
result.cvalue = speed;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatRot"){
|
||||
@@ -357,16 +308,15 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
if (rotation < -100){
|
||||
rotation = -99;
|
||||
}
|
||||
if (rotation > 100){
|
||||
else if (rotation > 100){
|
||||
rotation = 99;
|
||||
}
|
||||
if (rotation > -10 && rotation < 10){
|
||||
snprintf(buffer, bsize, "%3.2f", rotation);
|
||||
}
|
||||
if (rotation <= -10 || rotation >= 10){
|
||||
else {
|
||||
snprintf(buffer, bsize, "%3.0f", rotation);
|
||||
}
|
||||
result.cvalue = rotation;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatDop"){
|
||||
@@ -383,16 +333,15 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
if (dop > 99.9){
|
||||
dop = 99.9;
|
||||
}
|
||||
if (dop < limit_dec_10){
|
||||
if (dop < 10){
|
||||
snprintf(buffer, bsize, fmt_dec_1, dop);
|
||||
}
|
||||
else if(dop < limit_dec_100){
|
||||
else if(dop < 100){
|
||||
snprintf(buffer, bsize, fmt_dec_10, dop);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, dop);
|
||||
}
|
||||
result.cvalue = dop;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatLatitude"){
|
||||
@@ -403,12 +352,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
String latdir = "";
|
||||
float degree = abs(int(lat));
|
||||
float minute = abs((lat - int(lat)) * 60);
|
||||
if (lat > 0){
|
||||
latdir = "N";
|
||||
}
|
||||
else {
|
||||
latdir = "S";
|
||||
}
|
||||
latdir = (lat > 0) ? "N" : "S";
|
||||
latitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + latdir;
|
||||
result.unit = "";
|
||||
strcpy(buffer, latitude.c_str());
|
||||
@@ -417,7 +361,6 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 35.0 + float(random(0, 10)) / 10000.0;
|
||||
snprintf(buffer, bsize, " 51\" %2.4f' N", rawvalue);
|
||||
}
|
||||
result.cvalue = rawvalue;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatLongitude"){
|
||||
@@ -428,12 +371,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
String londir = "";
|
||||
float degree = abs(int(lon));
|
||||
float minute = abs((lon - int(lon)) * 60);
|
||||
if (lon > 0){
|
||||
londir = "E";
|
||||
}
|
||||
else {
|
||||
londir = "W";
|
||||
}
|
||||
londir = (lon > 0) ? "E" : "W";
|
||||
longitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + londir;
|
||||
result.unit = "";
|
||||
strcpy(buffer, longitude.c_str());
|
||||
@@ -442,7 +380,6 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 6.0 + float(random(0, 10)) / 100000.0;
|
||||
snprintf(buffer, bsize, " 15\" %2.4f'", rawvalue);
|
||||
}
|
||||
result.cvalue = rawvalue;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatDepth"){
|
||||
@@ -452,59 +389,53 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = value->value;
|
||||
}
|
||||
else {
|
||||
rawvalue = 18.0 + float(random(0, 100)) / 10.0; // create random depth values from [18..28] metres
|
||||
rawvalue = 18.0 + float(random(0, 100)) / 10.0;
|
||||
depth = rawvalue;
|
||||
}
|
||||
if(String(lengthFormat) == "ft"){
|
||||
depth = depth * 3.28084;
|
||||
depth = depth * 3.28084; // TODO use global defined factor
|
||||
result.unit = "ft";
|
||||
}
|
||||
else{
|
||||
result.unit = "m";
|
||||
}
|
||||
if (depth < limit_dec_10) {
|
||||
if (depth < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, depth);
|
||||
}
|
||||
else if (depth < limit_dec_100){
|
||||
else if (depth < 100){
|
||||
snprintf(buffer, bsize, fmt_dec_10, depth);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, depth);
|
||||
}
|
||||
result.cvalue = depth;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXte"){
|
||||
double xte = 0;
|
||||
if(usesimudata == false) {
|
||||
if (usesimudata == false) {
|
||||
xte = value->value;
|
||||
rawvalue = value->value;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
rawvalue = 6.0 + float(random(0, 4));
|
||||
xte = rawvalue;
|
||||
}
|
||||
if(String(distanceFormat) == "km"){
|
||||
if (distanceFormat == "km") {
|
||||
xte = xte * 0.001;
|
||||
result.unit = "km";
|
||||
}
|
||||
else if(String(distanceFormat) == "nm"){
|
||||
xte = xte * 0.000539957;
|
||||
} else if (distanceFormat == "nm") {
|
||||
xte = xte * 0.000539957; // TODO use global defined factor
|
||||
result.unit = "nm";
|
||||
}
|
||||
else{;
|
||||
} else {
|
||||
result.unit = "m";
|
||||
}
|
||||
if(xte < 10){
|
||||
snprintf(buffer,bsize,"%3.2f",xte);
|
||||
}
|
||||
if(xte >= 10 && xte < 100){
|
||||
if (xte < 10) {
|
||||
snprintf(buffer, bsize, "%3.2f", xte);
|
||||
} else if (xte < 100) {
|
||||
snprintf(buffer,bsize,"%3.1f",xte);
|
||||
}
|
||||
if(xte >= 100){
|
||||
snprintf(buffer,bsize,"%3.0f",xte);
|
||||
else {
|
||||
snprintf(buffer, bsize, "%3.0f", xte);
|
||||
}
|
||||
result.cvalue = xte;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "kelvinToC"){
|
||||
@@ -528,16 +459,15 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
else{
|
||||
result.unit = "K";
|
||||
}
|
||||
if(temp < limit_dec_10) {
|
||||
if (temp < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, temp);
|
||||
}
|
||||
else if (temp < limit_dec_100) {
|
||||
else if (temp < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, temp);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, temp);
|
||||
}
|
||||
result.cvalue = temp;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "mtr2nm"){
|
||||
@@ -555,22 +485,21 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
result.unit = "km";
|
||||
}
|
||||
else if (String(distanceFormat) == "nm") {
|
||||
distance = distance * 0.000539957;
|
||||
distance = distance * 0.000539957; // TODO use global defined factor
|
||||
result.unit = "nm";
|
||||
}
|
||||
else {
|
||||
result.unit = "m";
|
||||
}
|
||||
if (distance < limit_dec_10){
|
||||
if (distance < 10){
|
||||
snprintf(buffer, bsize, fmt_dec_1, distance);
|
||||
}
|
||||
else if (distance < limit_dec_100){
|
||||
else if (distance < 100){
|
||||
snprintf(buffer, bsize, fmt_dec_10, distance);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, distance);
|
||||
}
|
||||
result.cvalue = distance;
|
||||
}
|
||||
//########################################################
|
||||
// Special XDR formats
|
||||
@@ -589,7 +518,6 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
}
|
||||
snprintf(buffer, bsize, "%4.0f", pressure);
|
||||
result.unit = "hPa";
|
||||
result.cvalue = pressure;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:P:B"){
|
||||
@@ -605,7 +533,6 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
}
|
||||
snprintf(buffer, bsize, "%4.0f", pressure);
|
||||
result.unit = "mBar";
|
||||
result.cvalue = pressure;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:U:V"){
|
||||
@@ -618,14 +545,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 12 + float(random(0, 30)) / 10.0;
|
||||
voltage = rawvalue;
|
||||
}
|
||||
if (voltage < limit_dec_10) {
|
||||
if (voltage < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, voltage);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_10, voltage);
|
||||
}
|
||||
result.unit = "V";
|
||||
result.cvalue = voltage;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:I:A"){
|
||||
@@ -638,17 +564,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 8.2 + float(random(0, 50)) / 10.0;
|
||||
current = rawvalue;
|
||||
}
|
||||
if (current < limit_dec_10) {
|
||||
if (current < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, current);
|
||||
}
|
||||
else if(current < limit_dec_100) {
|
||||
else if(current < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, current);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, current);
|
||||
}
|
||||
result.unit = "A";
|
||||
result.cvalue = current;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:C:K"){
|
||||
@@ -661,17 +586,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 21.8 + float(random(0, 50)) / 10.0;
|
||||
temperature = rawvalue;
|
||||
}
|
||||
if (temperature < limit_dec_10) {
|
||||
if (temperature < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, temperature);
|
||||
}
|
||||
else if (temperature < limit_dec_100) {
|
||||
else if (temperature < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, temperature);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, temperature);
|
||||
}
|
||||
result.unit = "Deg C";
|
||||
result.cvalue = temperature;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:C:C"){
|
||||
@@ -684,17 +608,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 21.8 + float(random(0, 50)) / 10.0;
|
||||
temperature = rawvalue;
|
||||
}
|
||||
if (temperature < limit_dec_10) {
|
||||
if (temperature < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, temperature);
|
||||
}
|
||||
else if(temperature < limit_dec_100) {
|
||||
else if(temperature < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, temperature);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, temperature);
|
||||
}
|
||||
result.unit = "Deg C";
|
||||
result.cvalue = temperature;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:H:P"){
|
||||
@@ -707,17 +630,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 41.3 + float(random(0, 50)) / 10.0;
|
||||
humidity = rawvalue;
|
||||
}
|
||||
if (humidity < limit_dec_10) {
|
||||
if (humidity < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, humidity);
|
||||
}
|
||||
else if(humidity < limit_dec_100) {
|
||||
else if(humidity < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, humidity);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, humidity);
|
||||
}
|
||||
result.unit = "%";
|
||||
result.cvalue = humidity;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:V:P"){
|
||||
@@ -730,17 +652,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 85.8 + float(random(0, 50)) / 10.0;
|
||||
volume = rawvalue;
|
||||
}
|
||||
if (volume < limit_dec_10) {
|
||||
if (volume < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, volume);
|
||||
}
|
||||
else if (volume < limit_dec_100) {
|
||||
else if (volume < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, volume);
|
||||
}
|
||||
else if (volume >= limit_dec_100) {
|
||||
else if (volume >= 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_100, volume);
|
||||
}
|
||||
result.unit = "%";
|
||||
result.cvalue = volume;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:V:M"){
|
||||
@@ -753,17 +674,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 75.2 + float(random(0, 50)) / 10.0;
|
||||
volume = rawvalue;
|
||||
}
|
||||
if (volume < limit_dec_10) {
|
||||
if (volume < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, volume);
|
||||
}
|
||||
else if (volume < limit_dec_100) {
|
||||
else if (volume < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, volume);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, volume);
|
||||
}
|
||||
result.unit = "l";
|
||||
result.cvalue = volume;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:R:I"){
|
||||
@@ -776,17 +696,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 7.5 + float(random(0, 20)) / 10.0;
|
||||
flow = rawvalue;
|
||||
}
|
||||
if (flow < limit_dec_10) {
|
||||
if (flow < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, flow);
|
||||
}
|
||||
else if (flow < limit_dec_100) {
|
||||
else if (flow < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, flow);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, flow);
|
||||
}
|
||||
result.unit = "l/min";
|
||||
result.cvalue = flow;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:G:"){
|
||||
@@ -799,17 +718,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 18.5 + float(random(0, 20)) / 10.0;
|
||||
generic = rawvalue;
|
||||
}
|
||||
if (generic < limit_dec_10) {
|
||||
if (generic < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, generic);
|
||||
}
|
||||
else if (generic < limit_dec_100) {
|
||||
else if (generic < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, generic);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, generic);
|
||||
}
|
||||
result.unit = "";
|
||||
result.cvalue = generic;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:A:P"){
|
||||
@@ -822,17 +740,16 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 55.3 + float(random(0, 20)) / 10.0;
|
||||
dplace = rawvalue;
|
||||
}
|
||||
if (dplace < limit_dec_10) {
|
||||
if (dplace < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, dplace);
|
||||
}
|
||||
else if (dplace < limit_dec_100) {
|
||||
else if (dplace < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, dplace);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, dplace);
|
||||
}
|
||||
result.unit = "%";
|
||||
result.cvalue = dplace;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:A:D"){
|
||||
@@ -853,7 +770,6 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
snprintf(buffer,bsize,"%3.0f",angle);
|
||||
}
|
||||
result.unit = "Deg";
|
||||
result.cvalue = angle;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatXdr:T:R"){
|
||||
@@ -866,33 +782,31 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 2505 + random(0, 20);
|
||||
rpm = rawvalue;
|
||||
}
|
||||
if (rpm < limit_dec_10) {
|
||||
if (rpm < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, rpm);
|
||||
}
|
||||
else if (rpm < limit_dec_100) {
|
||||
else if (rpm < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, rpm);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, rpm);
|
||||
}
|
||||
result.unit = "rpm";
|
||||
result.cvalue = rpm;
|
||||
}
|
||||
//########################################################
|
||||
// Default format
|
||||
//########################################################
|
||||
else {
|
||||
if (value->value < limit_dec_10) {
|
||||
if (value->value < 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_1, value->value);
|
||||
}
|
||||
else if (value->value < limit_dec_100) {
|
||||
else if (value->value < 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, value->value);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, fmt_dec_100, value->value);
|
||||
}
|
||||
result.unit = "";
|
||||
result.cvalue = value->value;
|
||||
}
|
||||
buffer[bsize] = 0;
|
||||
result.value = rawvalue; // Return value is only necessary in case of simulation of graphic pointer
|
||||
@@ -900,30 +814,49 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper method for conversion of any data value from SI to user defined format
|
||||
double convertValue(const double &value, const String &name, const String &format, CommonData &commondata)
|
||||
{
|
||||
std::unique_ptr<GwApi::BoatValue> tmpBValue; // Temp variable to get converted data value from <OBP60Formatter::formatValue>
|
||||
double result; // data value converted to user defined target data format
|
||||
constexpr bool NO_SIMUDATA = true; // switch off simulation feature of <formatValue> function
|
||||
|
||||
// prepare temporary BoatValue structure for use in <formatValue>
|
||||
tmpBValue = std::unique_ptr<GwApi::BoatValue>(new GwApi::BoatValue(name)); // we don't need boat value name for pure value conversion
|
||||
tmpBValue->setFormat(format);
|
||||
tmpBValue->valid = true;
|
||||
tmpBValue->value = value;
|
||||
|
||||
result = formatValue(tmpBValue.get(), commondata, NO_SIMUDATA).cvalue; // get value (converted); ignore any simulation data setting
|
||||
return result;
|
||||
String formatDate(fmtDate fmttype, uint16_t year, uint8_t month, uint8_t day) {
|
||||
char buffer[12];
|
||||
if (fmttype == fmtDate::GB) {
|
||||
snprintf(buffer, 12, "%02d/%02d/%04d", day , month, year);
|
||||
}
|
||||
else if (fmttype == fmtDate::US) {
|
||||
snprintf(buffer, 12, "%02d/%02d/%04d", month, day, year);
|
||||
}
|
||||
else if (fmttype == fmtDate::ISO) {
|
||||
snprintf(buffer, 12, "%04d-%02d-%02d", year, month, day);
|
||||
}
|
||||
else if (fmttype == fmtDate::DE) {
|
||||
snprintf(buffer, 12, "%02d.%02d.%04d", day, month, year);
|
||||
} else {
|
||||
snprintf(buffer, 12, "%04d-%02d-%02d", year, month, day);
|
||||
}
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
// Helper method for conversion of any data value from SI to user defined format
|
||||
double convertValue(const double &value, const String &format, CommonData &commondata)
|
||||
{
|
||||
double result; // data value converted to user defined target data format
|
||||
String formatTime(fmtTime fmttype, uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
char buffer[10];
|
||||
if (fmttype == fmtTime::MMHH) {
|
||||
snprintf(buffer, 10, "%02d:%02d", hour , minute);
|
||||
}
|
||||
else if (fmttype == fmtTime::MMHHSS) {
|
||||
snprintf(buffer, 10, "%02d:%02d:%02d", hour, minute, second);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, 10, "%02d%02d%02d", hour, minute, second);
|
||||
}
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
result = convertValue(value, "dummy", format, commondata);
|
||||
return result;
|
||||
String formatLatitude(double lat) {
|
||||
float degree = abs(int(lat));
|
||||
float minute = abs((lat - int(lat)) * 60);
|
||||
return String(degree, 0) + "\x90 " + String(minute, 4) + "' " + ((lat > 0) ? "N" : "S");
|
||||
}
|
||||
|
||||
String formatLongitude(double lon) {
|
||||
float degree = abs(int(lon));
|
||||
float minute = abs((lon - int(lon)) * 60);
|
||||
return String(degree, 0) + "\x90 " + String(minute, 4) + "' " + ((lon > 0) ? "E" : "W");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
172
lib/obp60task/OBP60Formatter.h
Normal file
172
lib/obp60task/OBP60Formatter.h
Normal file
@@ -0,0 +1,172 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#ifndef _OBP60FORMATTER_H
|
||||
#define _OBP60FORMATTER_H
|
||||
|
||||
#include "GwApi.h"
|
||||
#include "Pagedata.h"
|
||||
#include <unordered_map>
|
||||
|
||||
/*
|
||||
|
||||
XDR types
|
||||
A Angular displacement
|
||||
C Temperature
|
||||
D Linear displacement
|
||||
F Frequency
|
||||
G Generic
|
||||
H Humidity
|
||||
I Current
|
||||
L Salinity
|
||||
N Force
|
||||
P Pressure
|
||||
R Flow
|
||||
S Switch or valve
|
||||
T Tachometer
|
||||
U Voltage
|
||||
V Volume
|
||||
|
||||
XDR units
|
||||
A Ampere
|
||||
B Bar
|
||||
C Celsius
|
||||
D Degrees
|
||||
H Hertz
|
||||
I Liter per second?
|
||||
M Meter / Cubic meter
|
||||
N Newton
|
||||
P Percent
|
||||
R RPM
|
||||
V Volt
|
||||
|
||||
*/
|
||||
|
||||
enum class fmtType {
|
||||
// Formatter names as defined in BoatItemBase
|
||||
COURSE,
|
||||
KNOTS,
|
||||
WIND,
|
||||
LATITUDE,
|
||||
LONGITUDE,
|
||||
XTE,
|
||||
FIXED0,
|
||||
DEPTH,
|
||||
DOP, // dilution of precision
|
||||
ROT,
|
||||
DATE,
|
||||
TIME,
|
||||
NAME,
|
||||
|
||||
kelvinToC, // TODO not a format but conversion
|
||||
mtr2nm, // TODO not a format but conversion
|
||||
|
||||
// XDR Formatter names
|
||||
XDR_PP, // pressure percent
|
||||
XDR_PB, // pressure bar
|
||||
XDR_UV, // voltage volt
|
||||
XDR_IA, // current ampere
|
||||
XDR_CK, // temperature kelvin
|
||||
XDR_CC, // temperature celsius
|
||||
XDR_HP, // humidity percent
|
||||
XDR_VP, // volume percent
|
||||
XDR_VM, // volume cubic meters
|
||||
XDR_RI, // flow liter per second?
|
||||
XDR_G, // generic
|
||||
XDR_AP, // angle percent
|
||||
XDR_AD, // angle degrees
|
||||
XDR_TR // tachometer rpm
|
||||
};
|
||||
|
||||
// Hint: String is not supported
|
||||
static std::unordered_map<const char*, fmtType> formatMap PROGMEM = {
|
||||
{"formatCourse", fmtType::COURSE},
|
||||
{"formatKnots", fmtType::KNOTS},
|
||||
{"formatWind", fmtType::WIND},
|
||||
{"formatLatitude", fmtType::LATITUDE},
|
||||
{"formatLongitude", fmtType::LONGITUDE},
|
||||
{"formatXte", fmtType::XTE},
|
||||
{"formatFixed0", fmtType::FIXED0},
|
||||
{"formatDepth", fmtType::DEPTH},
|
||||
{"formatDop", fmtType::DOP},
|
||||
{"formatRot", fmtType::ROT},
|
||||
{"formatDate", fmtType::DATE},
|
||||
{"formatTime", fmtType::TIME},
|
||||
{"formatName", fmtType::NAME},
|
||||
{"kelvinToC", fmtType::kelvinToC},
|
||||
{"mtr2nm", fmtType::mtr2nm},
|
||||
{"formatXdr:P:P", fmtType::XDR_PP},
|
||||
{"formatXdr:P:B", fmtType::XDR_PB},
|
||||
{"formatXdr:U:V", fmtType::XDR_UV},
|
||||
{"formatXdr:I:A", fmtType::XDR_IA},
|
||||
{"formatXdr:C:K", fmtType::XDR_CK},
|
||||
{"formatXdr:C:C", fmtType::XDR_CC},
|
||||
{"formatXdr:H:P", fmtType::XDR_HP},
|
||||
{"formatXdr:V:P", fmtType::XDR_VP},
|
||||
{"formatXdr:V:M", fmtType::XDR_VM},
|
||||
{"formatXdr:R:I", fmtType::XDR_RI},
|
||||
{"formatXdr:G:", fmtType::XDR_G},
|
||||
{"formatXdr:A:P", fmtType::XDR_AP},
|
||||
{"formatXdr:A:D", fmtType::XDR_AD},
|
||||
{"formatXdr:T:R", fmtType::XDR_TR}
|
||||
};
|
||||
|
||||
// Possible formats as scoped enums
|
||||
enum class fmtDate {DE, GB, US, ISO};
|
||||
enum class fmtTime {MMHH, MMHHSS};
|
||||
enum class fmtLength {METER, FEET, FATHOM, CABLE};
|
||||
enum class fmtDepth {METER, FEET, FATHOM};
|
||||
enum class fmtWind {KMH, MS, KN, BFT};
|
||||
enum class fmtCourse {DEG, RAD};
|
||||
enum class fmtRot {DEGS, RADS};
|
||||
enum class fmtXte {M, KM, NM, CABLE};
|
||||
enum class fmtPress {PA, BAR};
|
||||
enum class fmtTemp {KELVIN, CELSUIS, FAHRENHEIT};
|
||||
|
||||
// Conversion factors
|
||||
#define CONV_M_FT 3.2808399 // meter too feet
|
||||
#define CONV_M_FM 0.5468 // meter to fathom
|
||||
#define CONV_M_CBL 0.0053961182483768 // meter to cable
|
||||
#define CONV_CBL_FT 608 // cable to feet
|
||||
#define CONV_FM_FT 6 // fathom to feet
|
||||
|
||||
// Structure for formatted boat values
|
||||
typedef struct {
|
||||
double value;
|
||||
String svalue;
|
||||
String unit;
|
||||
} FormattedData;
|
||||
|
||||
// Formatter for boat values
|
||||
class Formatter {
|
||||
private:
|
||||
String stimeZone = "0";
|
||||
double timeZone = 0.0; // [UTC -14.00...+12.00]
|
||||
String lengthFormat = "m"; // [m|ft]
|
||||
String distanceFormat = "nm"; // [m|km|nm]
|
||||
String speedFormat = "kn"; // [m/s|km/h|kn]
|
||||
String windspeedFormat = "kn"; // [m/s|km/h|kn|bft]
|
||||
String tempFormat = "C"; // [K|°C|°F]
|
||||
String dateFormat = "ISO"; // [DE|GB|US|ISO]
|
||||
fmtDate dateFmt;
|
||||
bool usesimudata = false; // [on|off]
|
||||
|
||||
String precision = "2"; // [1|2]
|
||||
const char* fmt_dec_1;
|
||||
const char* fmt_dec_10;
|
||||
const char* fmt_dec_100;
|
||||
|
||||
public:
|
||||
Formatter(GwConfigHandler *config);
|
||||
fmtType stringToFormat(const char* formatStr);
|
||||
fmtDate getDateFormat(String sformat);
|
||||
fmtTime getTimeFormat(String sformat);
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata);
|
||||
String placeholder = "---";
|
||||
};
|
||||
|
||||
// Standard format functions without class and overhead
|
||||
String formatDate(fmtDate fmttype, uint16_t year, uint8_t month, uint8_t day);
|
||||
String formatTime(fmtTime fmttype, uint8_t hour, uint8_t minute, uint8_t second);
|
||||
String formatLatitude(double lat);
|
||||
String formatLongitude(double lon);
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,11 @@
|
||||
// General hardware definitions
|
||||
// CAN and RS485 bus pin definitions see obp60task.h
|
||||
|
||||
#if defined HARDWARE_V20 || HARDWARE_V21
|
||||
#ifdef HARDWARE_V21
|
||||
// Direction pin for RS485 NMEA0183
|
||||
#define OBP_DIRECTION_PIN 18
|
||||
// I2C
|
||||
#define I2C_SPEED 10000UL // 100kHz clock speed on I2C bus
|
||||
#define I2C_SPEED_LOW 1000UL // 10kHz clock speed on I2C bus for external bus
|
||||
#define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
|
||||
#define OBP_I2C_SDA 47
|
||||
#define OBP_I2C_SCL 21
|
||||
// DS1388 RTC
|
||||
@@ -23,8 +22,8 @@
|
||||
#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 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
|
||||
#define INA219_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
|
||||
#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
|
||||
@@ -43,8 +42,6 @@
|
||||
#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 GxEPD_WIDTH 400 // Display width
|
||||
#define GxEPD_HEIGHT 300 // Display height
|
||||
|
||||
// GPS (NEO-6M, NEO-M8N, ATGM336H)
|
||||
#define OBP_GPS_RX 2
|
||||
@@ -85,8 +82,7 @@
|
||||
// Direction pin for RS485 NMEA0183
|
||||
#define OBP_DIRECTION_PIN 8
|
||||
// I2C
|
||||
#define I2C_SPEED 100000UL // 100kHz clock speed on I2C bus
|
||||
#define I2C_SPEED_LOW 1000UL // 10kHz clock speed on I2C bus for external bus
|
||||
#define I2C_SPEED 100000UL // 100kHz clock speed on I2C bus
|
||||
#define OBP_I2C_SDA 21
|
||||
#define OBP_I2C_SCL 38
|
||||
// DS1388 RTC
|
||||
@@ -103,8 +99,8 @@
|
||||
#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 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
|
||||
#define INA219_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
|
||||
#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
|
||||
@@ -123,8 +119,6 @@
|
||||
#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)
|
||||
#define GxEPD_WIDTH 400 // Display width
|
||||
#define GxEPD_HEIGHT 300 // Display height
|
||||
// SPI SD-Card
|
||||
#define SD_SPI_CS GPIO_NUM_10
|
||||
#define SD_SPI_MOSI GPIO_NUM_40
|
||||
|
||||
@@ -26,20 +26,20 @@ void qrWiFi(String ssid, String passwd, uint16_t fgcolor, uint16_t bgcolor){
|
||||
// Each horizontal module
|
||||
for (uint8_t x = 0; x < qrcode.size; x++) {
|
||||
if(qrcode_getModule(&qrcode, x, y)){
|
||||
getdisplay().fillRect(box_x, box_y, box_s, box_s, fgcolor);
|
||||
epd->fillRect(box_x, box_y, box_s, box_s, fgcolor);
|
||||
} else {
|
||||
getdisplay().fillRect(box_x, box_y, box_s, box_s, bgcolor);
|
||||
epd->fillRect(box_x, box_y, box_s, box_s, bgcolor);
|
||||
}
|
||||
box_x = box_x + box_s;
|
||||
}
|
||||
box_y = box_y + box_s;
|
||||
box_x = init_x;
|
||||
}
|
||||
getdisplay().setFont(&Ubuntu_Bold32pt8b);
|
||||
getdisplay().setTextColor(fgcolor);
|
||||
getdisplay().setCursor(140, 285);
|
||||
getdisplay().print("WiFi");
|
||||
getdisplay().nextPage(); // Full Refresh
|
||||
epd->setFont(&Ubuntu_Bold32pt8b);
|
||||
epd->setTextColor(fgcolor);
|
||||
epd->setCursor(140, 285);
|
||||
epd->print("WiFi");
|
||||
epd->nextPage(); // Full Refresh
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,345 +1,152 @@
|
||||
#include "OBPDataOperations.h"
|
||||
//#include "BoatDataCalibration.h" // Functions lib for data instance calibration
|
||||
|
||||
// --- Class CalibrationData ---------------
|
||||
CalibrationData::CalibrationData(GwLog* log)
|
||||
{
|
||||
logger = log;
|
||||
}
|
||||
|
||||
void CalibrationData::readConfig(GwConfigHandler* config)
|
||||
// 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;
|
||||
}
|
||||
|
||||
calibrationMap[instance] = { 0.0f, 1.0f, 1.0f, 0.0f, false };
|
||||
offset = (config->getString(calOffset, "")).toDouble();
|
||||
slope = (config->getString(calSlope, "")).toDouble();
|
||||
smooth = (config->getString(calSmooth, "")).toInt(); // user input is int; further math is done with double
|
||||
|
||||
if (slope == 0.0) {
|
||||
slope = 1.0; // eliminate adjustment if user selected "0" -> that would set the calibrated value to "0"
|
||||
}
|
||||
|
||||
// Convert calibration values from user input format to internal standard SI format
|
||||
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 == "HDM" || instance == "HDT" || instance == "PRPOS" || instance == "RPOS" || instance == "TWA" || instance == "TWD") {
|
||||
offset *= DEG_TO_RAD; // Convert deg to rad
|
||||
|
||||
} else if (instance == "DBS" || 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;
|
||||
|
||||
calibrationMap[instance].offset = offset;
|
||||
calibrationMap[instance].slope = slope;
|
||||
calibrationMap[instance].smooth = smooth;
|
||||
calibrationMap[instance].isCalibrated = false;
|
||||
LOG_DEBUG(GwLog::LOG, "Calibration data type added: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(),
|
||||
calibrationMap[instance].offset, calibrationMap[instance].slope, calibrationMap[instance].smooth);
|
||||
}
|
||||
// LOG_DEBUG(GwLog::LOG, "All calibration data read");
|
||||
}
|
||||
|
||||
// Handle calibrationMap and calibrate all boat data values
|
||||
void CalibrationData::handleCalibration(BoatValueList* boatValueList)
|
||||
{
|
||||
GwApi::BoatValue* bValue;
|
||||
|
||||
for (const auto& cMap : calibrationMap) {
|
||||
std::string instance = cMap.first.c_str();
|
||||
bValue = boatValueList->findValueOrCreate(String(instance.c_str()));
|
||||
|
||||
calibrateInstance(bValue);
|
||||
smoothInstance(bValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Calibrate single boat data value
|
||||
// Return calibrated boat value or DBL_MAX, if no calibration was performed
|
||||
bool CalibrationData::calibrateInstance(GwApi::BoatValue* boatDataValue)
|
||||
{
|
||||
std::string instance = boatDataValue->getName().c_str();
|
||||
double offset = 0;
|
||||
double slope = 1.0;
|
||||
double dataValue = 0;
|
||||
std::string format = "";
|
||||
|
||||
// we test this earlier, but for safety reason ...
|
||||
if (calibrationMap.find(instance) == calibrationMap.end()) {
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not in calibration list", instance.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
calibrationMap[instance].isCalibrated = false; // reset calibration flag until properly calibrated
|
||||
|
||||
if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data
|
||||
return false;
|
||||
}
|
||||
|
||||
offset = calibrationMap[instance].offset;
|
||||
slope = calibrationMap[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 = WindUtils::toPI(dataValue);
|
||||
dataValue = WindUtils::to2PI(dataValue); // we should call <toPI> for format of [-180..180], but pages cannot display negative values properly yet
|
||||
|
||||
} else if (format == "formatCourse") { // instance is of type direction
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
dataValue = WindUtils::to2PI(dataValue);
|
||||
|
||||
} else if (format == "kelvinToC") { // instance is of type temperature
|
||||
dataValue = ((dataValue - 273.15) * slope) + offset + 273.15;
|
||||
|
||||
} else {
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
}
|
||||
|
||||
|
||||
boatDataValue->value = dataValue; // update boat data value with calibrated value
|
||||
calibrationMap[instance].value = dataValue; // store the calibrated value in the list
|
||||
calibrationMap[instance].isCalibrated = true;
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Offset: %f, Slope: %f, Result: %f", instance.c_str(), offset, slope, calibrationMap[instance].value);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Smooth single boat data value
|
||||
// Return smoothed boat value or DBL_MAX, if no smoothing was performed
|
||||
bool CalibrationData::smoothInstance(GwApi::BoatValue* boatDataValue)
|
||||
{
|
||||
std::string instance = boatDataValue->getName().c_str();
|
||||
double oldValue = 0;
|
||||
double dataValue = boatDataValue->value;
|
||||
double smoothFactor = 0;
|
||||
|
||||
// we test this earlier, but for safety reason ...
|
||||
if (calibrationMap.find(instance) == calibrationMap.end()) {
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not in calibration list", instance.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
calibrationMap[instance].isCalibrated = false; // reset calibration flag until properly calibrated
|
||||
|
||||
if (!boatDataValue->valid) { // no valid boat data value, so we don't need to do anything
|
||||
return false;
|
||||
}
|
||||
|
||||
smoothFactor = calibrationMap[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; // update boat data value with smoothed value
|
||||
calibrationMap[instance].value = dataValue; // store the smoothed value in the list
|
||||
calibrationMap[instance].isCalibrated = true;
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: smooth: %f, oldValue: %f, result: %f", instance.c_str(), smoothFactor, oldValue, calibrationMap[instance].value);
|
||||
|
||||
return true;
|
||||
}
|
||||
// --- End Class CalibrationData ---------------
|
||||
|
||||
// --- Class HstryBuf ---------------
|
||||
HstryBuf::HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLog* log)
|
||||
: logger(log)
|
||||
, boatDataName(name)
|
||||
{
|
||||
hstryBuf.resize(size);
|
||||
boatValue = boatValues->findValueOrCreate(name);
|
||||
}
|
||||
// Init history buffers for selected boat data
|
||||
void HstryBuf::init(BoatValueList* boatValues, GwLog *log) {
|
||||
|
||||
void HstryBuf::init(const String& format, int updFreq, int mltplr, double minVal, double maxVal)
|
||||
{
|
||||
hstryBuf.setMetaData(boatDataName, format, updFreq, mltplr, minVal, maxVal);
|
||||
hstryMin = minVal;
|
||||
hstryMax = maxVal;
|
||||
if (!boatValue->valid) {
|
||||
boatValue->setFormat(format);
|
||||
boatValue->value = std::numeric_limits<double>::max(); // mark current value invalid
|
||||
logger = log;
|
||||
|
||||
int hstryUpdFreq = 1000; // Update frequency for history buffers in ms
|
||||
int hstryMinVal = 0; // Minimum value for these history buffers
|
||||
twdHstryMax = 6283; // Max value for wind direction (TWD, AWD) in rad [0...2*PI], shifted by 1000 for 3 decimals
|
||||
twsHstryMax = 65000; // Max value for wind speed (TWS, AWS) in m/s [0..65], shifted by 1000 for 3 decimals
|
||||
awdHstryMax = twdHstryMax;
|
||||
awsHstryMax = twsHstryMax;
|
||||
twdHstryMin = hstryMinVal;
|
||||
twsHstryMin = hstryMinVal;
|
||||
awdHstryMin = hstryMinVal;
|
||||
awsHstryMin = hstryMinVal;
|
||||
const double DBL_MAX = std::numeric_limits<double>::max();
|
||||
|
||||
// Initialize history buffers with meta data
|
||||
hstryBufList.twdHstry->setMetaData("TWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax);
|
||||
hstryBufList.twsHstry->setMetaData("TWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax);
|
||||
hstryBufList.awdHstry->setMetaData("AWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax);
|
||||
hstryBufList.awsHstry->setMetaData("AWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax);
|
||||
|
||||
// create boat values for history data types, if they don't exist yet
|
||||
twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName());
|
||||
twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName());
|
||||
twaBVal = boatValues->findValueOrCreate("TWA");
|
||||
awdBVal = boatValues->findValueOrCreate(hstryBufList.awdHstry->getName());
|
||||
awsBVal = boatValues->findValueOrCreate(hstryBufList.awsHstry->getName());
|
||||
|
||||
if (!awdBVal->valid) { // AWD usually does not exist
|
||||
awdBVal->setFormat(hstryBufList.awdHstry->getFormat());
|
||||
awdBVal->value = DBL_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void HstryBuf::add(double value)
|
||||
{
|
||||
if (value >= hstryMin && value <= hstryMax) {
|
||||
hstryBuf.add(value);
|
||||
LOG_DEBUG(GwLog::DEBUG, "HstryBuf::add: name: %s, value: %.3f", hstryBuf.getName(), value);
|
||||
}
|
||||
}
|
||||
|
||||
void HstryBuf::handle(bool useSimuData, CommonData& common)
|
||||
{
|
||||
// GwApi::BoatValue* tmpBVal;
|
||||
std::unique_ptr<GwApi::BoatValue> tmpBVal; // Temp variable to get formatted and converted data value from OBP60Formatter
|
||||
|
||||
// create temporary boat value for calibration purposes and retrieval of simulation value
|
||||
// tmpBVal = new GwApi::BoatValue(boatDataName.c_str());
|
||||
tmpBVal = std::unique_ptr<GwApi::BoatValue>(new GwApi::BoatValue(boatDataName));
|
||||
tmpBVal->setFormat(boatValue->getFormat());
|
||||
tmpBVal->value = boatValue->value;
|
||||
tmpBVal->valid = boatValue->valid;
|
||||
|
||||
if (boatValue->valid) {
|
||||
// Calibrate boat value before adding it to history buffer
|
||||
//calibrationData.calibrateInstance(tmpBVal.get(), logger);
|
||||
//add(tmpBVal->value);
|
||||
add(boatValue->value);
|
||||
|
||||
} else if (useSimuData) { // add simulated value to history buffer
|
||||
double simSIValue = formatValue(tmpBVal.get(), common).value; // simulated value is generated at <formatValue>; here: retreive SI value
|
||||
add(simSIValue);
|
||||
} else {
|
||||
// here we will add invalid (DBL_MAX) value; this will mark periods of missing data in buffer together with a timestamp
|
||||
}
|
||||
}
|
||||
// --- End Class HstryBuf ---------------
|
||||
|
||||
// --- Class HstryBuffers ---------------
|
||||
HstryBuffers::HstryBuffers(int size, BoatValueList* boatValues, GwLog* log)
|
||||
: size(size)
|
||||
, boatValueList(boatValues)
|
||||
, logger(log)
|
||||
{
|
||||
|
||||
// collect boat values for true wind calculation
|
||||
// should all have been already created at true wind object initialization
|
||||
// potentially to be moved to history buffer handling
|
||||
awaBVal = boatValueList->findValueOrCreate("AWA");
|
||||
hdtBVal = boatValueList->findValueOrCreate("HDT");
|
||||
hdmBVal = boatValueList->findValueOrCreate("HDM");
|
||||
varBVal = boatValueList->findValueOrCreate("VAR");
|
||||
cogBVal = boatValueList->findValueOrCreate("COG");
|
||||
sogBVal = boatValueList->findValueOrCreate("SOG");
|
||||
awdBVal = boatValueList->findValueOrCreate("AWD");
|
||||
awaBVal = boatValues->findValueOrCreate("AWA");
|
||||
hdtBVal = boatValues->findValueOrCreate("HDT");
|
||||
hdmBVal = boatValues->findValueOrCreate("HDM");
|
||||
varBVal = boatValues->findValueOrCreate("VAR");
|
||||
cogBVal = boatValues->findValueOrCreate("COG");
|
||||
sogBVal = boatValues->findValueOrCreate("SOG");
|
||||
}
|
||||
|
||||
// Create history buffer for boat data type
|
||||
void HstryBuffers::addBuffer(const String& name)
|
||||
{
|
||||
if (HstryBuffers::getBuffer(name) != nullptr) { // buffer for this data type already exists
|
||||
return;
|
||||
}
|
||||
if (bufferParams.find(name) == bufferParams.end()) { // requested boat data type is not supported in list of <bufferParams>
|
||||
return;
|
||||
// Handle history buffers for TWD, TWS, AWD, AWS
|
||||
//void HstryBuf::handleHstryBuf(GwApi* api, BoatValueList* boatValues, bool useSimuData) {
|
||||
void HstryBuf::handleHstryBuf(bool useSimuData) {
|
||||
|
||||
static int16_t twd = 20; //initial value only relevant if we use simulation data
|
||||
static uint16_t tws = 20; //initial value only relevant if we use simulation data
|
||||
static double awd, aws, hdt = 20; //initial value only relevant if we use simulation data
|
||||
GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG,"obp60task handleHstryBuf: TWD_isValid? %d, twdBVal: %.1f, twaBVal: %.1f, twsBVal: %.1f", twdBVal->valid, twdBVal->value * RAD_TO_DEG,
|
||||
twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852);
|
||||
|
||||
if (twdBVal->valid) {
|
||||
calBVal = new GwApi::BoatValue("TWD"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(twdBVal->getFormat());
|
||||
calBVal->value = twdBVal->value;
|
||||
calBVal->valid = twdBVal->valid;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
twd = static_cast<int16_t>(std::round(calBVal->value * 1000.0));
|
||||
if (twd >= twdHstryMin && twd <= twdHstryMax) {
|
||||
hstryBufList.twdHstry->add(twd);
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
twd += random(-20, 20);
|
||||
twd = WindUtils::to360(twd);
|
||||
hstryBufList.twdHstry->add(static_cast<int16_t>(DegToRad(twd) * 1000.0));
|
||||
}
|
||||
|
||||
hstryBuffers[name] = std::unique_ptr<HstryBuf>(new HstryBuf(name, size, boatValueList, logger));
|
||||
if (twsBVal->valid) {
|
||||
calBVal = new GwApi::BoatValue("TWS"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(twsBVal->getFormat());
|
||||
calBVal->value = twsBVal->value;
|
||||
calBVal->valid = twsBVal->valid;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
tws = static_cast<uint16_t>(std::round(calBVal->value * 1000));
|
||||
if (tws >= twsHstryMin && tws <= twsHstryMax) {
|
||||
hstryBufList.twsHstry->add(tws);
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
tws += random(-5000, 5000); // TWS value in m/s; expands to 3 decimals
|
||||
tws = constrain(tws, 0, 25000); // Limit TWS to [0..25] m/s
|
||||
hstryBufList.twsHstry->add(tws);
|
||||
}
|
||||
|
||||
// Initialize metadata for buffer
|
||||
String valueFormat = bufferParams[name].format; // Data format of boat data type
|
||||
// String valueFormat = boatValueList->findValueOrCreate(name)->getFormat().c_str(); // Unfortunately, format is not yet available during system initialization
|
||||
int hstryUpdFreq = bufferParams[name].hstryUpdFreq; // Update frequency for history buffers in ms
|
||||
int mltplr = bufferParams[name].mltplr; // default multiplier which transforms original <double> value into buffer type format
|
||||
double bufferMinVal = bufferParams[name].bufferMinVal; // Min value for this history buffer
|
||||
double bufferMaxVal = bufferParams[name].bufferMaxVal; // Max value for this history buffer
|
||||
if (awaBVal->valid) {
|
||||
if (hdtBVal->valid) {
|
||||
hdt = hdtBVal->value; // Use HDT if available
|
||||
} else {
|
||||
hdt = WindUtils::calcHDT(&hdmBVal->value, &varBVal->value, &cogBVal->value, &sogBVal->value);
|
||||
}
|
||||
|
||||
hstryBuffers[name]->init(valueFormat, hstryUpdFreq, mltplr, bufferMinVal, bufferMaxVal);
|
||||
LOG_DEBUG(GwLog::DEBUG, "HstryBuffers: new buffer added: name: %s, format: %s, multiplier: %d, min value: %.2f, max value: %.2f", name, valueFormat, mltplr, bufferMinVal, bufferMaxVal);
|
||||
}
|
||||
|
||||
// Handle all registered history buffers
|
||||
void HstryBuffers::handleHstryBufs(bool useSimuData, CommonData& common)
|
||||
{
|
||||
for (auto& bufMap : hstryBuffers) {
|
||||
auto& buf = bufMap.second;
|
||||
buf->handle(useSimuData, common);
|
||||
awd = awaBVal->value + hdt;
|
||||
awd = WindUtils::to2PI(awd);
|
||||
calBVal = new GwApi::BoatValue("AWD"); // temporary solution for calibration of history buffer values
|
||||
calBVal->value = awd;
|
||||
calBVal->setFormat(awdBVal->getFormat());
|
||||
calBVal->valid = true;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
awdBVal->value = calBVal->value;
|
||||
awdBVal->valid = true;
|
||||
awd = std::round(calBVal->value * 1000.0);
|
||||
if (awd >= awdHstryMin && awd <= awdHstryMax) {
|
||||
hstryBufList.awdHstry->add(static_cast<int16_t>(awd));
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
awd += random(-20, 20);
|
||||
awd = WindUtils::to360(awd);
|
||||
hstryBufList.awdHstry->add(static_cast<int16_t>(DegToRad(awd) * 1000.0));
|
||||
}
|
||||
|
||||
if (awsBVal->valid) {
|
||||
calBVal = new GwApi::BoatValue("AWS"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(awsBVal->getFormat());
|
||||
calBVal->value = awsBVal->value;
|
||||
calBVal->valid = awsBVal->valid;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
aws = std::round(calBVal->value * 1000);
|
||||
if (aws >= awsHstryMin && aws <= awsHstryMax) {
|
||||
hstryBufList.awsHstry->add(static_cast<uint16_t>(aws));
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
aws += random(-5000, 5000); // TWS value in m/s; expands to 1 decimal
|
||||
aws = constrain(aws, 0, 25000); // Limit TWS to [0..25] m/s
|
||||
hstryBufList.awsHstry->add(aws);
|
||||
}
|
||||
}
|
||||
|
||||
RingBuffer<uint16_t>* HstryBuffers::getBuffer(const String& name)
|
||||
{
|
||||
auto it = hstryBuffers.find(name);
|
||||
if (it != hstryBuffers.end()) {
|
||||
return &it->second->hstryBuf;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
// --- End Class HstryBuffers ---------------
|
||||
// --- Class HstryBuf ---------------
|
||||
|
||||
// --- Class WindUtils --------------
|
||||
double WindUtils::to2PI(double a)
|
||||
{
|
||||
a = fmod(a, M_TWOPI);
|
||||
a = fmod(a, 2 * M_PI);
|
||||
if (a < 0.0) {
|
||||
a += M_TWOPI;
|
||||
a += 2 * M_PI;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -355,18 +162,18 @@ double WindUtils::toPI(double a)
|
||||
|
||||
double WindUtils::to360(double a)
|
||||
{
|
||||
a = fmod(a, 360.0);
|
||||
a = fmod(a, 360);
|
||||
if (a < 0.0) {
|
||||
a += 360.0;
|
||||
a += 360;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
double WindUtils::to180(double a)
|
||||
{
|
||||
a += 180.0;
|
||||
a += 180;
|
||||
a = to360(a);
|
||||
a -= 180.0;
|
||||
a -= 180;
|
||||
|
||||
return a;
|
||||
}
|
||||
@@ -398,14 +205,14 @@ void WindUtils::addPolar(const double* phi1, const double* r1,
|
||||
|
||||
void WindUtils::calcTwdSA(const double* AWA, const double* AWS,
|
||||
const double* CTW, const double* STW, const double* HDT,
|
||||
double* TWD, double* TWS, double* TWA, double* AWD)
|
||||
double* TWD, double* TWS, double* TWA)
|
||||
{
|
||||
*AWD = *AWA + *HDT;
|
||||
*AWD = to2PI(*AWD);
|
||||
double awd = *AWA + *HDT;
|
||||
awd = to2PI(awd);
|
||||
double stw = -*STW;
|
||||
addPolar(AWD, AWS, CTW, &stw, TWD, TWS);
|
||||
addPolar(&awd, AWS, CTW, &stw, TWD, TWS);
|
||||
|
||||
// Normalize TWD and TWA to 0-360°/2PI
|
||||
// Normalize TWD and TWA to 0-360°
|
||||
*TWD = to2PI(*TWD);
|
||||
*TWA = toPI(*TWD - *HDT);
|
||||
}
|
||||
@@ -427,12 +234,12 @@ double WindUtils::calcHDT(const double* hdmVal, const double* varVal, const doub
|
||||
return hdt;
|
||||
}
|
||||
|
||||
bool WindUtils::calcWinds(const double* awaVal, const double* awsVal,
|
||||
bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
||||
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal, double* awdVal)
|
||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal)
|
||||
{
|
||||
double stw, hdt, ctw;
|
||||
double twd, tws, twa, awd;
|
||||
double twd, tws, twa;
|
||||
double minSogVal = 0.1; // SOG below this value (m/s) is assumed to be data noise from GPS sensor
|
||||
|
||||
if (*hdtVal != DBL_MAX) {
|
||||
@@ -456,81 +263,60 @@ bool WindUtils::calcWinds(const double* awaVal, const double* awsVal,
|
||||
// If STW and SOG are not available, we cannot calculate true wind
|
||||
return false;
|
||||
}
|
||||
// LOG_DEBUG(GwLog::DEBUG, "WindUtils:calcWinds: HDT: %.1f, CTW %.1f, STW %.1f", hdt, ctw, stw);
|
||||
// Serial.println("\ncalcTrueWind: HDT: " + String(hdt) + ", CTW: " + String(ctw) + ", STW: " + String(stw));
|
||||
|
||||
if ((*awaVal == DBL_MAX) || (*awsVal == DBL_MAX)) {
|
||||
// Cannot calculate true wind without valid AWA, AWS; other checks are done earlier
|
||||
return false;
|
||||
} else {
|
||||
calcTwdSA(awaVal, awsVal, &ctw, &stw, &hdt, &twd, &tws, &twa, &awd);
|
||||
calcTwdSA(awaVal, awsVal, &ctw, &stw, &hdt, &twd, &tws, &twa);
|
||||
*twdVal = twd;
|
||||
*twsVal = tws;
|
||||
*twaVal = twa;
|
||||
*awdVal = awd;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate true wind data and add to obp60task boat data list
|
||||
bool WindUtils::addWinds()
|
||||
{
|
||||
double twd, tws, twa, awd, hdt;
|
||||
bool twCalculated = false;
|
||||
bool awdCalculated = false;
|
||||
bool WindUtils::addTrueWind(GwApi* api, BoatValueList* boatValues, GwLog* log) {
|
||||
|
||||
double awaVal = awaBVal->valid ? awaBVal->value : DBL_MAX;
|
||||
double awsVal = awsBVal->valid ? awsBVal->value : DBL_MAX;
|
||||
double cogVal = cogBVal->valid ? cogBVal->value : DBL_MAX;
|
||||
double stwVal = stwBVal->valid ? stwBVal->value : DBL_MAX;
|
||||
double sogVal = sogBVal->valid ? sogBVal->value : DBL_MAX;
|
||||
double hdtVal = hdtBVal->valid ? hdtBVal->value : DBL_MAX;
|
||||
double hdmVal = hdmBVal->valid ? hdmBVal->value : DBL_MAX;
|
||||
double varVal = varBVal->valid ? varBVal->value : DBL_MAX;
|
||||
LOG_DEBUG(GwLog::DEBUG, "WindUtils:addWinds: AWA %.1f, AWS %.1f, COG %.1f, STW %.1f, SOG %.2f, HDT %.1f, HDM %.1f, VAR %.1f", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852,
|
||||
cogBVal->value * RAD_TO_DEG, stwBVal->value * 3.6 / 1.852, sogBVal->value * 3.6 / 1.852, hdtBVal->value * RAD_TO_DEG, hdmBVal->value * RAD_TO_DEG, varBVal->value * RAD_TO_DEG);
|
||||
GwLog* logger = log;
|
||||
|
||||
// Check if TWD can be calculated from TWA and HDT/HDM
|
||||
if (twaBVal->valid) {
|
||||
double awaVal, awsVal, cogVal, stwVal, sogVal, hdtVal, hdmVal, varVal;
|
||||
double twd, tws, twa;
|
||||
bool isCalculated = false;
|
||||
|
||||
awaVal = awaBVal->valid ? awaBVal->value : DBL_MAX;
|
||||
awsVal = awsBVal->valid ? awsBVal->value : DBL_MAX;
|
||||
cogVal = cogBVal->valid ? cogBVal->value : DBL_MAX;
|
||||
stwVal = stwBVal->valid ? stwBVal->value : DBL_MAX;
|
||||
sogVal = sogBVal->valid ? sogBVal->value : DBL_MAX;
|
||||
hdtVal = hdtBVal->valid ? hdtBVal->value : DBL_MAX;
|
||||
hdmVal = hdmBVal->valid ? hdmBVal->value : DBL_MAX;
|
||||
varVal = varBVal->valid ? varBVal->value : DBL_MAX;
|
||||
LOG_DEBUG(GwLog::DEBUG,"obp60task addTrueWind: AWA %.1f, AWS %.1f, COG %.1f, STW %.1f, SOG %.2f, HDT %.1f, HDM %.1f, VAR %.1f", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852,
|
||||
cogBVal->value * RAD_TO_DEG, stwBVal->value * 3.6 / 1.852, sogBVal->value * 3.6 / 1.852, hdtBVal->value * RAD_TO_DEG, hdmBVal->value * RAD_TO_DEG, varBVal->value * RAD_TO_DEG);
|
||||
|
||||
isCalculated = calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &sogVal, &hdtVal, &hdmVal, &varVal, &twd, &tws, &twa);
|
||||
|
||||
if (isCalculated) { // Replace values only, if successfully calculated and not already available
|
||||
if (!twdBVal->valid) {
|
||||
if (hdtVal != DBL_MAX) {
|
||||
hdt = hdtVal; // Use HDT if available
|
||||
} else {
|
||||
hdt = calcHDT(&hdmVal, &varVal, &cogVal, &sogVal);
|
||||
}
|
||||
twd = twaBVal->value + hdt;
|
||||
twd = to2PI(twd);
|
||||
twdBVal->value = twd;
|
||||
twdBVal->valid = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Calculate true winds and AWD; if true winds exist, use at least AWD calculation
|
||||
twCalculated = calcWinds(&awaVal, &awsVal, &cogVal, &stwVal, &sogVal, &hdtVal, &hdmVal, &varVal, &twd, &tws, &twa, &awd);
|
||||
|
||||
if (twCalculated) { // Replace values only, if successfully calculated and not already available
|
||||
if (!twdBVal->valid) {
|
||||
twdBVal->value = twd;
|
||||
twdBVal->valid = true;
|
||||
}
|
||||
if (!twsBVal->valid) {
|
||||
twsBVal->value = tws;
|
||||
twsBVal->valid = true;
|
||||
}
|
||||
if (!twaBVal->valid) {
|
||||
//twaBVal->value = twa;
|
||||
twaBVal->value = to2PI(twa); // convert to [0..360], because pages cannot display negative values properly yet
|
||||
twaBVal->valid = true;
|
||||
}
|
||||
if (!awdBVal->valid) {
|
||||
awdBVal->value = awd;
|
||||
awdBVal->valid = true;
|
||||
}
|
||||
if (!twsBVal->valid) {
|
||||
twsBVal->value = tws;
|
||||
twsBVal->valid = true;
|
||||
}
|
||||
if (!twaBVal->valid) {
|
||||
twaBVal->value = twa;
|
||||
twaBVal->valid = true;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(GwLog::DEBUG, "WindUtils:addWinds: twCalculated %d, TWD %.1f, TWA %.1f, TWS %.2f kn, AWD: %.1f", twCalculated, twdBVal->value * RAD_TO_DEG,
|
||||
twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852, awdBVal->value * RAD_TO_DEG);
|
||||
LOG_DEBUG(GwLog::DEBUG,"obp60task addTrueWind: isCalculated %d, TWD %.1f, TWA %.1f, TWS %.1f", isCalculated, twdBVal->value * RAD_TO_DEG,
|
||||
twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852);
|
||||
|
||||
return twCalculated;
|
||||
return isCalculated;
|
||||
}
|
||||
// --- End Class WindUtils --------------
|
||||
// --- Class WindUtils --------------
|
||||
|
||||
@@ -1,116 +1,68 @@
|
||||
// Function lib for boat data calibration, history buffer handling, true wind calculation, and other operations on boat data
|
||||
#pragma once
|
||||
#include <N2kMessages.h>
|
||||
#include "OBPRingBuffer.h"
|
||||
#include "Pagedata.h"
|
||||
#include "BoatDataCalibration.h" // Functions lib for data instance calibration
|
||||
#include "obp60task.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <math.h>
|
||||
|
||||
// Calibration of boat data values, when user setting available
|
||||
// supported boat data types are: AWA, AWS, COG, DBS, DBT, HDM, HDT, PRPOS, RPOS, SOG, STW, TWA, TWS, TWD, WTemp
|
||||
class CalibrationData {
|
||||
private:
|
||||
typedef struct {
|
||||
double offset; // calibration offset
|
||||
double slope; // calibration slope
|
||||
double smooth; // smoothing factor
|
||||
double value; // calibrated data value (for future use)
|
||||
bool isCalibrated; // is data instance value calibrated? (for future use)
|
||||
} tCalibrationData;
|
||||
|
||||
std::unordered_map<std::string, tCalibrationData> calibrationMap; // list of calibration data instances
|
||||
std::unordered_map<std::string, double> lastValue; // array for last smoothed values of boat data values
|
||||
GwLog* logger;
|
||||
|
||||
static constexpr int8_t MAX_CALIBRATION_DATA = 4; // maximum number of calibration data instances
|
||||
|
||||
public:
|
||||
CalibrationData(GwLog* log);
|
||||
void readConfig(GwConfigHandler* config);
|
||||
void handleCalibration(BoatValueList* boatValues); // Handle calibrationMap and calibrate all boat data values
|
||||
bool calibrateInstance(GwApi::BoatValue* boatDataValue); // Calibrate single boat data value
|
||||
bool smoothInstance(GwApi::BoatValue* boatDataValue); // Smooth single boat data value
|
||||
};
|
||||
typedef struct {
|
||||
RingBuffer<int16_t>* twdHstry;
|
||||
RingBuffer<uint16_t>* twsHstry;
|
||||
RingBuffer<int16_t>* awdHstry;
|
||||
RingBuffer<uint16_t>* awsHstry;
|
||||
} tBoatHstryData; // Holds pointers to all history buffers for boat data
|
||||
|
||||
class HstryBuf {
|
||||
private:
|
||||
RingBuffer<uint16_t> hstryBuf; // Circular buffer to store history values
|
||||
String boatDataName;
|
||||
double hstryMin;
|
||||
double hstryMax;
|
||||
GwApi::BoatValue* boatValue;
|
||||
GwLog* logger;
|
||||
GwLog *logger;
|
||||
|
||||
friend class HstryBuffers;
|
||||
RingBuffer<int16_t> twdHstry; // Circular buffer to store true wind direction values
|
||||
RingBuffer<uint16_t> twsHstry; // Circular buffer to store true wind speed values (TWS)
|
||||
RingBuffer<int16_t> awdHstry; // Circular buffer to store apparant wind direction values
|
||||
RingBuffer<uint16_t> awsHstry; // Circular buffer to store apparant xwind speed values (AWS)
|
||||
int16_t twdHstryMin; // Min value for wind direction (TWD) in history buffer
|
||||
int16_t twdHstryMax; // Max value for wind direction (TWD) in history buffer
|
||||
uint16_t twsHstryMin;
|
||||
uint16_t twsHstryMax;
|
||||
int16_t awdHstryMin;
|
||||
int16_t awdHstryMax;
|
||||
uint16_t awsHstryMin;
|
||||
uint16_t awsHstryMax;
|
||||
|
||||
// boat values for buffers and for true wind calculation
|
||||
GwApi::BoatValue *twdBVal, *twsBVal, *twaBVal, *awdBVal, *awsBVal;
|
||||
GwApi::BoatValue *awaBVal, *hdtBVal, *hdmBVal, *varBVal, *cogBVal, *sogBVal;
|
||||
|
||||
public:
|
||||
HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLog* log);
|
||||
void init(const String& format, int updFreq, int mltplr, double minVal, double maxVal);
|
||||
void add(double value);
|
||||
void handle(bool useSimuData, CommonData& common);
|
||||
};
|
||||
tBoatHstryData hstryBufList;
|
||||
|
||||
class HstryBuffers {
|
||||
private:
|
||||
std::map<String, std::unique_ptr<HstryBuf>> hstryBuffers;
|
||||
int size; // size of all history buffers
|
||||
BoatValueList* boatValueList;
|
||||
GwLog* logger;
|
||||
GwApi::BoatValue *awaBVal, *hdtBVal, *hdmBVal, *varBVal, *cogBVal, *sogBVal, *awdBVal; // boat values for true wind calculation
|
||||
|
||||
struct HistoryParams {
|
||||
int hstryUpdFreq; // update frequency of history buffer (documentation only)
|
||||
int mltplr; // specifies actual value precision being storable:
|
||||
// [10000: 0 - 6.5535 | 1000: 0 - 65.535 | 100: 0 - 650.35 | 10: 0 - 6503.5
|
||||
double bufferMinVal; // minimum valid data value
|
||||
double bufferMaxVal; // maximum valid data value
|
||||
String format; // format of data type
|
||||
HstryBuf(){
|
||||
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; // Generate history buffers of zero size
|
||||
};
|
||||
|
||||
// Define buffer parameters for supported boat data type
|
||||
std::map<String, HistoryParams> bufferParams = {
|
||||
{ "AWA", { 1000, 10000, 0.0, M_TWOPI, "formatWind" } },
|
||||
{ "AWD", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "AWS", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "COG", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "DBS", { 1000, 100, 0.0, 650.0, "formatDepth" } },
|
||||
{ "DBT", { 1000, 100, 0.0, 650.0, "formatDepth" } },
|
||||
{ "DPT", { 1000, 100, 0.0, 650.0, "formatDepth" } },
|
||||
{ "HDM", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "HDT", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "ROT", { 1000, 10000, -M_PI / 180.0 * 99.0, M_PI / 180.0 * 99.0, "formatRot" } }, // min/max is -/+ 99 degrees for "rate of turn"
|
||||
{ "SOG", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "STW", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "TWA", { 1000, 10000, 0.0, M_TWOPI, "formatWind" } },
|
||||
{ "TWD", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "TWS", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "WTemp", { 1000, 100, 233.0, 650.0, "kelvinToC" } } // [-50..376] °C
|
||||
HstryBuf(int size) {
|
||||
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry};
|
||||
hstryBufList.twdHstry->resize(960); // store 960 TWD values for 16 minutes history
|
||||
hstryBufList.twsHstry->resize(960);
|
||||
hstryBufList.awdHstry->resize(960);
|
||||
hstryBufList.awsHstry->resize(960);
|
||||
};
|
||||
|
||||
public:
|
||||
HstryBuffers(int size, BoatValueList* boatValues, GwLog* log);
|
||||
void addBuffer(const String& name);
|
||||
void handleHstryBufs(bool useSimuData, CommonData& common);
|
||||
RingBuffer<uint16_t>* getBuffer(const String& name);
|
||||
void init(BoatValueList* boatValues, GwLog *log);
|
||||
void handleHstryBuf(bool useSimuData);
|
||||
};
|
||||
|
||||
class WindUtils {
|
||||
private:
|
||||
GwApi::BoatValue *twaBVal, *twsBVal, *twdBVal;
|
||||
GwApi::BoatValue *awaBVal, *awsBVal, *awdBVal, *cogBVal, *stwBVal, *sogBVal, *hdtBVal, *hdmBVal, *varBVal;
|
||||
GwApi::BoatValue *twdBVal, *twsBVal, *twaBVal;
|
||||
GwApi::BoatValue *awaBVal, *awsBVal, *cogBVal, *stwBVal, *sogBVal, *hdtBVal, *hdmBVal, *varBVal;
|
||||
static constexpr double DBL_MAX = std::numeric_limits<double>::max();
|
||||
GwLog* logger;
|
||||
|
||||
public:
|
||||
WindUtils(BoatValueList* boatValues, GwLog* log)
|
||||
: logger(log)
|
||||
{
|
||||
twaBVal = boatValues->findValueOrCreate("TWA");
|
||||
twsBVal = boatValues->findValueOrCreate("TWS");
|
||||
WindUtils(BoatValueList* boatValues){
|
||||
twdBVal = boatValues->findValueOrCreate("TWD");
|
||||
twsBVal = boatValues->findValueOrCreate("TWS");
|
||||
twaBVal = boatValues->findValueOrCreate("TWA");
|
||||
awaBVal = boatValues->findValueOrCreate("AWA");
|
||||
awsBVal = boatValues->findValueOrCreate("AWS");
|
||||
awdBVal = boatValues->findValueOrCreate("AWD");
|
||||
cogBVal = boatValues->findValueOrCreate("COG");
|
||||
stwBVal = boatValues->findValueOrCreate("STW");
|
||||
sogBVal = boatValues->findValueOrCreate("SOG");
|
||||
@@ -118,7 +70,6 @@ public:
|
||||
hdmBVal = boatValues->findValueOrCreate("HDM");
|
||||
varBVal = boatValues->findValueOrCreate("VAR");
|
||||
};
|
||||
|
||||
static double to2PI(double a);
|
||||
static double toPI(double a);
|
||||
static double to360(double a);
|
||||
@@ -130,10 +81,10 @@ public:
|
||||
double* phi, double* r);
|
||||
void calcTwdSA(const double* AWA, const double* AWS,
|
||||
const double* CTW, const double* STW, const double* HDT,
|
||||
double* TWD, double* TWS, double* TWA, double* AWD);
|
||||
double* TWD, double* TWS, double* TWA);
|
||||
static double calcHDT(const double* hdmVal, const double* varVal, const double* cogVal, const double* sogVal);
|
||||
bool calcWinds(const double* awaVal, const double* awsVal,
|
||||
bool calcTrueWind(const double* awaVal, const double* awsVal,
|
||||
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal, double* awdVal);
|
||||
bool addWinds();
|
||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal);
|
||||
bool addTrueWind(GwApi* api, BoatValueList* boatValues, GwLog *log);
|
||||
};
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef _OBP60FUNCTIONS_H
|
||||
#define _OBP60FUNCTIONS_H
|
||||
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
#include <Arduino.h>
|
||||
#include "OBP60Hardware.h"
|
||||
|
||||
#include "OBP60Extensions.h" // for buzzer
|
||||
#include "OBPKeyboardTask.h"
|
||||
|
||||
// Global vars
|
||||
|
||||
// Touch keypad over ESP32 touch sensor inputs
|
||||
@@ -58,10 +59,10 @@ void initKeys(CommonData &commonData) {
|
||||
commonData.keydata[5].h = height;
|
||||
}
|
||||
|
||||
#if defined HARDWARE_V20 || HARDWARE_V21
|
||||
// Keypad functions for original OBP60 hardware
|
||||
int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) {
|
||||
|
||||
#ifdef HARDWARE_V21
|
||||
// Keypad functions for original OBP60 hardware
|
||||
int readKeypad(GwLog* logger, uint thSensitivity) {
|
||||
|
||||
// Touch sensor values
|
||||
// 35000 - Not touched
|
||||
// 50000 - Light toched with fingertip
|
||||
@@ -233,35 +234,35 @@ void initKeys(CommonData &commonData) {
|
||||
keycodeold2 = keycode2;
|
||||
|
||||
return keystatus;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOARD_OBP40S3
|
||||
int readSensorpads(){
|
||||
// Read key code
|
||||
if(digitalRead(UP) == LOW){
|
||||
#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;
|
||||
}
|
||||
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) {
|
||||
// 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);
|
||||
@@ -273,31 +274,68 @@ void initKeys(CommonData &commonData) {
|
||||
|
||||
// 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;
|
||||
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;
|
||||
// 100% Task-CPU RLY?
|
||||
while(readSensorpads() > 0){} // Wait for pad release
|
||||
delay(keydelay);
|
||||
}
|
||||
// Copy keycode
|
||||
keycodeold = keycode;
|
||||
while(readSensorpads() > 0){} // Wait for pad release
|
||||
delay(keydelay);
|
||||
}
|
||||
}
|
||||
else{
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keystatus = 0;
|
||||
else {
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keystatus = 0;
|
||||
}
|
||||
|
||||
return keystatus;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void keyboardTask(void *param) {
|
||||
|
||||
// params needed:
|
||||
// queue
|
||||
// logger
|
||||
// sensitivity
|
||||
// use_syspage for deep sleep activation
|
||||
|
||||
KbTaskData *data = (KbTaskData *)param;
|
||||
|
||||
int keycode = 0;
|
||||
data->logger->logDebug(GwLog::LOG, "Start keyboard task");
|
||||
|
||||
while (true) {
|
||||
#ifdef BOARD_OBP40S3
|
||||
keycode = readKeypad(data->logger, data->sensitivity, data->use_syspage);
|
||||
#else
|
||||
keycode = readKeypad(data->logger, data->sensitivity);
|
||||
#endif
|
||||
//send a key event
|
||||
if (keycode != 0) {
|
||||
xQueueSend(data->queue, &keycode, 0);
|
||||
data->logger->logDebug(GwLog::LOG,"kbtask: send keycode: %d", keycode);
|
||||
}
|
||||
delay(20); // 50Hz update rate (20ms)
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void createKeyboardTask(KbTaskData *param) {
|
||||
TaskHandle_t xHandle = NULL;
|
||||
if (xTaskCreate(keyboardTask, "keyboard", configMINIMAL_STACK_SIZE + 1024, param, configMAX_PRIORITIES-1, &xHandle) != pdPASS) {
|
||||
param->logger->logDebug(GwLog::ERROR, "Failed to create keyboard task!");
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
16
lib/obp60task/OBPKeyboardTask.h
Normal file
16
lib/obp60task/OBPKeyboardTask.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
#include "GwLog.h"
|
||||
#include "Pagedata.h"
|
||||
|
||||
typedef struct {
|
||||
QueueHandle_t queue;
|
||||
GwLog* logger = nullptr;
|
||||
uint sensitivity = 100;
|
||||
#ifdef BOARD_OBP40S3
|
||||
bool use_syspage = true;
|
||||
#endif
|
||||
} KbTaskData;
|
||||
|
||||
void initKeys(CommonData &commonData);
|
||||
void createKeyboardTask(KbTaskData *param);
|
||||
@@ -1,44 +1,15 @@
|
||||
#pragma once
|
||||
#include "FreeRTOS.h"
|
||||
#include "GwSynchronized.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <WString.h>
|
||||
|
||||
template <typename T>
|
||||
struct PSRAMAllocator {
|
||||
using value_type = T;
|
||||
|
||||
PSRAMAllocator() = default;
|
||||
|
||||
template <class U>
|
||||
constexpr PSRAMAllocator(const PSRAMAllocator<U>&) noexcept { }
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
void* ptr = heap_caps_malloc(n * sizeof(T), MALLOC_CAP_SPIRAM);
|
||||
if (!ptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return static_cast<T*>(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) noexcept
|
||||
{
|
||||
heap_caps_free(p);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
bool operator==(const PSRAMAllocator<T>&, const PSRAMAllocator<U>&) { return true; }
|
||||
|
||||
template <class T, class U>
|
||||
bool operator!=(const PSRAMAllocator<T>&, const PSRAMAllocator<U>&) { return false; }
|
||||
#include "WString.h"
|
||||
|
||||
template <typename T>
|
||||
class RingBuffer {
|
||||
private:
|
||||
std::vector<T, PSRAMAllocator<T>> buffer; // THE buffer vector, allocated in PSRAM
|
||||
std::vector<T> buffer; // THE buffer vector
|
||||
size_t capacity;
|
||||
size_t head; // Points to the next insertion position
|
||||
size_t first; // Points to the first (oldest) valid element
|
||||
@@ -47,52 +18,49 @@ private:
|
||||
bool is_Full; // Indicates that all buffer elements are used and ringing is in use
|
||||
T MIN_VAL; // lowest possible value of buffer of type <T>
|
||||
T MAX_VAL; // highest possible value of buffer of type <T> -> indicates invalid value in buffer
|
||||
double dblMIN_VAL, dblMAX_VAL; // MIN_VAL, MAX_VAL in double format
|
||||
mutable SemaphoreHandle_t bufLocker;
|
||||
|
||||
// metadata for buffer
|
||||
String dataName; // Name of boat data in buffer
|
||||
String dataFmt; // Format of boat data in buffer
|
||||
int updFreq; // Update frequency in milliseconds
|
||||
double mltplr; // Multiplier which transforms original <double> value into buffer type format
|
||||
double smallest; // Value range of buffer: smallest value; needs to be => MIN_VAL
|
||||
double largest; // Value range of buffer: biggest value; needs to be < MAX_VAL, since MAX_VAL indicates invalid entries
|
||||
T smallest; // Value range of buffer: smallest value; needs to be => MIN_VAL
|
||||
T largest; // Value range of buffer: biggest value; needs to be < MAX_VAL, since MAX_VAL indicates invalid entries
|
||||
|
||||
void initCommon();
|
||||
|
||||
public:
|
||||
RingBuffer();
|
||||
RingBuffer(size_t size);
|
||||
void setMetaData(String name, String format, int updateFrequency, double multiplier, double minValue, double maxValue); // Set meta data for buffer
|
||||
bool getMetaData(String& name, String& format, int& updateFrequency, double& multiplier, double& minValue, double& maxValue); // Get meta data of buffer
|
||||
void setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue); // Set meta data for buffer
|
||||
bool getMetaData(String& name, String& format, int& updateFrequency, T& minValue, T& maxValue); // Get meta data of buffer
|
||||
bool getMetaData(String& name, String& format);
|
||||
String getName() const; // Get buffer name
|
||||
String getFormat() const; // Get buffer data format
|
||||
void add(const double& value); // Add a new value to buffer
|
||||
double get(size_t index) const; // Get value at specific position (0-based index from oldest to newest)
|
||||
double getFirst() const; // Get the first (oldest) value in buffer
|
||||
double getLast() const; // Get the last (newest) value in buffer
|
||||
double getMin() const; // Get the lowest value in buffer
|
||||
double getMin(size_t amount) const; // Get minimum value of the last <amount> values of buffer
|
||||
double getMax() const; // Get the highest value in buffer
|
||||
double getMax(size_t amount) const; // Get maximum value of the last <amount> values of buffer
|
||||
double getMid() const; // Get mid value between <min> and <max> value in buffer
|
||||
double getMid(size_t amount) const; // Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||
double getMedian() const; // Get the median value in buffer
|
||||
double getMedian(size_t amount) const; // Get the median value of the last <amount> values of buffer
|
||||
void add(const T& value); // Add a new value to buffer
|
||||
T get(size_t index) const; // Get value at specific position (0-based index from oldest to newest)
|
||||
T getFirst() const; // Get the first (oldest) value in buffer
|
||||
T getLast() const; // Get the last (newest) value in buffer
|
||||
T getMin() const; // Get the lowest value in buffer
|
||||
T getMin(size_t amount) const; // Get minimum value of the last <amount> values of buffer
|
||||
T getMax() const; // Get the highest value in buffer
|
||||
T getMax(size_t amount) const; // Get maximum value of the last <amount> values of buffer
|
||||
T getMid() const; // Get mid value between <min> and <max> value in buffer
|
||||
T getMid(size_t amount) const; // Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||
T getMedian() const; // Get the median value in buffer
|
||||
T getMedian(size_t amount) const; // Get the median value of the last <amount> values of buffer
|
||||
size_t getCapacity() const; // Get the buffer capacity (maximum size)
|
||||
size_t getCurrentSize() const; // Get the current number of elements in buffer
|
||||
size_t getFirstIdx() const; // Get the index of oldest value in buffer
|
||||
size_t getLastIdx() const; // Get the index of newest value in buffer
|
||||
bool isEmpty() const; // Check if buffer is empty
|
||||
bool isFull() const; // Check if buffer is full
|
||||
double getMinVal() const; // Get lowest possible value for buffer
|
||||
double getMaxVal() const; // Get highest possible value for buffer; used for unset/invalid buffer data
|
||||
T getMinVal() const; // Get lowest possible value for buffer
|
||||
T getMaxVal() const; // Get highest possible value for buffer; used for unset/invalid buffer data
|
||||
void clear(); // Clear buffer
|
||||
void resize(size_t size); // Delete buffer and set new size
|
||||
double operator[](size_t index) const; // Operator[] for convenient access (same as get())
|
||||
std::vector<double> getAllValues() const; // Get all current values in native buffer format as a vector
|
||||
std::vector<double> getAllValues(size_t amount) const; // Get last <amount> values in native buffer format as a vector
|
||||
T operator[](size_t index) const; // Operator[] for convenient access (same as get())
|
||||
std::vector<T> getAllValues() const; // Get all current values as a vector
|
||||
};
|
||||
|
||||
#include "OBPRingBuffer.tpp"
|
||||
@@ -1,21 +1,14 @@
|
||||
#include "OBPRingBuffer.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T>
|
||||
void RingBuffer<T>::initCommon()
|
||||
{
|
||||
void RingBuffer<T>::initCommon() {
|
||||
MIN_VAL = std::numeric_limits<T>::lowest();
|
||||
MAX_VAL = std::numeric_limits<T>::max();
|
||||
dblMIN_VAL = static_cast<double>(MIN_VAL);
|
||||
dblMAX_VAL = static_cast<double>(MAX_VAL);
|
||||
dataName = "";
|
||||
dataFmt = "";
|
||||
updFreq = -1;
|
||||
mltplr = 1;
|
||||
smallest = dblMIN_VAL;
|
||||
largest = dblMAX_VAL;
|
||||
smallest = MIN_VAL;
|
||||
largest = MAX_VAL;
|
||||
bufLocker = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
@@ -42,27 +35,24 @@ RingBuffer<T>::RingBuffer(size_t size)
|
||||
, is_Full(false)
|
||||
{
|
||||
initCommon();
|
||||
|
||||
buffer.reserve(size);
|
||||
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values
|
||||
}
|
||||
|
||||
// Specify meta data of buffer content
|
||||
template <typename T>
|
||||
void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency, double multiplier, double minValue, double maxValue)
|
||||
void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue)
|
||||
{
|
||||
GWSYNCHRONIZED(&bufLocker);
|
||||
dataName = name;
|
||||
dataFmt = format;
|
||||
updFreq = updateFrequency;
|
||||
mltplr = multiplier;
|
||||
smallest = std::max(dblMIN_VAL, minValue);
|
||||
largest = std::min(dblMAX_VAL, maxValue);
|
||||
smallest = std::max(MIN_VAL, minValue);
|
||||
largest = std::min(MAX_VAL, maxValue);
|
||||
}
|
||||
|
||||
// Get meta data of buffer content
|
||||
template <typename T>
|
||||
bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequency, double& multiplier, double& minValue, double& maxValue)
|
||||
bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequency, T& minValue, T& maxValue)
|
||||
{
|
||||
if (dataName == "" || dataFmt == "" || updFreq == -1) {
|
||||
return false; // Meta data not set
|
||||
@@ -72,7 +62,6 @@ bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequen
|
||||
name = dataName;
|
||||
format = dataFmt;
|
||||
updateFrequency = updFreq;
|
||||
multiplier = mltplr;
|
||||
minValue = smallest;
|
||||
maxValue = largest;
|
||||
return true;
|
||||
@@ -108,13 +97,13 @@ String RingBuffer<T>::getFormat() const
|
||||
|
||||
// Add a new value to buffer
|
||||
template <typename T>
|
||||
void RingBuffer<T>::add(const double& value)
|
||||
void RingBuffer<T>::add(const T& value)
|
||||
{
|
||||
GWSYNCHRONIZED(&bufLocker);
|
||||
if (value < smallest || value > largest) {
|
||||
buffer[head] = MAX_VAL; // Store MAX_VAL if value is out of range
|
||||
} else {
|
||||
buffer[head] = static_cast<T>(std::round(value * mltplr));
|
||||
buffer[head] = value;
|
||||
}
|
||||
last = head;
|
||||
|
||||
@@ -126,63 +115,63 @@ void RingBuffer<T>::add(const double& value)
|
||||
is_Full = true;
|
||||
}
|
||||
}
|
||||
// Serial.printf("Ringbuffer: value %.3f, multiplier: %.1f, buffer: %d\n", value, mltplr, buffer[head]);
|
||||
|
||||
head = (head + 1) % capacity;
|
||||
}
|
||||
|
||||
// Get value at specific position (0-based index from oldest to newest)
|
||||
template <typename T>
|
||||
double RingBuffer<T>::get(size_t index) const
|
||||
T RingBuffer<T>::get(size_t index) const
|
||||
{
|
||||
GWSYNCHRONIZED(&bufLocker);
|
||||
if (isEmpty() || index < 0 || index >= count) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
||||
size_t realIndex = (first + index) % capacity;
|
||||
return static_cast<double>(buffer[realIndex] / mltplr);
|
||||
return buffer[realIndex];
|
||||
}
|
||||
|
||||
// Operator[] for convenient access (same as get())
|
||||
template <typename T>
|
||||
double RingBuffer<T>::operator[](size_t index) const
|
||||
T RingBuffer<T>::operator[](size_t index) const
|
||||
{
|
||||
return get(index);
|
||||
}
|
||||
|
||||
// Get the first (oldest) value in the buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getFirst() const
|
||||
T RingBuffer<T>::getFirst() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
return get(0);
|
||||
}
|
||||
|
||||
// Get the last (newest) value in the buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getLast() const
|
||||
T RingBuffer<T>::getLast() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
return get(count - 1);
|
||||
}
|
||||
|
||||
// Get the lowest value in the buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMin() const
|
||||
T RingBuffer<T>::getMin() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
||||
double minVal = dblMAX_VAL;
|
||||
double value;
|
||||
T minVal = MAX_VAL;
|
||||
T value;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
value = get(i);
|
||||
if (value < minVal && value != dblMAX_VAL) {
|
||||
if (value < minVal && value != MAX_VAL) {
|
||||
minVal = value;
|
||||
}
|
||||
}
|
||||
@@ -191,19 +180,19 @@ double RingBuffer<T>::getMin() const
|
||||
|
||||
// Get minimum value of the last <amount> values of buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMin(size_t amount) const
|
||||
T RingBuffer<T>::getMin(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
double minVal = dblMAX_VAL;
|
||||
double value;
|
||||
T minVal = MAX_VAL;
|
||||
T value;
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
value = get(count - 1 - i);
|
||||
if (value < minVal && value != dblMAX_VAL) {
|
||||
if (value < minVal && value != MAX_VAL) {
|
||||
minVal = value;
|
||||
}
|
||||
}
|
||||
@@ -212,81 +201,75 @@ double RingBuffer<T>::getMin(size_t amount) const
|
||||
|
||||
// Get the highest value in the buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMax() const
|
||||
T RingBuffer<T>::getMax() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
||||
double maxVal = dblMIN_VAL;
|
||||
double value;
|
||||
T maxVal = MIN_VAL;
|
||||
T value;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
value = get(i);
|
||||
if (value > maxVal && value != dblMAX_VAL) {
|
||||
if (value > maxVal && value != MAX_VAL) {
|
||||
maxVal = value;
|
||||
}
|
||||
}
|
||||
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
|
||||
maxVal = dblMAX_VAL;
|
||||
}
|
||||
return maxVal;
|
||||
}
|
||||
|
||||
// Get maximum value of the last <amount> values of buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMax(size_t amount) const
|
||||
T RingBuffer<T>::getMax(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
double maxVal = dblMIN_VAL;
|
||||
double value;
|
||||
T maxVal = MIN_VAL;
|
||||
T value;
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
value = get(count - 1 - i);
|
||||
if (value > maxVal && value != dblMAX_VAL) {
|
||||
if (value > maxVal && value != MAX_VAL) {
|
||||
maxVal = value;
|
||||
}
|
||||
}
|
||||
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
|
||||
maxVal = dblMAX_VAL;
|
||||
}
|
||||
return maxVal;
|
||||
}
|
||||
|
||||
// Get mid value between <min> and <max> value in the buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMid() const
|
||||
T RingBuffer<T>::getMid() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
||||
return (getMin() + getMax()) / 2;
|
||||
return (getMin() + getMax()) / static_cast<T>(2);
|
||||
}
|
||||
|
||||
// Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMid(size_t amount) const
|
||||
T RingBuffer<T>::getMid(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
return (getMin(amount) + getMax(amount)) / 2;
|
||||
return (getMin(amount) + getMax(amount)) / static_cast<T>(2);
|
||||
}
|
||||
|
||||
// Get the median value in the buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMedian() const
|
||||
T RingBuffer<T>::getMedian() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
||||
// Create a temporary vector with current valid elements
|
||||
@@ -302,20 +285,20 @@ double RingBuffer<T>::getMedian() const
|
||||
|
||||
if (count % 2 == 1) {
|
||||
// Odd number of elements
|
||||
return static_cast<double>(temp[count / 2]);
|
||||
return temp[count / 2];
|
||||
} else {
|
||||
// Even number of elements - return average of middle two
|
||||
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||
return static_cast<double>((temp[count / 2 - 1] + temp[count / 2]) / 2);
|
||||
return (temp[count / 2 - 1] + temp[count / 2]) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the median value of the last <amount> values of buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMedian(size_t amount) const
|
||||
T RingBuffer<T>::getMedian(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
@@ -325,7 +308,7 @@ double RingBuffer<T>::getMedian(size_t amount) const
|
||||
temp.reserve(amount);
|
||||
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
temp.push_back(get(count - 1 - i));
|
||||
temp.push_back(get(i));
|
||||
}
|
||||
|
||||
// Sort to find median
|
||||
@@ -333,11 +316,11 @@ double RingBuffer<T>::getMedian(size_t amount) const
|
||||
|
||||
if (amount % 2 == 1) {
|
||||
// Odd number of elements
|
||||
return static_cast<double>(temp[amount / 2]);
|
||||
return temp[amount / 2];
|
||||
} else {
|
||||
// Even number of elements - return average of middle two
|
||||
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||
return static_cast<double>((temp[amount / 2 - 1] + temp[amount / 2]) / 2);
|
||||
return (temp[amount / 2 - 1] + temp[amount / 2]) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,16 +368,16 @@ bool RingBuffer<T>::isFull() const
|
||||
|
||||
// Get lowest possible value for buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMinVal() const
|
||||
T RingBuffer<T>::getMinVal() const
|
||||
{
|
||||
return dblMIN_VAL;
|
||||
return MIN_VAL;
|
||||
}
|
||||
|
||||
// Get highest possible value for buffer; used for unset/invalid buffer data
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMaxVal() const
|
||||
T RingBuffer<T>::getMaxVal() const
|
||||
{
|
||||
return dblMAX_VAL;
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
||||
// Clear buffer
|
||||
@@ -422,41 +405,19 @@ void RingBuffer<T>::resize(size_t newSize)
|
||||
is_Full = false;
|
||||
|
||||
buffer.clear();
|
||||
buffer.reserve(newSize);
|
||||
buffer.resize(newSize, MAX_VAL);
|
||||
}
|
||||
|
||||
// Get all current values in native buffer format as a vector
|
||||
// Get all current values as a vector
|
||||
template <typename T>
|
||||
std::vector<double> RingBuffer<T>::getAllValues() const
|
||||
std::vector<T> RingBuffer<T>::getAllValues() const
|
||||
{
|
||||
std::vector<double> result;
|
||||
std::vector<T> result;
|
||||
result.reserve(count);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
result.push_back(get(i));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get last <amount> values in native buffer format as a vector
|
||||
template <typename T>
|
||||
std::vector<double> RingBuffer<T>::getAllValues(size_t amount) const
|
||||
{
|
||||
std::vector<double> result;
|
||||
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return result;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
result.reserve(amount);
|
||||
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
result.push_back(get(count - 1 - i));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
#include <Adafruit_Sensor.h> // Adafruit Lib for sensors
|
||||
#include <Adafruit_BME280.h> // Adafruit Lib for BME280
|
||||
@@ -49,10 +50,8 @@ void sensorTask(void *param){
|
||||
|
||||
// Init sensor stuff
|
||||
bool oneWire_ready = false; // 1Wire initialized and ready to use
|
||||
bool iRTC_ready = false; // Software RTC initialized and ready to use
|
||||
bool RTC_ready = false; // DS1388 initialized and ready to use
|
||||
bool GPS_ready = false; // GPS initialized and ready to use
|
||||
bool N2K_GPS_ready = false; // GPS time on N2K bus
|
||||
bool BME280_ready = false; // BME280 initialized and ready to use
|
||||
bool BMP280_ready = false; // BMP280 initialized and ready to use
|
||||
bool BMP180_ready = false; // BMP180 initialized and ready to use
|
||||
@@ -92,16 +91,16 @@ 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
|
||||
#ifdef VOLTAGE_SENSOR
|
||||
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||
#else
|
||||
#else
|
||||
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||
#endif
|
||||
#endif
|
||||
sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration
|
||||
#ifdef LIPO_ACCU_1200
|
||||
#ifdef LIPO_ACCU_1200
|
||||
sensors.BatteryChargeStatus = 0; // Set to discharging
|
||||
sensors.batteryLevelLiPo = 0; // Level 0...100%
|
||||
#endif
|
||||
#endif
|
||||
sensors.batteryCurrent = 0;
|
||||
sensors.batteryPower = 0;
|
||||
// Fill average arrays with start values
|
||||
@@ -384,7 +383,6 @@ void sensorTask(void *param){
|
||||
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);
|
||||
iRTC_ready = true;
|
||||
sensors.rtcValid = true;
|
||||
} else {
|
||||
api->getLogger()->logDebug(GwLog::LOG,"NTP time fetch failed!");
|
||||
@@ -403,7 +401,7 @@ void sensorTask(void *param){
|
||||
if (millis() > starttime0 + 100)
|
||||
{
|
||||
starttime0 = millis();
|
||||
// Send NMEA0183 GPS data on several bus systems (N2K an 0183) all 100ms
|
||||
// Send NMEA0183 GPS data on several bus systems all 100ms
|
||||
if (GPS_ready == true && hdop->value <= hdopAccuracy)
|
||||
{
|
||||
SNMEA0183Msg NMEA0183Msg;
|
||||
@@ -415,55 +413,9 @@ void sensorTask(void *param){
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Time set logic for RTC and N2K
|
||||
###############################
|
||||
|
||||
iRTC = Software RTC updatetd with NTP via internet
|
||||
RTC = RTC chip on PCB
|
||||
GPS = GPS Receiver on PCB
|
||||
N2K = GPS time on N2K od 183 bus
|
||||
0 = device not ready
|
||||
1 = device ready
|
||||
X = independend
|
||||
() = source for set time N2K
|
||||
-> = set RTC via iRTC
|
||||
<- = set RTC via GPS
|
||||
|
||||
iRTC RTC GPS N2K
|
||||
0 0 0 (1)
|
||||
0 0 (1) (X)
|
||||
0 (1) 0 (X)
|
||||
0 1 <-(1) (X)
|
||||
(1) 0 0 (X)
|
||||
1 0 (1) (X)
|
||||
1 ->(1) 0 (X)
|
||||
1 1 <-(1) (X)
|
||||
|
||||
*/
|
||||
|
||||
// If RTC DS1388 ready, then copy iRTC and GPS data to RTC all 1min
|
||||
if(millis() > starttime11 + 1*60*1000){
|
||||
// If RTC DS1388 ready, then copy GPS data to RTC all 5min
|
||||
if(millis() > starttime11 + 5*60*1000){
|
||||
starttime11 = millis();
|
||||
// Set RTC chip via iRTC (NTP)
|
||||
if(iRTC_ready == true && RTC_ready == true && GPS_ready == false){
|
||||
GwApi::Status status;
|
||||
api->getStatus(status);
|
||||
// Check WiFi connection
|
||||
if (status.wifiClientConnected) {
|
||||
sensors.rtcTime = rtc.getTimeStruct(); // Get time from software RTC (iRTC)
|
||||
DateTime now = DateTime(
|
||||
sensors.rtcTime.tm_year + 1900,
|
||||
sensors.rtcTime.tm_mon + 1,
|
||||
sensors.rtcTime.tm_mday,
|
||||
sensors.rtcTime.tm_hour,
|
||||
sensors.rtcTime.tm_min,
|
||||
sensors.rtcTime.tm_sec
|
||||
);
|
||||
ds1388.adjust(now);
|
||||
}
|
||||
}
|
||||
// Set RTC chip via internal GPS
|
||||
if(rtcOn == "DS1388" && RTC_ready == true && GPS_ready == true){
|
||||
api->getBoatDataValues(3,valueList);
|
||||
if(gpsdays->valid && gpsseconds->valid && hdop->valid){
|
||||
@@ -471,33 +423,40 @@ void sensorTask(void *param){
|
||||
// sample input: date = "Dec 26 2009", time = "12:34:56"
|
||||
// ds1388.adjust(DateTime("Dec 26 2009", "12:34:56"));
|
||||
DateTime adjusttime(ts);
|
||||
api->getLogger()->logDebug(GwLog::LOG,"Adjust RTC time via internal GPS: %04d/%02d/%02d %02d:%02d:%02d",adjusttime.year(), adjusttime.month(), adjusttime.day(), adjusttime.hour(), adjusttime.minute(), adjusttime.second());
|
||||
api->getLogger()->logDebug(GwLog::LOG,"Adjust RTC time: %04d/%02d/%02d %02d:%02d:%02d",adjusttime.year(), adjusttime.month(), adjusttime.day(), adjusttime.hour(), adjusttime.minute(), adjusttime.second());
|
||||
// Adjust RTC time as unix time value
|
||||
ds1388.adjust(adjusttime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set RTC chip via N2K or 183 in case the internal GPS is off (only one time)
|
||||
if(N2K_GPS_ready == false && RTC_ready == true && GPS_ready == false){
|
||||
api->getBoatDataValues(3,valueList);
|
||||
if(gpsdays->valid && gpsseconds->valid && hdop->valid){
|
||||
long ts = tNMEA0183Msg::daysToTime_t(gpsdays->value - (30*365+7))+floor(gpsseconds->value); // Adjusted to reference year 2000 (-30 years and 7 days for switch years)
|
||||
// sample input: date = "Dec 26 2009", time = "12:34:56"
|
||||
// ds1388.adjust(DateTime("Dec 26 2009", "12:34:56"));
|
||||
DateTime adjusttime(ts);
|
||||
api->getLogger()->logDebug(GwLog::LOG,"Adjust RTC time via N2K/183: %04d/%02d/%02d %02d:%02d:%02d",adjusttime.year(), adjusttime.month(), adjusttime.day(), adjusttime.hour(), adjusttime.minute(), adjusttime.second());
|
||||
// Adjust RTC time as unix time value
|
||||
ds1388.adjust(adjusttime);
|
||||
// N2K GPS time ready
|
||||
N2K_GPS_ready = true;
|
||||
}
|
||||
// Send 1Wire data for all temperature sensors all 2s
|
||||
if(millis() > starttime13 + 2000 && String(oneWireOn) == "DS18B20" && oneWire_ready == true){
|
||||
starttime13 = millis();
|
||||
float tempC;
|
||||
ds18b20.requestTemperatures(); // Collect all temperature values (max.8)
|
||||
for(int i=0;i<numberOfDevices; i++){
|
||||
// Send only one 1Wire data per loop step (time reduction)
|
||||
if(i == loopCounter % numberOfDevices){
|
||||
if(ds18b20.getAddress(tempDeviceAddress, i)){
|
||||
// Read temperature value in Celsius
|
||||
tempC = ds18b20.getTempC(tempDeviceAddress);
|
||||
}
|
||||
// Send to NMEA200 bus for each sensor with instance number
|
||||
if(!isnan(tempC)){
|
||||
sensors.onewireTemp[i] = tempC; // Save values in SensorData
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"DS18B20-%1d Temp: %.1f",i,tempC);
|
||||
SetN2kPGN130316(N2kMsg, 0, i, N2kts_OutsideTemperature, CToKelvin(tempC), N2kDoubleNA);
|
||||
api->sendN2kMessage(N2kMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
loopCounter++;
|
||||
}
|
||||
|
||||
// Send RTC date and time to N2K all 500ms
|
||||
// Get current RTC date and time all 500ms
|
||||
if (millis() > starttime12 + 500) {
|
||||
starttime12 = millis();
|
||||
// Send date and time from RTC chip if GPS not ready
|
||||
if (rtcOn == "DS1388" && RTC_ready) {
|
||||
DateTime dt = ds1388.now();
|
||||
sensors.rtcTime.tm_year = dt.year() - 1900; // Save values in SensorData
|
||||
@@ -523,83 +482,42 @@ void sensorTask(void *param){
|
||||
}
|
||||
// N2K sysTime is double in n2klib
|
||||
double sysTime = (dt.hour() * 3600) + (dt.minute() * 60) + dt.second();
|
||||
if(!isnan(daysAt1970) && !isnan(sysTime)){
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send date and time from software RTC (iRTC)
|
||||
if (iRTC_ready == true && RTC_ready == false && GPS_ready == false) {
|
||||
// Use internal RTC feature
|
||||
sensors.rtcTime = rtc.getTimeStruct(); // Save software RTC values in SensorData
|
||||
// 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 = ((sensors.rtcTime.tm_year-1)-1968)/4 - ((sensors.rtcTime.tm_year-1)-1900)/100 + ((sensors.rtcTime.tm_year-1)-1600)/400;
|
||||
long daysAt1970 = (sensors.rtcTime.tm_year-1970)*365 + switchYear + daysOfYear[sensors.rtcTime.tm_mon-1] + sensors.rtcTime.tm_mday-1;
|
||||
// If switch year then add one day
|
||||
if ((sensors.rtcTime.tm_mon > 2) && (sensors.rtcTime.tm_year % 4 == 0 && (sensors.rtcTime.tm_year % 100 != 0 || sensors.rtcTime.tm_year % 400 == 0))) {
|
||||
daysAt1970 += 1;
|
||||
}
|
||||
// N2K sysTime is double in n2klib
|
||||
double sysTime = (sensors.rtcTime.tm_hour * 3600) + (sensors.rtcTime.tm_min * 60) + sensors.rtcTime.tm_sec;
|
||||
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);
|
||||
// }
|
||||
}
|
||||
} else if (sensors.rtcValid) {
|
||||
// use internal rtc feature
|
||||
sensors.rtcTime = rtc.getTimeStruct();
|
||||
}
|
||||
}
|
||||
|
||||
// Send 1Wire data for all temperature sensors to N2K all 2s
|
||||
if(millis() > starttime13 + 2000 && String(oneWireOn) == "DS18B20" && oneWire_ready == true){
|
||||
starttime13 = millis();
|
||||
float tempC;
|
||||
ds18b20.requestTemperatures(); // Collect all temperature values (max.8)
|
||||
for(int i=0;i<numberOfDevices; i++){
|
||||
// Send only one 1Wire data per loop step (time reduction)
|
||||
if(i == loopCounter % numberOfDevices){
|
||||
if(ds18b20.getAddress(tempDeviceAddress, i)){
|
||||
// Read temperature value in Celsius
|
||||
tempC = ds18b20.getTempC(tempDeviceAddress);
|
||||
}
|
||||
// Send to NMEA200 bus for each sensor with instance number
|
||||
if(!isnan(tempC)){
|
||||
sensors.onewireTemp[i] = tempC; // Save values in SensorData
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"DS18B20-%1d Temp: %.1f",i,tempC);
|
||||
SetN2kPGN130316(N2kMsg, 0, i, N2kts_OutsideTemperature, CToKelvin(tempC), N2kDoubleNA);
|
||||
api->sendN2kMessage(N2kMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
loopCounter++;
|
||||
}
|
||||
|
||||
// Send supply voltage value to N2K all 1s
|
||||
// Send supply voltage value all 1s
|
||||
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
|
||||
starttime5 = millis();
|
||||
float rawVoltage = 0; // Default value
|
||||
#ifdef BOARD_OBP40S3
|
||||
#ifdef BOARD_OBP40S3
|
||||
sensors.batteryVoltage = 0; // If no sensor then zero voltage
|
||||
#endif
|
||||
#if defined(BOARD_OBP40S3) && defined(VOLTAGE_SENSOR)
|
||||
#endif
|
||||
#if defined(BOARD_OBP40S3) && defined(VOLTAGE_SENSOR)
|
||||
rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||
sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration
|
||||
#endif
|
||||
#ifdef BOARD_OBP60S3
|
||||
#endif
|
||||
#ifdef BOARD_OBP60S3
|
||||
rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||
sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration
|
||||
#endif
|
||||
#endif
|
||||
// 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
|
||||
#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
|
||||
@@ -638,19 +556,24 @@ void sensorTask(void *param){
|
||||
SetN2kDCBatStatus(N2kMsg, 10, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 0);
|
||||
api->sendN2kMessage(N2kMsg);
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP60S3
|
||||
#endif
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Send to NMEA200 bus
|
||||
if(!isnan(sensors.batteryVoltage)){
|
||||
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 1);
|
||||
api->sendN2kMessage(N2kMsg);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Send data from environment sensor to N2K all 2s
|
||||
// Send data from environment sensor all 2s
|
||||
if(millis() > starttime6 + 2000){
|
||||
starttime6 = millis();
|
||||
|
||||
// DEBUG
|
||||
UBaseType_t stackfree = uxTaskGetStackHighWaterMark(NULL);
|
||||
api->getLogger()->logDebug(GwLog::LOG, "obpSensortask Stack=%d", stackfree);
|
||||
|
||||
unsigned char TempSource = 2; // Inside temperature
|
||||
unsigned char PressureSource = 0; // Atmospheric pressure
|
||||
unsigned char HumiditySource = 0; // Inside humidity
|
||||
@@ -713,7 +636,7 @@ void sensorTask(void *param){
|
||||
}
|
||||
}
|
||||
|
||||
// Send rotation angle to N2K all 500ms
|
||||
// Send rotation angle all 500ms
|
||||
if(millis() > starttime7 + 500){
|
||||
starttime7 = millis();
|
||||
double rotationAngle=0;
|
||||
@@ -761,7 +684,7 @@ void sensorTask(void *param){
|
||||
}
|
||||
}
|
||||
|
||||
// Send battery power value to N2K all 1s
|
||||
// Send battery power value all 1s
|
||||
if(millis() > starttime8 + 1000 && (String(powsensor1) == "INA219" || String(powsensor1) == "INA226")){
|
||||
starttime8 = millis();
|
||||
if(String(powsensor1) == "INA226" && INA226_1_ready == true){
|
||||
@@ -803,7 +726,7 @@ void sensorTask(void *param){
|
||||
}
|
||||
}
|
||||
|
||||
// Send solar power value to N2K all 1s
|
||||
// Send solar power value all 1s
|
||||
if(millis() > starttime9 + 1000 && (String(powsensor2) == "INA219" || String(powsensor2) == "INA226")){
|
||||
starttime9 = millis();
|
||||
if(String(powsensor2) == "INA226" && INA226_2_ready == true){
|
||||
@@ -833,7 +756,7 @@ void sensorTask(void *param){
|
||||
}
|
||||
}
|
||||
|
||||
// Send generator power value to N2K all 1s
|
||||
// Send generator power value all 1s
|
||||
if(millis() > starttime10 + 1000 && (String(powsensor3) == "INA219" || String(powsensor3) == "INA226")){
|
||||
starttime10 = millis();
|
||||
if(String(powsensor3) == "INA226" && INA226_3_ready == true){
|
||||
@@ -868,8 +791,12 @@ void sensorTask(void *param){
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
||||
void createSensorTask(SharedData *shared){
|
||||
xTaskCreate(sensorTask,"readSensors",10000,shared,3,NULL);
|
||||
void createSensorTask(SharedData *shared) {
|
||||
TaskHandle_t xHandle = NULL;
|
||||
GwLog *logger = shared->api->getLogger();
|
||||
esp_err_t err = xTaskCreate(sensorTask, "readSensors", configMINIMAL_STACK_SIZE + 8192, shared, 3, &xHandle);
|
||||
if ( err != pdPASS) {
|
||||
logger->logDebug(GwLog::ERROR, "Failed to create sensor task! (err=%d)", err);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
#include "GwSynchronized.h"
|
||||
#include "GwApi.h"
|
||||
|
||||
@@ -1,805 +0,0 @@
|
||||
// Function lib for display of boat data in various chart formats
|
||||
#include "OBPcharts.h"
|
||||
#include "OBPDataOperations.h"
|
||||
#include "OBPRingBuffer.h"
|
||||
|
||||
std::map<String, ChartProps> Chart::dfltChrtDta = {
|
||||
{ "formatWind", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
|
||||
{ "formatCourse", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
|
||||
{ "formatKnots", { 7.71, 2.56 } }, // default speed range in m/s
|
||||
{ "formatDepth", { 15.0, 5.0 } }, // default depth range in m
|
||||
{ "kelvinToC", { 30.0, 5.0 } } // default temp range in °C/K
|
||||
};
|
||||
|
||||
// --- Class Chart ---------------
|
||||
|
||||
// Chart - object holding the actual chart, incl. data buffer and format definition
|
||||
// Parameters: <dataBuf> the history data buffer for the chart
|
||||
// <dfltRng> default range of chart, e.g. 30 = [0..30]
|
||||
// <common> common program data; required for logger and color data
|
||||
// <useSimuData> flag to indicate if simulation data is active
|
||||
Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData)
|
||||
: dataBuf(dataBuf)
|
||||
, dfltRng(dfltRng)
|
||||
, commonData(&common)
|
||||
, useSimuData(useSimuData)
|
||||
{
|
||||
logger = commonData->logger;
|
||||
fgColor = commonData->fgcolor;
|
||||
bgColor = commonData->bgcolor;
|
||||
|
||||
dWidth = getdisplay().width();
|
||||
dHeight = getdisplay().height();
|
||||
|
||||
dataBuf.getMetaData(dbName, dbFormat);
|
||||
dbMIN_VAL = dataBuf.getMinVal();
|
||||
dbMAX_VAL = dataBuf.getMaxVal();
|
||||
bufSize = dataBuf.getCapacity();
|
||||
|
||||
// Initialize chart data format; shorter version of standard format indicator
|
||||
if (dbFormat == "formatCourse" || dbFormat == "formatWind" || dbFormat == "formatRot") {
|
||||
chrtDataFmt = WIND; // Chart is showing data of course / wind <degree> format
|
||||
} else if (dbFormat == "formatRot") {
|
||||
chrtDataFmt = ROTATION; // Chart is showing data of rotational <degree> format
|
||||
} else if (dbFormat == "formatKnots") {
|
||||
chrtDataFmt = SPEED; // Chart is showing data of speed or windspeed format
|
||||
} else if (dbFormat == "formatDepth") {
|
||||
chrtDataFmt = DEPTH; // Chart ist showing data of <depth> format
|
||||
} else if (dbFormat == "kelvinToC") {
|
||||
chrtDataFmt = TEMPERATURE; // Chart ist showing data of <temp> format
|
||||
} else {
|
||||
chrtDataFmt = OTHER; // Chart is showing any other data format
|
||||
}
|
||||
|
||||
// "0" value is the same for any data format but for user defined temperature format
|
||||
zeroValue = 0.0;
|
||||
if (chrtDataFmt == TEMPERATURE) {
|
||||
tempFormat = commonData->config->getString(commonData->config->tempFormat); // [K|°C|°F]
|
||||
if (tempFormat == "K") {
|
||||
zeroValue = 0.0;
|
||||
} else if (tempFormat == "C") {
|
||||
zeroValue = 273.15;
|
||||
} else if (tempFormat == "F") {
|
||||
zeroValue = 255.37;
|
||||
}
|
||||
}
|
||||
|
||||
// Read default range and range step for this chart type
|
||||
if (dfltChrtDta.count(dbFormat)) {
|
||||
dfltRng = dfltChrtDta[dbFormat].range;
|
||||
rngStep = dfltChrtDta[dbFormat].step;
|
||||
} else {
|
||||
dfltRng = 15.0;
|
||||
rngStep = 5.0;
|
||||
}
|
||||
|
||||
// Initialize chart range values
|
||||
chrtMin = zeroValue;
|
||||
chrtMax = chrtMin + dfltRng;
|
||||
chrtMid = (chrtMin + chrtMax) / 2;
|
||||
chrtRng = dfltRng;
|
||||
recalcRngMid = true; // initialize <chrtMid> and chart borders on first screen call
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "Chart Init: dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot {x,y}: %d, %d, dbname: %s, rngStep: %.4f, chrtDataFmt: %d",
|
||||
dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, dbName, rngStep, chrtDataFmt);
|
||||
};
|
||||
|
||||
Chart::~Chart()
|
||||
{
|
||||
}
|
||||
|
||||
// Perform all actions to draw chart
|
||||
// Parameters: <chrtDir>: chart timeline direction: 'H' = horizontal, 'V' = vertical
|
||||
// <chrtSz>: chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom
|
||||
// <chrtIntv>: chart timeline interval
|
||||
// <prntName>; print data name on horizontal half chart [true|false]
|
||||
// <showCurrValue>: print current boat data value [true|false]
|
||||
// <currValue>: current boat data value; used only for test on valid data
|
||||
void Chart::showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue)
|
||||
{
|
||||
if (!setChartDimensions(chrtDir, chrtSz)) {
|
||||
return; // wrong chart dimension parameters
|
||||
}
|
||||
|
||||
drawChrt(chrtDir, chrtIntv, currValue);
|
||||
drawChrtTimeAxis(chrtDir, chrtSz, chrtIntv);
|
||||
drawChrtValAxis(chrtDir, chrtSz, prntName);
|
||||
|
||||
if (!bufDataValid) { // No valid data available
|
||||
prntNoValidData(chrtDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (showCurrValue) { // show latest value from history buffer; this should be the most current one
|
||||
currValue.value = dataBuf.getLast();
|
||||
currValue.valid = currValue.value != dbMAX_VAL;
|
||||
prntCurrValue(chrtDir, currValue);
|
||||
}
|
||||
}
|
||||
|
||||
// define dimensions and start points for chart
|
||||
bool Chart::setChartDimensions(const char direction, const int8_t size)
|
||||
{
|
||||
if ((direction != HORIZONTAL && direction != VERTICAL) || (size < 0 || size > 2)) {
|
||||
LOG_DEBUG(GwLog::ERROR, "obp60:setChartDimensions %s: wrong parameters", dataBuf.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
// horizontal chart timeline direction
|
||||
timAxis = dWidth - 1;
|
||||
switch (size) {
|
||||
case 0:
|
||||
valAxis = dHeight - top - bottom;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 1:
|
||||
valAxis = (dHeight - top - bottom) / 2 - hGap;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 2:
|
||||
valAxis = (dHeight - top - bottom) / 2 - hGap;
|
||||
cRoot = { 0, top + (valAxis + hGap) + hGap - 1 };
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (direction == VERTICAL) {
|
||||
// vertical chart timeline direction
|
||||
timAxis = dHeight - top - bottom;
|
||||
switch (size) {
|
||||
case 0:
|
||||
valAxis = dWidth - 1;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 1:
|
||||
valAxis = dWidth / 2 - vGap;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 2:
|
||||
valAxis = dWidth / 2 - vGap;
|
||||
cRoot = { dWidth / 2 + vGap - 1, top - 1 };
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(GwLog::ERROR, "obp60:setChartDimensions %s: direction: %c, size: %d, dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot{%d, %d}, top: %d, bottom: %d, hGap: %d, vGap: %d",
|
||||
dataBuf.getName(), direction, size, dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, top, bottom, hGap, vGap);
|
||||
return true;
|
||||
}
|
||||
|
||||
// draw chart
|
||||
void Chart::drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue& currValue)
|
||||
{
|
||||
double chrtScale; // Scale for data values in pixels per value
|
||||
|
||||
getBufferStartNSize(chrtIntv);
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "Chart:drawChart: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng);
|
||||
calcChrtBorders(chrtMin, chrtMid, chrtMax, chrtRng);
|
||||
chrtScale = double(valAxis) / chrtRng; // Chart scale: pixels per value step
|
||||
LOG_DEBUG(GwLog::DEBUG, "Chart:drawChart: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng);
|
||||
|
||||
// Do we have valid buffer data?
|
||||
if (dataBuf.getMax() == dbMAX_VAL) { // only <MAX_VAL> values in buffer -> no valid wind data available
|
||||
bufDataValid = false;
|
||||
return;
|
||||
|
||||
} else if (currValue.valid || useSimuData) { // latest boat data valid or simulation mode
|
||||
numNoData = 0; // reset data error counter
|
||||
bufDataValid = true;
|
||||
|
||||
} else { // currently no valid data
|
||||
numNoData++;
|
||||
bufDataValid = true;
|
||||
|
||||
if (numNoData > THRESHOLD_NO_DATA) { // If more than 4 invalid values in a row, flag for invalid data
|
||||
bufDataValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
drawChartLines(chrtDir, chrtIntv, chrtScale);
|
||||
}
|
||||
|
||||
// Identify buffer size and buffer start position for chart
|
||||
void Chart::getBufferStartNSize(const int8_t chrtIntv)
|
||||
{
|
||||
count = dataBuf.getCurrentSize();
|
||||
currIdx = dataBuf.getLastIdx();
|
||||
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
|
||||
|
||||
if (chrtIntv != oldChrtIntv || count == 1) {
|
||||
// new data interval selected by user; this is only x * 230 values instead of 240 seconds (4 minutes) per interval step
|
||||
numBufVals = min(count, (timAxis - MIN_FREE_VALUES) * chrtIntv); // keep free or release MIN_FREE_VALUES on chart for plotting of new values
|
||||
bufStart = max(0, count - numBufVals);
|
||||
lastAddedIdx = currIdx;
|
||||
oldChrtIntv = chrtIntv;
|
||||
|
||||
} else {
|
||||
numBufVals = numBufVals + numAddedBufVals;
|
||||
lastAddedIdx = currIdx;
|
||||
if (count == bufSize) {
|
||||
bufStart = max(0, bufStart - numAddedBufVals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check and adjust chart range and set range borders and range middle
|
||||
void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, double& rng)
|
||||
{
|
||||
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) {
|
||||
|
||||
if (chrtDataFmt == ROTATION) {
|
||||
// if chart data is of type 'rotation', we want to have <rndMid> always to be '0'
|
||||
rngMid = 0;
|
||||
|
||||
} else { // WIND: Chart data is of type 'course' or 'wind'
|
||||
|
||||
// initialize <rngMid> if data buffer has just been started filling
|
||||
if ((count == 1 && rngMid == 0) || rngMid == dbMAX_VAL) {
|
||||
recalcRngMid = true;
|
||||
}
|
||||
|
||||
if (recalcRngMid) {
|
||||
// Set rngMid
|
||||
|
||||
rngMid = dataBuf.getMid(numBufVals);
|
||||
|
||||
if (rngMid == dbMAX_VAL) {
|
||||
rngMid = 0;
|
||||
} else {
|
||||
rngMid = std::round(rngMid / rngStep) * rngStep; // Set new center value; round to next <rngStep> value
|
||||
|
||||
// Check if range between 'min' and 'max' is > 180° or crosses '0'
|
||||
rngMin = dataBuf.getMin(numBufVals);
|
||||
rngMax = dataBuf.getMax(numBufVals);
|
||||
rng = (rngMax >= rngMin ? rngMax - rngMin : M_TWOPI - rngMin + rngMax);
|
||||
rng = std::max(rng, dfltRng); // keep at least default chart range
|
||||
|
||||
if (rng > M_PI) { // If wind range > 180°, adjust wndCenter to smaller wind range end
|
||||
rngMid = WindUtils::to2PI(rngMid + M_PI);
|
||||
}
|
||||
}
|
||||
recalcRngMid = false; // Reset flag for <rngMid> determination
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "calcChrtRange: rngMin: %.1f°, rngMid: %.1f°, rngMax: %.1f°, rng: %.1f°, rngStep: %.1f°", rngMin * RAD_TO_DEG, rngMid * RAD_TO_DEG, rngMax * RAD_TO_DEG,
|
||||
rng * RAD_TO_DEG, rngStep * RAD_TO_DEG);
|
||||
}
|
||||
}
|
||||
|
||||
// check and adjust range between left, mid, and right chart limit
|
||||
double halfRng = rng / 2.0; // we calculate with range between <rngMid> and edges
|
||||
double tmpRng = getAngleRng(rngMid, numBufVals);
|
||||
tmpRng = (tmpRng == dbMAX_VAL ? 0 : std::ceil(tmpRng / rngStep) * rngStep);
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "calcChrtBorders: tmpRng: %.1f°, halfRng: %.1f°", tmpRng * RAD_TO_DEG, halfRng * RAD_TO_DEG);
|
||||
|
||||
if (tmpRng > halfRng) { // expand chart range to new value
|
||||
halfRng = tmpRng;
|
||||
}
|
||||
|
||||
else if (tmpRng + rngStep < halfRng) { // Contract chart range for higher resolution if possible
|
||||
halfRng = std::max(dfltRng / 2.0, tmpRng);
|
||||
}
|
||||
|
||||
rngMin = WindUtils::to2PI(rngMid - halfRng);
|
||||
rngMax = (halfRng < M_PI ? rngMid + halfRng : rngMid + halfRng - (M_TWOPI / 360)); // if chart range is 360°, then make <rngMax> 1° smaller than <rngMin>
|
||||
rngMax = WindUtils::to2PI(rngMax);
|
||||
|
||||
rng = halfRng * 2.0;
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "calcChrtBorders: rngMin: %.1f°, rngMid: %.1f°, rngMax: %.1f°, tmpRng: %.1f°, rng: %.1f°, rngStep: %.1f°", rngMin * RAD_TO_DEG, rngMid * RAD_TO_DEG, rngMax * RAD_TO_DEG,
|
||||
tmpRng * RAD_TO_DEG, rng * RAD_TO_DEG, rngStep * RAD_TO_DEG);
|
||||
|
||||
} else { // chart data is of any other type
|
||||
|
||||
double currMinVal = dataBuf.getMin(numBufVals);
|
||||
double currMaxVal = dataBuf.getMax(numBufVals);
|
||||
|
||||
if (currMinVal == dbMAX_VAL || currMaxVal == dbMAX_VAL) {
|
||||
return; // no valid data
|
||||
}
|
||||
|
||||
// check if current chart border have to be adjusted
|
||||
if (currMinVal < rngMin || (currMinVal > (rngMin + rngStep))) { // decrease rngMin if required or increase if lowest value is higher than old rngMin
|
||||
rngMin = std::floor(currMinVal / rngStep) * rngStep; // align low range to lowest buffer value and nearest range interval
|
||||
}
|
||||
if ((currMaxVal > rngMax) || (currMaxVal < (rngMax - rngStep))) { // increase rngMax if required or decrease if lowest value is lower than old rngMax
|
||||
rngMax = std::ceil(currMaxVal / rngStep) * rngStep;
|
||||
}
|
||||
|
||||
// Chart range starts at least at '0' if minimum data value allows it
|
||||
if (rngMin > zeroValue && dbMIN_VAL <= zeroValue) {
|
||||
rngMin = zeroValue;
|
||||
}
|
||||
|
||||
// ensure minimum chart range in user format
|
||||
if ((rngMax - rngMin) < dfltRng) {
|
||||
rngMax = rngMin + dfltRng;
|
||||
}
|
||||
|
||||
rngMid = (rngMin + rngMax) / 2.0;
|
||||
rng = rngMax - rngMin;
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "calcChrtRange-end: currMinVal: %.1f, currMaxVal: %.1f, rngMin: %.1f, rngMid: %.1f, rngMax: %.1f, rng: %.1f, rngStep: %.1f, zeroValue: %.1f, dbMIN_VAL: %.1f",
|
||||
currMinVal, currMaxVal, rngMin, rngMid, rngMax, rng, rngStep, zeroValue, dbMIN_VAL);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw chart graph
|
||||
void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const double chrtScale)
|
||||
{
|
||||
double chrtVal; // Current data value
|
||||
Pos point, prevPoint; // current and previous chart point
|
||||
|
||||
for (int i = 0; i < (numBufVals / chrtIntv); i++) {
|
||||
|
||||
chrtVal = dataBuf.get(bufStart + (i * chrtIntv)); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer
|
||||
|
||||
if (chrtVal == dbMAX_VAL) {
|
||||
chrtPrevVal = dbMAX_VAL;
|
||||
} else {
|
||||
|
||||
point = setCurrentChartPoint(i, direction, chrtVal, chrtScale);
|
||||
|
||||
// if (i >= (numBufVals / chrtIntv) - 5) // log chart data of 1 line (adjust for test purposes)
|
||||
// LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %.2f, chrtMin: %.2f, {x,y} {%d,%d}", i, chrtVal, chrtMin, x, y);
|
||||
|
||||
if ((i == 0) || (chrtPrevVal == dbMAX_VAL)) {
|
||||
// just a dot for 1st chart point or after some invalid values
|
||||
prevPoint = point;
|
||||
|
||||
} else if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) {
|
||||
// cross borders check for degree values; shift values to [-PI..0..PI]; when crossing borders, range is 2x PI degrees
|
||||
|
||||
double normCurrVal = WindUtils::to2PI(chrtVal - chrtMin);
|
||||
double normPrevVal = WindUtils::to2PI(chrtPrevVal - chrtMin);
|
||||
// Check if pixel positions are far apart (crossing chart boundary); happens when one value is near chrtMax and the other near chrtMin
|
||||
bool crossedBorders = std::abs(normCurrVal - normPrevVal) > (chrtRng / 2.0);
|
||||
|
||||
if (crossedBorders) { // If current value crosses chart borders compared to previous value, split line
|
||||
// LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: crossedBorders: %d, chrtVal: %.2f, chrtPrevVal: %.2f", crossedBorders, chrtVal, chrtPrevVal);
|
||||
bool wrappingFromHighToLow = normCurrVal < normPrevVal; // Determine which edge we're crossing
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
int ySplit = wrappingFromHighToLow ? (cRoot.y + valAxis) : cRoot.y;
|
||||
drawBoldLine(prevPoint.x, prevPoint.y, point.x, ySplit);
|
||||
prevPoint.y = wrappingFromHighToLow ? cRoot.y : (cRoot.y + valAxis);
|
||||
|
||||
} else { // vertical chart
|
||||
int xSplit = wrappingFromHighToLow ? (cRoot.x + valAxis) : cRoot.x;
|
||||
drawBoldLine(prevPoint.x, prevPoint.y, xSplit, point.y);
|
||||
prevPoint.x = wrappingFromHighToLow ? cRoot.x : (cRoot.x + valAxis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chrtDataFmt == DEPTH) {
|
||||
if (direction == HORIZONTAL) { // horizontal chart
|
||||
drawBoldLine(point.x, point.y, point.x, cRoot.y + valAxis);
|
||||
} else { // vertical chart
|
||||
drawBoldLine(point.x, point.y, cRoot.x + valAxis, point.y);
|
||||
}
|
||||
} else {
|
||||
drawBoldLine(prevPoint.x, prevPoint.y, point.x, point.y);
|
||||
}
|
||||
|
||||
chrtPrevVal = chrtVal;
|
||||
prevPoint = point;
|
||||
}
|
||||
|
||||
// Reaching chart area top end
|
||||
if (i >= timAxis - 1) {
|
||||
oldChrtIntv = 0; // force reset of buffer start and number of values to show in next display loop
|
||||
|
||||
if (chrtDataFmt == WIND) { // degree of course or wind
|
||||
recalcRngMid = true;
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: chart end: timAxis: %d, i: %d, bufStart: %d, numBufVals: %d, recalcRngCntr: %d", timAxis, i, bufStart, numBufVals, recalcRngMid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set current chart point to draw
|
||||
Pos Chart::setCurrentChartPoint(const int i, const char direction, const double chrtVal, const double chrtScale)
|
||||
{
|
||||
Pos currentPoint;
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
currentPoint.x = cRoot.x + i; // Position in chart area
|
||||
|
||||
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) { // degree type value
|
||||
currentPoint.y = cRoot.y + static_cast<int>((WindUtils::to2PI(chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
} else if (chrtDataFmt == SPEED or chrtDataFmt == TEMPERATURE) { // speed or temperature data format -> print low values at bottom
|
||||
currentPoint.y = cRoot.y + valAxis - static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
} else { // any other data format
|
||||
currentPoint.y = cRoot.y + static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
}
|
||||
|
||||
} else { // vertical chart
|
||||
currentPoint.y = cRoot.y + timAxis - i; // Position in chart area
|
||||
|
||||
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) { // degree type value
|
||||
currentPoint.x = cRoot.x + static_cast<int>((WindUtils::to2PI(chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
} else {
|
||||
currentPoint.x = cRoot.x + static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
}
|
||||
}
|
||||
|
||||
return currentPoint;
|
||||
}
|
||||
|
||||
// chart time axis label + lines
|
||||
void Chart::drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, const int8_t chrtIntv)
|
||||
{
|
||||
float axSlots, intv, i;
|
||||
char sTime[6];
|
||||
int timeRng = chrtIntv * 4; // chart time interval: [1] 4 min., [2] 8 min., [3] 12 min., [4] 16 min., [8] 32 min.
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setTextColor(fgColor);
|
||||
|
||||
axSlots = 5; // number of axis labels
|
||||
intv = timAxis / (axSlots - 1); // minutes per chart axis interval (interval is 1 less than axSlots)
|
||||
i = timeRng; // Chart axis label start at -32, -16, -12, ... minutes
|
||||
|
||||
if (chrtDir == HORIZONTAL) {
|
||||
getdisplay().fillRect(0, cRoot.y, dWidth, 2, fgColor);
|
||||
|
||||
for (float j = 0; j < timAxis - 1; j += intv) { // fill time axis with values but keep area free on right hand side for value label
|
||||
|
||||
// draw text with appropriate offset
|
||||
int tOffset = j == 0 ? 13 : -4;
|
||||
snprintf(sTime, sizeof(sTime), "-%.0f", i);
|
||||
drawTextCenter(cRoot.x + j + tOffset, cRoot.y - 8, sTime);
|
||||
getdisplay().drawLine(cRoot.x + j, cRoot.y, cRoot.x + j, cRoot.y + 5, fgColor); // draw short vertical time mark
|
||||
|
||||
i -= chrtIntv;
|
||||
}
|
||||
|
||||
} else { // vertical chart
|
||||
|
||||
for (float j = intv; j < timAxis - 1; j += intv) { // don't print time label at upper and lower end of time axis
|
||||
|
||||
i -= chrtIntv; // we start not at top chart position
|
||||
snprintf(sTime, sizeof(sTime), "-%.0f", i);
|
||||
getdisplay().drawLine(cRoot.x, cRoot.y + j, cRoot.x + valAxis, cRoot.y + j, fgColor); // Grid line
|
||||
|
||||
if (chrtSz == FULL_SIZE) { // full size chart
|
||||
getdisplay().fillRect(0, cRoot.y + j - 9, 32, 15, bgColor); // clear small area to remove potential chart lines
|
||||
getdisplay().setCursor((4 - strlen(sTime)) * 7, cRoot.y + j + 3); // time value; print left screen; value right-formated
|
||||
getdisplay().printf("%s", sTime); // Range value
|
||||
} else if (chrtSz == HALF_SIZE_RIGHT) { // half size chart; right side
|
||||
drawTextCenter(dWidth / 2, cRoot.y + j, sTime); // time value; print mid screen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// chart value axis labels + lines
|
||||
void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntName)
|
||||
{
|
||||
const GFXfont* font;
|
||||
constexpr bool NO_LABEL = false;
|
||||
constexpr bool LABEL = true;
|
||||
|
||||
getdisplay().setTextColor(fgColor);
|
||||
|
||||
if (chrtDir == HORIZONTAL) {
|
||||
|
||||
if (chrtSz == FULL_SIZE) {
|
||||
|
||||
font = &Ubuntu_Bold12pt8b;
|
||||
|
||||
// print buffer data name on right hand side of time axis (max. size 5 characters)
|
||||
getdisplay().setFont(font);
|
||||
drawTextRalign(cRoot.x + timAxis, cRoot.y - 3, dbName.substring(0, 5));
|
||||
|
||||
if (chrtDataFmt == WIND) {
|
||||
prntHorizChartThreeValueAxisLabel(font);
|
||||
return;
|
||||
}
|
||||
|
||||
// for any other data formats print multiple axis value lines on full charts
|
||||
prntHorizChartMultiValueAxisLabel(font);
|
||||
return;
|
||||
|
||||
} else { // half size chart -> just print edge values + middle chart line
|
||||
|
||||
font = &Ubuntu_Bold10pt8b;
|
||||
|
||||
if (prntName) {
|
||||
// print buffer data name on right hand side of time axis (max. size 5 characters)
|
||||
getdisplay().setFont(font);
|
||||
drawTextRalign(cRoot.x + timAxis, cRoot.y - 3, dbName.substring(0, 5));
|
||||
}
|
||||
|
||||
prntHorizChartThreeValueAxisLabel(font);
|
||||
return;
|
||||
}
|
||||
|
||||
} else { // vertical chart
|
||||
|
||||
if (chrtSz == FULL_SIZE) {
|
||||
font = &Ubuntu_Bold12pt8b;
|
||||
getdisplay().setFont(font); // use larger font
|
||||
drawTextRalign(cRoot.x + (valAxis * 0.42), cRoot.y - 2, dbName.substring(0, 6)); // print buffer data name (max. size 5 characters)
|
||||
|
||||
} else {
|
||||
|
||||
font = &Ubuntu_Bold10pt8b;
|
||||
}
|
||||
|
||||
prntVerticChartThreeValueAxisLabel(font);
|
||||
}
|
||||
}
|
||||
|
||||
// Print current data value
|
||||
void Chart::prntCurrValue(const char direction, GwApi::BoatValue& currValue)
|
||||
{
|
||||
const int xPosVal = (direction == HORIZONTAL) ? cRoot.x + (timAxis / 2) - 56 : cRoot.x + 32;
|
||||
const int yPosVal = (direction == HORIZONTAL) ? cRoot.y + valAxis - 7 : cRoot.y + timAxis - 7;
|
||||
|
||||
FormattedData frmtDbData = formatValue(&currValue, *commonData, NO_SIMUDATA);
|
||||
String sdbValue = frmtDbData.svalue; // value as formatted string
|
||||
String dbUnit = frmtDbData.unit; // Unit of value; limit length to 3 characters
|
||||
|
||||
getdisplay().fillRect(xPosVal - 1, yPosVal - 35, 128, 41, bgColor); // Clear area for TWS value
|
||||
getdisplay().drawRect(xPosVal, yPosVal - 34, 126, 40, fgColor); // Draw box for TWS value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
getdisplay().setCursor(xPosVal + 1, yPosVal);
|
||||
getdisplay().print(sdbValue); // value
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||
getdisplay().setCursor(xPosVal + 76, yPosVal - 17);
|
||||
getdisplay().print(dbName.substring(0, 3)); // Name, limited to 3 characters
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(xPosVal + 76, yPosVal + 0);
|
||||
getdisplay().print(dbUnit); // Unit
|
||||
}
|
||||
|
||||
// print message for no valid data availabletemplate <typename T>
|
||||
void Chart::prntNoValidData(const char direction)
|
||||
{
|
||||
Pos p;
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
p.x = cRoot.x + (timAxis / 2);
|
||||
p.y = cRoot.y + (valAxis / 2) - 10;
|
||||
} else {
|
||||
p.x = cRoot.x + (valAxis / 2);
|
||||
p.y = cRoot.y + (timAxis / 2) - 10;
|
||||
}
|
||||
|
||||
getdisplay().fillRect(p.x - 37, p.y - 10, 78, 24, bgColor); // Clear area for message
|
||||
drawTextCenter(p.x, p.y, "No data");
|
||||
|
||||
LOG_DEBUG(GwLog::LOG, "Page chart <%s>: No valid data available", dbName);
|
||||
}
|
||||
|
||||
// Get maximum difference of last <amount> of dataBuf ringbuffer values to center chart; for angle data only
|
||||
double Chart::getAngleRng(const double center, size_t amount)
|
||||
{
|
||||
size_t count = dataBuf.getCurrentSize();
|
||||
|
||||
if (dataBuf.isEmpty() || amount <= 0) {
|
||||
return dbMAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
double value = 0;
|
||||
double range = 0;
|
||||
double maxRng = dbMIN_VAL;
|
||||
|
||||
// Start from the newest value (last) and go backwards x times
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
value = dataBuf.get(count - 1 - i);
|
||||
|
||||
if (value == dbMAX_VAL) {
|
||||
continue; // ignore invalid values
|
||||
}
|
||||
|
||||
range = abs(fmod((value - center + (M_TWOPI + M_PI)), M_TWOPI) - M_PI);
|
||||
if (range > maxRng)
|
||||
maxRng = range;
|
||||
}
|
||||
|
||||
if (maxRng > M_PI) {
|
||||
maxRng = M_PI;
|
||||
}
|
||||
|
||||
return (maxRng != dbMIN_VAL ? maxRng : dbMAX_VAL); // Return range from <mid> to <max>
|
||||
}
|
||||
|
||||
// print value axis label with only three values: top, mid, and bottom for vertical chart
|
||||
void Chart::prntVerticChartThreeValueAxisLabel(const GFXfont* font)
|
||||
{
|
||||
double cVal;
|
||||
char sVal[7];
|
||||
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y, valAxis, 2, fgColor); // top chart line
|
||||
getdisplay().setFont(font);
|
||||
|
||||
cVal = chrtMin;
|
||||
cVal = convertValue(cVal, dbName, dbFormat, *commonData); // value (converted)
|
||||
snprintf(sVal, sizeof(sVal), "%.0f", round(cVal));
|
||||
getdisplay().setCursor(cRoot.x, cRoot.y - 2);
|
||||
getdisplay().printf("%s", sVal); // Range low end
|
||||
|
||||
cVal = chrtMid;
|
||||
cVal = convertValue(cVal, dbName, dbFormat, *commonData); // value (converted)
|
||||
snprintf(sVal, sizeof(sVal), "%.0f", round(cVal));
|
||||
drawTextCenter(cRoot.x + (valAxis / 2), cRoot.y - 9, sVal); // Range mid end
|
||||
|
||||
cVal = chrtMax;
|
||||
cVal = convertValue(cVal, dbName, dbFormat, *commonData); // value (converted)
|
||||
snprintf(sVal, sizeof(sVal), "%.0f", round(cVal));
|
||||
drawTextRalign(cRoot.x + valAxis - 2, cRoot.y - 2, sVal); // Range high end
|
||||
|
||||
// draw vertical grid lines for each axis label
|
||||
for (int j = 0; j <= valAxis; j += (valAxis / 2)) {
|
||||
getdisplay().drawLine(cRoot.x + j, cRoot.y, cRoot.x + j, cRoot.y + timAxis, fgColor);
|
||||
}
|
||||
}
|
||||
|
||||
// print value axis label with only three values: top, mid, and bottom for horizontal chart
|
||||
void Chart::prntHorizChartThreeValueAxisLabel(const GFXfont* font)
|
||||
{
|
||||
double axLabel;
|
||||
double chrtMin, chrtMid, chrtMax;
|
||||
int xOffset, yOffset; // offset for text position of x axis label for different font sizes
|
||||
String sVal;
|
||||
|
||||
if (font == &Ubuntu_Bold10pt8b) {
|
||||
xOffset = 39;
|
||||
yOffset = 15;
|
||||
} else if (font == &Ubuntu_Bold12pt8b) {
|
||||
xOffset = 51;
|
||||
yOffset = 18;
|
||||
}
|
||||
getdisplay().setFont(font);
|
||||
|
||||
// convert & round chart bottom+top label to next range step
|
||||
chrtMin = convertValue(this->chrtMin, dbName, dbFormat, *commonData);
|
||||
chrtMid = convertValue(this->chrtMid, dbName, dbFormat, *commonData);
|
||||
chrtMax = convertValue(this->chrtMax, dbName, dbFormat, *commonData);
|
||||
chrtMin = std::round(chrtMin * 100.0) / 100.0;
|
||||
chrtMid = std::round(chrtMid * 100.0) / 100.0;
|
||||
chrtMax = std::round(chrtMax * 100.0) / 100.0;
|
||||
|
||||
// print top axis label
|
||||
axLabel = (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE) ? chrtMax : chrtMin;
|
||||
sVal = formatLabel(axLabel);
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + 2, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + yOffset, sVal); // range value
|
||||
|
||||
// print mid axis label
|
||||
axLabel = chrtMid;
|
||||
sVal = formatLabel(axLabel);
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 3, 16, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + (valAxis / 2) + 6, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor);
|
||||
|
||||
// print bottom axis label
|
||||
axLabel = (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE) ? chrtMin : chrtMax;
|
||||
sVal = formatLabel(axLabel);
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + valAxis - 14, xOffset + 3, 15, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + valAxis, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + valAxis, cRoot.x + timAxis, cRoot.y + valAxis, fgColor);
|
||||
}
|
||||
|
||||
// print value axis label with multiple axis lines for horizontal chart
|
||||
void Chart::prntHorizChartMultiValueAxisLabel(const GFXfont* font)
|
||||
{
|
||||
double chrtMin, chrtMax, chrtRng;
|
||||
double axSlots, axIntv, axLabel;
|
||||
int xOffset; // offset for text position of x axis label for different font sizes
|
||||
String sVal;
|
||||
|
||||
if (font == &Ubuntu_Bold10pt8b) {
|
||||
xOffset = 38;
|
||||
} else if (font == &Ubuntu_Bold12pt8b) {
|
||||
xOffset = 50;
|
||||
}
|
||||
getdisplay().setFont(font);
|
||||
|
||||
chrtMin = convertValue(this->chrtMin, dbName, dbFormat, *commonData);
|
||||
// chrtMin = std::floor(chrtMin / rngStep) * rngStep;
|
||||
chrtMin = std::round(chrtMin * 100.0) / 100.0;
|
||||
chrtMax = convertValue(this->chrtMax, dbName, dbFormat, *commonData);
|
||||
// chrtMax = std::ceil(chrtMax / rngStep) * rngStep;
|
||||
chrtMax = std::round(chrtMax * 100.0) / 100.0;
|
||||
chrtRng = std::round((chrtMax - chrtMin) * 100) / 100;
|
||||
|
||||
axSlots = valAxis / static_cast<double>(VALAXIS_STEP); // number of axis labels (and we want to have a double calculation, no integer)
|
||||
axIntv = chrtRng / axSlots;
|
||||
axLabel = chrtMin + axIntv;
|
||||
LOG_DEBUG(GwLog::DEBUG, "Chart::printHorizMultiValueAxisLabel: chrtRng: %.2f, th-chrtRng: %.2f, axSlots: %.2f, axIntv: %.2f, axLabel: %.2f, chrtMin: %.2f, chrtMid: %.2f, chrtMax: %.2f", chrtRng, this->chrtRng, axSlots, axIntv, axLabel, this->chrtMin, chrtMid, chrtMax);
|
||||
|
||||
int loopStrt, loopEnd, loopStp;
|
||||
if (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE || chrtDataFmt == OTHER) {
|
||||
// High value at top
|
||||
loopStrt = valAxis - VALAXIS_STEP;
|
||||
loopEnd = VALAXIS_STEP / 2;
|
||||
loopStp = VALAXIS_STEP * -1;
|
||||
} else {
|
||||
// Low value at top
|
||||
loopStrt = VALAXIS_STEP;
|
||||
loopEnd = valAxis - (VALAXIS_STEP / 2);
|
||||
loopStp = VALAXIS_STEP;
|
||||
}
|
||||
|
||||
for (int j = loopStrt; (loopStp > 0) ? (j < loopEnd) : (j > loopEnd); j += loopStp) {
|
||||
sVal = formatLabel(axLabel);
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + j - 11, xOffset + 3, 21, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + j + 7, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + j, cRoot.x + timAxis, cRoot.y + j, fgColor);
|
||||
|
||||
axLabel += axIntv;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw chart line with thickness of 2px
|
||||
void Chart::drawBoldLine(const int16_t x1, const int16_t y1, const int16_t x2, const int16_t y2)
|
||||
{
|
||||
int16_t dx = std::abs(x2 - x1);
|
||||
int16_t dy = std::abs(y2 - y1);
|
||||
|
||||
getdisplay().drawLine(x1, y1, x2, y2, fgColor);
|
||||
|
||||
if (dx >= dy) { // line has horizontal tendency
|
||||
getdisplay().drawLine(x1, y1 - 1, x2, y2 - 1, fgColor);
|
||||
} else { // line has vertical tendency
|
||||
getdisplay().drawLine(x1 - 1, y1, x2 - 1, y2, fgColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert and format current axis label to user defined format; helper function for easier handling of OBP60Formatter
|
||||
String Chart::convNformatLabel(const double& label)
|
||||
{
|
||||
GwApi::BoatValue tmpBVal(dbName); // temporary boat value for string formatter
|
||||
String sVal;
|
||||
|
||||
tmpBVal.setFormat(dbFormat);
|
||||
tmpBVal.valid = true;
|
||||
tmpBVal.value = label;
|
||||
sVal = formatValue(&tmpBVal, *commonData, NO_SIMUDATA).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
if (sVal.length() > 0 && sVal[0] == '!') {
|
||||
sVal = sVal.substring(1); // cut leading "!" created at OBPFormatter; doesn't work for other fonts than 7SEG
|
||||
}
|
||||
|
||||
return sVal;
|
||||
}
|
||||
|
||||
// Format current axis label for printing w/o data format conversion (has been done earlier)
|
||||
String Chart::formatLabel(const double& label)
|
||||
{
|
||||
char sVal[11];
|
||||
|
||||
if (dbFormat == "formatCourse" || dbFormat == "formatWind") {
|
||||
// Format 3 numbers with prefix zero
|
||||
snprintf(sVal, sizeof(sVal), "%03.0f", label);
|
||||
|
||||
} else if (dbFormat == "formatRot") {
|
||||
if (label > -10 && label < 10) {
|
||||
snprintf(sVal, sizeof(sVal), "%3.2f", label);
|
||||
} else {
|
||||
snprintf(sVal, sizeof(sVal), "%3.0f", label);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (label < 10) {
|
||||
snprintf(sVal, sizeof(sVal), "%3.1f", label);
|
||||
} else {
|
||||
snprintf(sVal, sizeof(sVal), "%3.0f", label);
|
||||
}
|
||||
}
|
||||
|
||||
return String(sVal);
|
||||
}
|
||||
// --- Class Chart ---------------
|
||||
@@ -1,116 +0,0 @@
|
||||
// Function lib for display of boat data in various graphical chart formats
|
||||
#pragma once
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
struct Pos {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct ChartProps {
|
||||
double range;
|
||||
double step;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RingBuffer;
|
||||
class GwLog;
|
||||
|
||||
class Chart {
|
||||
protected:
|
||||
CommonData* commonData;
|
||||
GwLog* logger;
|
||||
|
||||
enum ChrtDataFormat {
|
||||
WIND,
|
||||
ROTATION,
|
||||
SPEED,
|
||||
DEPTH,
|
||||
TEMPERATURE,
|
||||
OTHER
|
||||
};
|
||||
|
||||
static constexpr char HORIZONTAL = 'H';
|
||||
static constexpr char VERTICAL = 'V';
|
||||
static constexpr int8_t FULL_SIZE = 0;
|
||||
static constexpr int8_t HALF_SIZE_LEFT = 1;
|
||||
static constexpr int8_t HALF_SIZE_RIGHT = 2;
|
||||
|
||||
static constexpr int8_t MIN_FREE_VALUES = 60; // free 60 values when chart line reaches chart end
|
||||
static constexpr int8_t THRESHOLD_NO_DATA = 3; // max. seconds of invalid values in a row
|
||||
static constexpr int8_t VALAXIS_STEP = 60; // pixels between two chart value axis labels
|
||||
|
||||
static constexpr bool NO_SIMUDATA = true; // switch off simulation feature of <formatValue> function
|
||||
|
||||
RingBuffer<uint16_t>& dataBuf; // Buffer to display
|
||||
//char chrtDir; // Chart timeline direction: 'H' = horizontal, 'V' = vertical
|
||||
//int8_t chrtSz; // Chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom
|
||||
double dfltRng; // Default range of chart, e.g. 30 = [0..30]
|
||||
uint16_t fgColor; // color code for any screen writing
|
||||
uint16_t bgColor; // color code for screen background
|
||||
bool useSimuData; // flag to indicate if simulation data is active
|
||||
String tempFormat; // user defined format for temperature
|
||||
double zeroValue; // "0" SI value for temperature
|
||||
|
||||
int dWidth; // Display width
|
||||
int dHeight; // Display height
|
||||
int top = 44; // chart gap at top of display (25 lines for standard gap + 19 lines for axis labels)
|
||||
int bottom = 25; // chart gap at bottom of display to keep space for status line
|
||||
int hGap = 11; // gap between 2 horizontal charts; actual gap is 2x <gap>
|
||||
int vGap = 17; // gap between 2 vertical charts; actual gap is 2x <gap>
|
||||
int timAxis, valAxis; // size of time and value chart axis
|
||||
Pos cRoot; // start point of chart area
|
||||
double chrtRng; // Range of buffer values from min to max value
|
||||
double chrtMin; // Range low end value
|
||||
double chrtMax; // Range high end value
|
||||
double chrtMid; // Range mid value
|
||||
double rngStep; // Defines the step of adjustment (e.g. 10 m/s) for value axis range
|
||||
bool recalcRngMid = false; // Flag for re-calculation of mid value of chart for wind data types
|
||||
|
||||
String dbName, dbFormat; // Name and format of data buffer
|
||||
ChrtDataFormat chrtDataFmt; // Data format of chart boat data type
|
||||
double dbMIN_VAL; // Lowest possible value of buffer of type <T>
|
||||
double dbMAX_VAL; // Highest possible value of buffer of type <T>; indicates invalid value in buffer
|
||||
size_t bufSize; // History buffer size: 1.920 values for 32 min. history chart
|
||||
int count; // current size of buffer
|
||||
int numBufVals; // number of wind values available for current interval selection
|
||||
int bufStart; // 1st data value in buffer to show
|
||||
int numAddedBufVals; // Number of values added to buffer since last display
|
||||
size_t currIdx; // Current index in TWD history buffer
|
||||
size_t lastIdx; // Last index of TWD history buffer
|
||||
size_t lastAddedIdx = 0; // Last index of TWD history buffer when new data was added
|
||||
int numNoData; // Counter for multiple invalid data values in a row
|
||||
bool bufDataValid = false; // Flag to indicate if buffer data is valid
|
||||
int oldChrtIntv = 0; // remember recent user selection of data interval
|
||||
|
||||
double chrtPrevVal; // Last data value in chart area
|
||||
int x, y; // x and y coordinates for drawing
|
||||
int prevX, prevY; // Last x and y coordinates for drawing
|
||||
|
||||
bool setChartDimensions(const char direction, const int8_t size); //define dimensions and start points for chart
|
||||
void drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue& currValue); // Draw chart line
|
||||
void getBufferStartNSize(const int8_t chrtIntv); // Identify buffer size and buffer start position for chart
|
||||
void calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, double& rng); // Calculate chart points for value axis and return range between <min> and <max>
|
||||
void drawChartLines(const char direction, const int8_t chrtIntv, const double chrtScale); // Draw chart graph
|
||||
Pos setCurrentChartPoint(const int i, const char direction, const double chrtVal, const double chrtScale); // Set current chart point to draw
|
||||
void drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, const int8_t chrtIntv); // Draw time axis of chart, value and lines
|
||||
void drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntLabel); // Draw value axis of chart, value and lines
|
||||
void prntCurrValue(const char chrtDir, GwApi::BoatValue& currValue); // Add current boat data value to chart
|
||||
void prntNoValidData(const char chrtDir); // print message for no valid data available
|
||||
double getAngleRng(const double center, size_t amount); // Calculate range between chart center and edges
|
||||
void prntVerticChartThreeValueAxisLabel(const GFXfont* font); // print value axis label with only three values: top, mid, and bottom for vertical chart
|
||||
void prntHorizChartThreeValueAxisLabel(const GFXfont* font); // print value axis label with only three values: top, mid, and bottom for horizontal chart
|
||||
void prntHorizChartMultiValueAxisLabel(const GFXfont* font); // print value axis label with multiple axis lines for horizontal chart
|
||||
void drawBoldLine(const int16_t x1, const int16_t y1, const int16_t x2, const int16_t y2); // Draw chart line with thickness of 2px
|
||||
String convNformatLabel(const double& label); // Convert and format current axis label to user defined format; helper function for easier handling of OBP60Formatter
|
||||
String formatLabel(const double& label); // Format current axis label for printing w/o data format conversion (has been done earlier)
|
||||
|
||||
public:
|
||||
// Define default chart range and range step for each boat data type
|
||||
static std::map<String, ChartProps> dfltChrtDta;
|
||||
|
||||
Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData); // Chart object of data chart
|
||||
~Chart();
|
||||
void showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue); // Perform all actions to draw chart
|
||||
};
|
||||
178
lib/obp60task/PageAIS.cpp
Normal file
178
lib/obp60task/PageAIS.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
/*
|
||||
AIS Overview
|
||||
- circle with certain range, e.g. 5nm
|
||||
- AIS-Targets in range with speed and heading
|
||||
- perhaps collision alarm
|
||||
Data: LAT LON SOG HDT
|
||||
|
||||
Feature possibilities
|
||||
- switch between North up / Heading up
|
||||
- filter
|
||||
- zoom
|
||||
- special vessel symbols
|
||||
|
||||
*/
|
||||
|
||||
class PageAIS : public Page
|
||||
{
|
||||
private:
|
||||
|
||||
int scale = 5; // Radius of display circle in nautical miles
|
||||
|
||||
bool alarm = false;
|
||||
bool alarm_enabled = false;
|
||||
int alarm_range = 3;
|
||||
|
||||
char mode = 'N'; // (N)ormal, (C)onfig
|
||||
|
||||
void displayModeNormal(PageData &pageData) {
|
||||
|
||||
// TBD Boatvalues: ...
|
||||
|
||||
logger->logDebug(GwLog::DEBUG,"Drawing at PageAIS");
|
||||
|
||||
Point c = {200, 150}; // center = current boat position
|
||||
uint16_t r = 125;
|
||||
|
||||
const std::vector<Point> pts_boat = { // polygon lines
|
||||
{c.x - 5, c.y},
|
||||
{c.x - 5, c.y - 10},
|
||||
{c.x, c.y - 16},
|
||||
{c.x + 5, c.y - 10},
|
||||
{c.x + 5, c.y}
|
||||
};
|
||||
drawPoly(pts_boat, commonData->fgcolor);
|
||||
|
||||
// Title and corner value headings
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("AIS");
|
||||
|
||||
// zoom scale
|
||||
epd->drawLine(c.x + 10, c.y, c.x + r - 4, c.y, commonData->fgcolor);
|
||||
// arrow left
|
||||
epd->drawLine(c.x + 10, c.y, c.x + 16, c.y - 4, commonData->fgcolor);
|
||||
epd->drawLine(c.x + 10, c.y, c.x + 16, c.y + 4, commonData->fgcolor);
|
||||
// arrow right
|
||||
epd->drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y - 4, commonData->fgcolor);
|
||||
epd->drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y + 4, commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
drawTextCenter(c.x + r / 2, c.y + 8, String(scale) + "nm");
|
||||
|
||||
}
|
||||
|
||||
void displayModeConfig() {
|
||||
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("AIS configuration");
|
||||
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
// TODO menu
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
PageAIS(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageAIS");
|
||||
alarm_range = 3;
|
||||
}
|
||||
|
||||
void setupKeys(){
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "MODE";
|
||||
commonData->keydata[1].label = "ALARM";
|
||||
}
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
int handleKey(int key){
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
} else {
|
||||
mode = 'N';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
int handleKey(int key) {
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
} else {
|
||||
mode = 'N';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
|
||||
// Logging boat values
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageAIS; Mode=%c", mode);
|
||||
|
||||
// Set display in partial refresh mode
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height());
|
||||
|
||||
if (mode == 'N') {
|
||||
displayModeNormal(pageData);
|
||||
} else if (mode == 'C') {
|
||||
displayModeConfig();
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageAIS(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 registerPageAIS(
|
||||
"AIS", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"LAT", "LON", "SOG", "HDT"}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
432
lib/obp60task/PageAnchor.cpp
Normal file
432
lib/obp60task/PageAnchor.cpp
Normal file
@@ -0,0 +1,432 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "ConfigMenu.h"
|
||||
|
||||
/*
|
||||
Anchor overview with additional associated data
|
||||
This page is in experimental stage so be warned!
|
||||
North is up.
|
||||
|
||||
Boatdata used
|
||||
DBS - Water depth
|
||||
HDT - Boat heading
|
||||
AWS - Wind strength; Boat not moving so we assume AWS=TWS and AWD=TWD
|
||||
AWD - Wind direction
|
||||
LAT/LON - Boat position, current
|
||||
HDOP - Position error
|
||||
|
||||
This is the fist page to contain a configuration page with
|
||||
data entry option.
|
||||
Also it will make use of the new alarm function.
|
||||
|
||||
Data
|
||||
Anchor position lat/lon
|
||||
Depth at anchor position
|
||||
Chain length used
|
||||
Boat position current
|
||||
Depth at boat position
|
||||
Boat heading
|
||||
Wind direction
|
||||
Wind strength
|
||||
Alarm j/n
|
||||
Alarm radius
|
||||
GPS position error
|
||||
Timestamp while dropping anchor
|
||||
|
||||
Drop / raise function in device OBP40 has to be done inside
|
||||
config mode because of limited number of buttons.
|
||||
|
||||
Save position in FRAM
|
||||
Alarm: gps fix lost
|
||||
switch unit feet/meter
|
||||
|
||||
*/
|
||||
|
||||
#define anchor_width 16
|
||||
#define anchor_height 16
|
||||
static unsigned char anchor_bits[] = {
|
||||
0x80, 0x01, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xf0, 0x0f, 0x80, 0x01,
|
||||
0x80, 0x01, 0x88, 0x11, 0x8c, 0x31, 0x8e, 0x71, 0x84, 0x21, 0x86, 0x61,
|
||||
0x86, 0x61, 0xfc, 0x3f, 0xf8, 0x1f, 0x80, 0x01 };
|
||||
|
||||
class PageAnchor : public Page
|
||||
{
|
||||
private:
|
||||
String lengthformat;
|
||||
|
||||
int scale = 50; // Radius of display circle in meter
|
||||
|
||||
bool alarm = false;
|
||||
bool alarm_enabled = false;
|
||||
uint8_t alarm_range;
|
||||
|
||||
uint8_t chain_length;
|
||||
uint8_t chain;
|
||||
|
||||
bool anchor_set = false;
|
||||
double anchor_lat;
|
||||
double anchor_lon;
|
||||
double anchor_depth;
|
||||
int anchor_ts; // time stamp anchor dropped
|
||||
|
||||
char mode = 'N'; // (N)ormal, (C)onfig
|
||||
int8_t editmode = -1; // marker for menu/edit/set function
|
||||
|
||||
ConfigMenu *menu;
|
||||
|
||||
void displayModeNormal(PageData &pageData) {
|
||||
|
||||
// Boatvalues: DBS, HDT, AWS, AWD, LAT, LON, HDOP
|
||||
GwApi::BoatValue *bv_dbs = pageData.values[0]; // DBS
|
||||
String sval_dbs = commonData->fmt->formatValue(bv_dbs, *commonData).svalue;
|
||||
String sunit_dbs = commonData->fmt->formatValue(bv_dbs, *commonData).unit;
|
||||
GwApi::BoatValue *bv_hdt = pageData.values[1]; // HDT
|
||||
String sval_hdt = commonData->fmt->formatValue(bv_hdt, *commonData).svalue;
|
||||
GwApi::BoatValue *bv_aws = pageData.values[2]; // AWS
|
||||
String sval_aws = commonData->fmt->formatValue(bv_aws, *commonData).svalue;
|
||||
String sunit_aws = commonData->fmt->formatValue(bv_aws, *commonData).unit;
|
||||
GwApi::BoatValue *bv_awd = pageData.values[3]; // AWD
|
||||
String sval_awd = commonData->fmt->formatValue(bv_awd, *commonData).svalue;
|
||||
GwApi::BoatValue *bv_lat = pageData.values[4]; // LAT
|
||||
String sval_lat = commonData->fmt->formatValue(bv_lat, *commonData).svalue;
|
||||
GwApi::BoatValue *bv_lon = pageData.values[5]; // LON
|
||||
String sval_lon = commonData->fmt->formatValue(bv_lon, *commonData).svalue;
|
||||
GwApi::BoatValue *bv_hdop = pageData.values[6]; // HDOP
|
||||
String sval_hdop = commonData->fmt->formatValue(bv_hdop, *commonData).svalue;
|
||||
String sunit_hdop = commonData->fmt->formatValue(bv_hdop, *commonData).unit;
|
||||
|
||||
logger->logDebug(GwLog::DEBUG, "Drawing at PageAnchor; DBS=%f, HDT=%f, AWS=%f", bv_dbs->value, bv_hdt->value, bv_aws->value);
|
||||
|
||||
Point c = {200, 150}; // center = anchor position
|
||||
uint16_t r = 125;
|
||||
|
||||
Point b = {200, 180}; // boat position while dropping anchor
|
||||
|
||||
const std::vector<Point> pts_boat = { // polygon lines
|
||||
{b.x - 5, b.y},
|
||||
{b.x - 5, b.y - 10},
|
||||
{b.x, b.y - 16},
|
||||
{b.x + 5, b.y - 10},
|
||||
{b.x + 5, b.y}
|
||||
};
|
||||
//rotatePoints und dann Linien zeichnen
|
||||
// TODO rotate boat according to current heading
|
||||
//drawPoly(rotatePoints(c, pts, RadToDeg(value2)), commonData->fgcolor);
|
||||
drawPoly(pts_boat, commonData->fgcolor);
|
||||
|
||||
// Draw wind arrow
|
||||
const std::vector<Point> pts_wind = {
|
||||
{c.x, c.y - r + 25},
|
||||
{c.x - 12, c.y - r - 4},
|
||||
{c.x, c.y - r + 6},
|
||||
{c.x + 12, c.y - r - 4}
|
||||
};
|
||||
if (bv_awd->valid) {
|
||||
fillPoly4(rotatePoints(c, pts_wind, bv_awd->value), commonData->fgcolor);
|
||||
}
|
||||
|
||||
// Title and corner value headings
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("Anchor");
|
||||
|
||||
epd->setFont(&Ubuntu_Bold10pt8b);
|
||||
epd->setCursor(8, 200);
|
||||
epd->print("Depth");
|
||||
drawTextRalign(392, 38, "Chain");
|
||||
drawTextRalign(392, 200, "Wind");
|
||||
|
||||
// Units
|
||||
epd->setCursor(8, 272);
|
||||
epd->print(sunit_dbs);
|
||||
drawTextRalign(392, 272, sunit_aws);
|
||||
drawTextRalign(392, 100, lengthformat); // chain unit not implemented
|
||||
|
||||
// Corner values
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(8, 70);
|
||||
epd->print("Alarm: ");
|
||||
epd->print(alarm_enabled ? "On" : "Off");
|
||||
|
||||
epd->setCursor(8, 90);
|
||||
epd->print("HDOP");
|
||||
epd->setCursor(8, 106);
|
||||
if (bv_hdop->valid) {
|
||||
epd->print(round(bv_hdop->value), 0);
|
||||
epd->print(sunit_hdop);
|
||||
} else {
|
||||
epd->print("n/a");
|
||||
}
|
||||
|
||||
// Values
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
// Current chain used
|
||||
epd->setCursor(328, 85);
|
||||
epd->print("27");
|
||||
|
||||
// Depth
|
||||
epd->setCursor(8, 250);
|
||||
epd->print(sval_dbs);
|
||||
// Wind
|
||||
epd->setCursor(328, 250);
|
||||
epd->print(sval_aws);
|
||||
|
||||
epd->drawCircle(c.x, c.y, r, commonData->fgcolor);
|
||||
epd->drawCircle(c.x, c.y, r + 1, commonData->fgcolor);
|
||||
|
||||
// zoom scale
|
||||
epd->drawLine(c.x + 10, c.y, c.x + r - 4, c.y, commonData->fgcolor);
|
||||
// arrow left
|
||||
epd->drawLine(c.x + 10, c.y, c.x + 16, c.y - 4, commonData->fgcolor);
|
||||
epd->drawLine(c.x + 10, c.y, c.x + 16, c.y + 4, commonData->fgcolor);
|
||||
// arrow right
|
||||
epd->drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y - 4, commonData->fgcolor);
|
||||
epd->drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y + 4, commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
drawTextCenter(c.x + r / 2, c.y + 8, String(scale) + "m");
|
||||
|
||||
// alarm range circle
|
||||
if (alarm_enabled) {
|
||||
// alarm range in meter has to be smaller than the scale in meter
|
||||
// r and r_range are pixel values
|
||||
uint16_t r_range = int(alarm_range * r / scale);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageAnchor; Alarm range = %d", r_range);
|
||||
epd->drawCircle(c.x, c.y, r_range, commonData->fgcolor);
|
||||
}
|
||||
|
||||
// draw anchor symbol (as bitmap)
|
||||
epd->drawXBitmap(c.x - anchor_width / 2, c.y - anchor_height / 2,
|
||||
anchor_bits, anchor_width, anchor_height, commonData->fgcolor);
|
||||
|
||||
}
|
||||
|
||||
void displayModeConfig() {
|
||||
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("Anchor configuration");
|
||||
|
||||
// TODO
|
||||
// show lat/lon for anchor pos
|
||||
// show lat/lon for boat pos
|
||||
// show distance anchor <-> boat
|
||||
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
for (int i = 0 ; i < menu->getItemCount(); i++) {
|
||||
ConfigMenuItem *itm = menu->getItemByIndex(i);
|
||||
if (!itm) {
|
||||
logger->logDebug(GwLog::ERROR, "Menu item not found: %d", i);
|
||||
} else {
|
||||
Rect r = menu->getItemRect(i);
|
||||
bool inverted = (i == menu->getActiveIndex());
|
||||
drawTextBoxed(r, itm->getLabel(), commonData->fgcolor, commonData->bgcolor, inverted, false);
|
||||
if (inverted and editmode > 0) {
|
||||
// triangle as edit marker
|
||||
epd->fillTriangle(r.x + r.w + 20, r.y, r.x + r.w + 30, r.y + r.h / 2, r.x + r.w + 20, r.y + r.h, commonData->fgcolor);
|
||||
}
|
||||
epd->setCursor(r.x + r.w + 40, r.y + r.h - 4);
|
||||
if (itm->getType() == "int") {
|
||||
epd->print(itm->getValue());
|
||||
epd->print(itm->getUnit());
|
||||
} else {
|
||||
epd->print(itm->getValue() == 0 ? "No" : "Yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
PageAnchor(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageAnchor");
|
||||
|
||||
// preload configuration data
|
||||
lengthformat = config->getString(config->lengthFormat);
|
||||
chain_length = config->getInt(config->chainLength);
|
||||
|
||||
chain = 0;
|
||||
anchor_set = false;
|
||||
alarm_range = 30;
|
||||
|
||||
// Initialize config menu
|
||||
menu = new ConfigMenu("Options", 40, 80);
|
||||
menu->setItemDimension(150, 20);
|
||||
|
||||
ConfigMenuItem *newitem;
|
||||
newitem = menu->addItem("chain", "Chain out", "int", 0, "m");
|
||||
if (! newitem) {
|
||||
// Demo: in case of failure exit here, should never be happen
|
||||
logger->logDebug(GwLog::ERROR, "Menu item creation failed");
|
||||
return;
|
||||
}
|
||||
newitem->setRange(0, 200, {1, 5, 10});
|
||||
newitem = menu->addItem("chainmax", "Chain max", "int", chain_length, "m");
|
||||
newitem->setRange(0, 200, {1, 5, 10});
|
||||
newitem = menu->addItem("zoom", "Zoom", "int", 50, "m");
|
||||
newitem->setRange(0, 200, {1, });
|
||||
newitem = menu->addItem("range", "Alarm range", "int", 40, "m");
|
||||
newitem->setRange(0, 200, {1, 5, 10});
|
||||
newitem = menu->addItem("alat", "Adjust anchor lat.", "int", 0, "m");
|
||||
newitem->setRange(0, 200, {1, 5, 10});
|
||||
newitem = menu->addItem("alon", "Adjust anchor lon.", "int", 0, "m");
|
||||
newitem->setRange(0, 200, {1, 5, 10});
|
||||
#ifdef BOARD_OBP40S3
|
||||
// Intodruced here because of missing keys for OBP40
|
||||
newitem = menu->addItem("anchor", "Anchor down", "bool", 0, "");
|
||||
#endif
|
||||
menu->setItemActive("zoom");
|
||||
}
|
||||
|
||||
void setupKeys(){
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "MODE";
|
||||
commonData->keydata[1].label = "ALARM";
|
||||
}
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
int handleKey(int key){
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
} else {
|
||||
mode = 'N';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (mode == 'N') {
|
||||
if (key == 2) { // Toggle alarm
|
||||
alarm_enabled = !alarm_enabled;
|
||||
return 0;
|
||||
}
|
||||
} else { // Config mode
|
||||
if (key == 3) {
|
||||
// menu down
|
||||
menu->goNext();
|
||||
return 0;
|
||||
}
|
||||
if (key == 4) {
|
||||
// menu up
|
||||
menu->goPrev();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
int handleKey(int key){
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
commonData->keydata[1].label = "EDIT";
|
||||
} else {
|
||||
mode = 'N';
|
||||
commonData->keydata[1].label = "ALARM";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (mode == 'N') {
|
||||
if (key == 2) { // Toggle alarm
|
||||
alarm_enabled = !alarm_enabled;
|
||||
return 0;
|
||||
}
|
||||
} else { // Config mode
|
||||
// TODO different code for OBP40 / OBP60
|
||||
if (key == 9) {
|
||||
// menu down
|
||||
if (editmode > 0) {
|
||||
// decrease item value
|
||||
menu->getActiveItem()->decValue();
|
||||
} else {
|
||||
menu->goNext();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 10) {
|
||||
// menu up or value up
|
||||
if (editmode > 0) {
|
||||
// increase item value
|
||||
menu->getActiveItem()->incValue();
|
||||
} else {
|
||||
menu->goPrev();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 2) {
|
||||
// enter / leave edit mode for current menu item
|
||||
if (editmode > 0) {
|
||||
commonData->keydata[1].label = "EDIT";
|
||||
editmode = 0;
|
||||
} else {
|
||||
commonData->keydata[1].label = "SET";
|
||||
editmode = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
|
||||
void displayNew(PageData &pageData){
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
|
||||
// Logging boat values
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageAnchor; Mode=%c", mode);
|
||||
|
||||
// Set display in partial refresh mode
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
if (mode == 'N') {
|
||||
displayModeNormal(pageData);
|
||||
} else if (mode == 'C') {
|
||||
displayModeConfig();
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageAnchor(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 registerPageAnchor(
|
||||
"Anchor", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"DBS", "HDT", "AWS", "AWD", "LAT", "LON", "HDOP"}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -1,251 +1,126 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
// These constants have to match the declaration below in :
|
||||
// PageDescription registerPageAutopilot(
|
||||
// {"HDM","HDT", "COG", "STW", "SOG", "DBT","XTE", "DTW", "BTW"}, // Bus values we need in the page
|
||||
const int HowManyValues = 9;
|
||||
/*
|
||||
Autopilot
|
||||
|
||||
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 ShowDBT = 5;
|
||||
const int ShowXTE = 6;
|
||||
const int ShowDTW = 7;
|
||||
const int ShowBTW = 8;
|
||||
|
||||
const int Compass_X0 = 200; // X center point of compass band
|
||||
const int Compass_Y0 = 220; // Y 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 PageAutopilot : public Page
|
||||
{
|
||||
int WhichDataCompass = ShowHDM; // Start value
|
||||
int WhichDataDisplay = ShowHDM; // Start value
|
||||
private:
|
||||
char mode = 'N'; // (N)ormal, (C)onfig
|
||||
|
||||
void displayModeNormal(PageData &pageData) {
|
||||
|
||||
// TBD Boatvalues: ...
|
||||
|
||||
logger->logDebug(GwLog::DEBUG, "Drawing at PageAutopilot");
|
||||
|
||||
// Title and corner value headings
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("Autopilot");
|
||||
|
||||
public:
|
||||
PageAutopilot(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageAutopilot");
|
||||
}
|
||||
|
||||
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 > ShowDBT)
|
||||
WhichDataDisplay = ShowHDM;
|
||||
}
|
||||
void displayModeConfig() {
|
||||
|
||||
if(key == 11){
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("Autopilot configuration");
|
||||
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
// TODO menu
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
PageAutopilot(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageAutopilot");
|
||||
}
|
||||
|
||||
void setupKeys() {
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "MODE";
|
||||
}
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
int handleKey(int key) {
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
} else {
|
||||
mode = 'N';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
int handleKey(int key){
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
commonData->keydata[1].label = "EDIT";
|
||||
} else {
|
||||
mode = 'N';
|
||||
commonData->keydata[1].label = "ALARM";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
|
||||
void displayNew(PageData &pageData){
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int 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];
|
||||
FormattedData 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 PageAutopilot: %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 PAGE_OK; // WTF why this statement?
|
||||
|
||||
//***********************************************************
|
||||
// Logging boat values
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageAutopilot; Mode=%c", mode);
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height());
|
||||
|
||||
// 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;
|
||||
if (mode == 'N') {
|
||||
displayModeNormal(pageData);
|
||||
} else if (mode == 'C') {
|
||||
displayModeConfig();
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageAutopilot(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
|
||||
@@ -256,8 +131,8 @@ PageDescription registerPageAutopilot(
|
||||
"Autopilot", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"HDM","HDT", "COG", "STW", "SOG", "DBT","XTE", "DTW", "BTW"}, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
|
||||
false // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -5,13 +6,21 @@
|
||||
|
||||
class PageBME280 : public Page
|
||||
{
|
||||
public:
|
||||
PageBME280(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageBME280");
|
||||
private:
|
||||
String tempformat;
|
||||
String useenvsensor;
|
||||
|
||||
public:
|
||||
PageBME280(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageBME280");
|
||||
|
||||
// Get config data
|
||||
tempformat = config->getString(config->tempFormat);
|
||||
useenvsensor = config->getString(config->useEnvSensor);
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key){
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -21,8 +30,6 @@ class PageBME280 : public Page
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
double value1 = 0;
|
||||
double value2 = 0;
|
||||
@@ -30,13 +37,6 @@ class PageBME280 : public Page
|
||||
String svalue1 = "";
|
||||
String svalue2 = "";
|
||||
String svalue3 = "";
|
||||
|
||||
// Get config data
|
||||
String tempformat = config->getString(config->tempFormat);
|
||||
bool simulation = config->getBool(config->useSimuData);
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String useenvsensor = config->getString(config->useEnvSensor);
|
||||
|
||||
// Get sensor values #1
|
||||
String name1 = "Temp"; // Value name
|
||||
@@ -99,82 +99,82 @@ class PageBME280 : public Page
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageBME280, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageBME280, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// ############### Value 1 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 55);
|
||||
getdisplay().print(name1); // Page name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 55);
|
||||
epd->print(name1); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 90);
|
||||
getdisplay().print(unit1); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 90);
|
||||
epd->print(unit1); // Unit
|
||||
|
||||
// Switch font if format for any values
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 90);
|
||||
|
||||
// Show bus data
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
epd->print(svalue1); // Real value as formated string
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 2 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 145);
|
||||
getdisplay().print(name2); // Page name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 145);
|
||||
epd->print(name2); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 180);
|
||||
getdisplay().print(unit2); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 180);
|
||||
epd->print(unit2); // Unit
|
||||
|
||||
// Switch font if format for any values
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 180);
|
||||
|
||||
// Show bus data
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
epd->print(svalue2); // Real value as formated string
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 3 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 235);
|
||||
getdisplay().print(name3); // Page name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 235);
|
||||
epd->print(name3); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 270);
|
||||
getdisplay().print(unit3); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 270);
|
||||
epd->print(unit3); // Unit
|
||||
|
||||
// Switch font if format for any values
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(140, 270);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(140, 270);
|
||||
|
||||
// Show bus data
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
epd->print(svalue3); // Real value as formated string
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
238
lib/obp60task/PageBarograph.cpp
Normal file
238
lib/obp60task/PageBarograph.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
/*
|
||||
* Barograph WIP
|
||||
* - Zoom feature
|
||||
* - Saves data in FRAM if available
|
||||
*/
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
class PageBarograph : public Page
|
||||
{
|
||||
private:
|
||||
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): Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageBarograph");
|
||||
|
||||
// Get config data
|
||||
useenvsensor = 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
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
// Logging boat values
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageBarograph");
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
// Frames
|
||||
epd->fillRect(0, 75, 400, 2, commonData->fgcolor); // fillRect: x, y, w, h
|
||||
epd->fillRect(130, 20, 2, 55, commonData->fgcolor);
|
||||
epd->fillRect(270, 20, 2, 55, commonData->fgcolor);
|
||||
epd->fillRect(325, 20, 2, 55, commonData->fgcolor);
|
||||
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
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
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
drawTextCenter(200, 40, String(commonData->data.airPressure / 100, 1));
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
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;
|
||||
|
||||
// epd->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);
|
||||
epd->drawLine(x0 - i * xstep, y0, x0 - i * xstep, y0 - h, commonData->fgcolor);
|
||||
drawTextCenter(x0 - i * xstep, y0 - 10, label);
|
||||
}
|
||||
|
||||
// y-axis
|
||||
epd->drawLine(x0 + 5, y0, x0 + 5, y0 - h, commonData->fgcolor); // drawLine: x1, y1, x2, y2
|
||||
epd->drawLine(x0 - w, y0, x0 - w, y0 - h, commonData->fgcolor);
|
||||
epd->drawLine(x0 - w - 5, y0, x0 - w - 5, y0 - h, commonData->fgcolor);
|
||||
epd->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
|
||||
epd->setCursor(x0 + 10, y + 5);
|
||||
epd->print(String(ys));
|
||||
epd->drawLine(x0 + 5, y, x0 - w - 5, y, commonData->fgcolor);
|
||||
} else {
|
||||
// small step, only short lines left and right
|
||||
epd->drawLine(x0 + 5, y, x0, y, commonData->fgcolor);
|
||||
epd->drawLine(x0 - w - 5, y, x0 - w, y, commonData->fgcolor);
|
||||
}
|
||||
y -= dy;
|
||||
ys += 1;
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -5,20 +6,25 @@
|
||||
|
||||
class PageBattery : public Page
|
||||
{
|
||||
private:
|
||||
String powsensor1;
|
||||
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");
|
||||
public:
|
||||
PageBattery(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageBattery");
|
||||
|
||||
// Get config data
|
||||
String powsensor1 = config->getString(config->usePowSensor1);
|
||||
}
|
||||
|
||||
virtual void setupKeys(){
|
||||
void setupKeys(){
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "AVG";
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key){
|
||||
// Change average
|
||||
if(key == 1){
|
||||
average ++;
|
||||
@@ -34,10 +40,18 @@ class PageBattery : public Page
|
||||
return key;
|
||||
}
|
||||
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
|
||||
// Old values for hold function
|
||||
double value1 = 0;
|
||||
static String svalue1old = "";
|
||||
@@ -48,15 +62,7 @@ class PageBattery : public Page
|
||||
double value3 = 0;
|
||||
static String svalue3old = "";
|
||||
static String unit3old = "";
|
||||
|
||||
// Get config data
|
||||
String lengthformat = config->getString(config->lengthFormat);
|
||||
// bool simulation = config->getBool(config->useSimuData);
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String powsensor1 = config->getString(config->usePowSensor1);
|
||||
bool simulation = config->getBool(config->useSimuData);
|
||||
|
||||
|
||||
// Get voltage value
|
||||
String name1 = "VBat"; // Value name
|
||||
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
|
||||
@@ -145,147 +151,141 @@ class PageBattery : public Page
|
||||
String svalue3 = String(value3); // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit3 = "W"; // Unit of value
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery, %s: %f, %s: %f, %s: %f, Avg: %d", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, average);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageBattery, %s: %f, %s: %f, %s: %f, Avg: %d", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, average);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
// Show average settings
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
switch (average) {
|
||||
case 0:
|
||||
getdisplay().setCursor(60, 90);
|
||||
getdisplay().print("Avg: 1s");
|
||||
getdisplay().setCursor(60, 180);
|
||||
getdisplay().print("Avg: 1s");
|
||||
getdisplay().setCursor(60, 270);
|
||||
getdisplay().print("Avg: 1s");
|
||||
epd->setCursor(60, 90);
|
||||
epd->print("Avg: 1s");
|
||||
epd->setCursor(60, 180);
|
||||
epd->print("Avg: 1s");
|
||||
epd->setCursor(60, 270);
|
||||
epd->print("Avg: 1s");
|
||||
break;
|
||||
case 1:
|
||||
getdisplay().setCursor(60, 90);
|
||||
getdisplay().print("Avg: 10s");
|
||||
getdisplay().setCursor(60, 180);
|
||||
getdisplay().print("Avg: 10s");
|
||||
getdisplay().setCursor(60, 270);
|
||||
getdisplay().print("Avg: 10s");
|
||||
epd->setCursor(60, 90);
|
||||
epd->print("Avg: 10s");
|
||||
epd->setCursor(60, 180);
|
||||
epd->print("Avg: 10s");
|
||||
epd->setCursor(60, 270);
|
||||
epd->print("Avg: 10s");
|
||||
break;
|
||||
case 2:
|
||||
getdisplay().setCursor(60, 90);
|
||||
getdisplay().print("Avg: 60s");
|
||||
getdisplay().setCursor(60, 180);
|
||||
getdisplay().print("Avg: 60s");
|
||||
getdisplay().setCursor(60, 270);
|
||||
getdisplay().print("Avg: 60s");
|
||||
epd->setCursor(60, 90);
|
||||
epd->print("Avg: 60s");
|
||||
epd->setCursor(60, 180);
|
||||
epd->print("Avg: 60s");
|
||||
epd->setCursor(60, 270);
|
||||
epd->print("Avg: 60s");
|
||||
break;
|
||||
case 3:
|
||||
getdisplay().setCursor(60, 90);
|
||||
getdisplay().print("Avg: 300s");
|
||||
getdisplay().setCursor(60, 180);
|
||||
getdisplay().print("Avg: 300s");
|
||||
getdisplay().setCursor(60, 270);
|
||||
getdisplay().print("Avg: 300s");
|
||||
epd->setCursor(60, 90);
|
||||
epd->print("Avg: 300s");
|
||||
epd->setCursor(60, 180);
|
||||
epd->print("Avg: 300s");
|
||||
epd->setCursor(60, 270);
|
||||
epd->print("Avg: 300s");
|
||||
break;
|
||||
default:
|
||||
getdisplay().setCursor(60, 90);
|
||||
getdisplay().print("Avg: 1s");
|
||||
getdisplay().setCursor(60, 180);
|
||||
getdisplay().print("Avg: 1s");
|
||||
getdisplay().setCursor(60, 270);
|
||||
getdisplay().print("Avg: 1s");
|
||||
epd->setCursor(60, 90);
|
||||
epd->print("Avg: 1s");
|
||||
epd->setCursor(60, 180);
|
||||
epd->print("Avg: 1s");
|
||||
epd->setCursor(60, 270);
|
||||
epd->print("Avg: 1s");
|
||||
break;
|
||||
}
|
||||
|
||||
// ############### Value 1 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 55);
|
||||
getdisplay().print(name1); // Value name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 55);
|
||||
epd->print(name1); // Value name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 90);
|
||||
getdisplay().print(unit1); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 90);
|
||||
epd->print(unit1); // Unit
|
||||
|
||||
// Show value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 90);
|
||||
|
||||
// Show bus data
|
||||
if(String(powsensor1) != "off"){
|
||||
getdisplay().print(value1,2); // Real value as formated string
|
||||
epd->print(value1,2); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // No sensor data (sensor is off)
|
||||
epd->print(commonData->fmt->placeholder); // No sensor data (sensor is off)
|
||||
}
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 2 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 145);
|
||||
getdisplay().print(name2); // Value name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 145);
|
||||
epd->print(name2); // Value name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 180);
|
||||
getdisplay().print(unit2); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 180);
|
||||
epd->print(unit2); // Unit
|
||||
|
||||
// Show value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 180);
|
||||
|
||||
// Show bus data
|
||||
if(String(powsensor1) != "off"){
|
||||
getdisplay().print(value2,1); // Real value as formated string
|
||||
epd->print(value2,1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // No sensor data (sensor is off)
|
||||
epd->print(commonData->fmt->placeholder); // No sensor data (sensor is off)
|
||||
}
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 3 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 235);
|
||||
getdisplay().print(name3); // Value name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 235);
|
||||
epd->print(name3); // Value name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 270);
|
||||
getdisplay().print(unit3); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 270);
|
||||
epd->print(unit3); // Unit
|
||||
|
||||
// Show value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 270);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 270);
|
||||
|
||||
// Show bus data
|
||||
if(String(powsensor1) != "off"){
|
||||
getdisplay().print(value3,1); // Real value as formated string
|
||||
epd->print(value3,1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // No sensor data (sensor is off)
|
||||
epd->print(commonData->fmt->placeholder); // No sensor data (sensor is off)
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -6,23 +7,34 @@
|
||||
|
||||
class PageBattery2 : public Page
|
||||
{
|
||||
bool init = false; // Marker for init done
|
||||
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;
|
||||
private:
|
||||
String batVoltage;
|
||||
int batCapacity;
|
||||
String batType;
|
||||
String powerSensor;
|
||||
bool init = false; // Marker for init done
|
||||
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");
|
||||
PageBattery2(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageBattery2");
|
||||
|
||||
// Get config data
|
||||
batVoltage = config->getString(config->batteryVoltage);
|
||||
batCapacity = config->getInt(config->batteryCapacity);
|
||||
batType = config->getString(config->batteryType);
|
||||
powerSensor = config->getString(config->usePowSensor1);
|
||||
}
|
||||
|
||||
virtual void setupKeys(){
|
||||
void setupKeys(){
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "AVG";
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key) {
|
||||
// Change average
|
||||
if(key == 1){
|
||||
average ++;
|
||||
@@ -44,11 +56,7 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData)
|
||||
{
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
// Polynominal coefficients second order for battery energy level calculation
|
||||
// index 0 = Pb, 1 = Gel, 2 = AGM, 3 = LiFePo4
|
||||
float x0[4] = {+3082.5178, +1656.1571, +1316.8766, +14986.9336}; // Offset
|
||||
@@ -57,16 +65,6 @@ public:
|
||||
int batPercentage = 0; // Battery level
|
||||
float batRange = 0; // Range in hours
|
||||
|
||||
// Get config data
|
||||
bool simulation = config->getBool(config->useSimuData);
|
||||
bool holdvalues = config->getBool(config->holdvalues);
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String batVoltage = config->getString(config->batteryVoltage);
|
||||
int batCapacity = config->getInt(config->batteryCapacity);
|
||||
String batType = config->getString(config->batteryType);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String powerSensor = config->getString(config->usePowSensor1);
|
||||
|
||||
double value1 = 0; // Battery voltage
|
||||
double value2 = 0; // Battery current
|
||||
double value3 = 0; // Battery power consumption
|
||||
@@ -142,149 +140,133 @@ public:
|
||||
if(batRange > 99) batRange = 99;
|
||||
|
||||
// Optical warning by limit violation
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
// Limits for Pb battery
|
||||
if(String(batType) == "Pb" && (raw < 11.8 || raw > 14.8)){
|
||||
if (flashLED == "Limit Violation") {
|
||||
bool violation = false;
|
||||
if (batType == "Pb") {
|
||||
violation = (raw < 11.8 || raw > 14.8);
|
||||
} else if (batType == "Gel") {
|
||||
violation = (raw < 11.8 || raw > 14.4);
|
||||
} else if (batType == "AGM") {
|
||||
violation = (raw < 11.8 || raw > 14.7);
|
||||
} else if (batType == "LiFePo4") {
|
||||
violation = (raw < 12.0 || raw > 14.6);
|
||||
}
|
||||
if (violation) {
|
||||
setBlinkingLED(true);
|
||||
}
|
||||
if(String(batType) == "Pb" && (raw >= 11.8 && raw <= 14.8)){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
// Limits for Gel battery
|
||||
if(String(batType) == "Gel" && (raw < 11.8 || raw > 14.4)){
|
||||
setBlinkingLED(true);
|
||||
}
|
||||
if(String(batType) == "Gel" && (raw >= 11.8 && raw <= 14.4)){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
// Limits for AGM battery
|
||||
if(String(batType) == "AGM" && (raw < 11.8 || raw > 14.7)){
|
||||
setBlinkingLED(true);
|
||||
}
|
||||
if(String(batType) == "AGM" && (raw >= 11.8 && raw <= 14.7)){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
// Limits for LiFePo4 battery
|
||||
if(String(batType) == "LiFePo4" && (raw < 12.0 || raw > 14.6)){
|
||||
setBlinkingLED(true);
|
||||
}
|
||||
if(String(batType) == "LiFePo4" && (raw >= 12.0 && raw <= 14.6)){
|
||||
} else {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Logging voltage value
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery2, Type:%s %s:=%f", batType.c_str(), name1.c_str(), raw);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageBattery2, Type:%s %s:=%f", batType.c_str(), name1.c_str(), raw);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(10, 65);
|
||||
getdisplay().print("Bat.");
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(10, 65);
|
||||
epd->print("Bat.");
|
||||
|
||||
// Show battery type
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(90, 65);
|
||||
getdisplay().print(batType);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(90, 65);
|
||||
epd->print(batType);
|
||||
|
||||
// Show voltage type
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 140);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 140);
|
||||
int bvoltage = 0;
|
||||
if(String(batVoltage) == "12V") bvoltage = 12;
|
||||
else bvoltage = 24;
|
||||
getdisplay().print(bvoltage);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
epd->print(bvoltage);
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("V");
|
||||
|
||||
// Show battery capacity
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
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);
|
||||
if(batCapacity <= 999) getdisplay().print("Ah");
|
||||
if(batCapacity > 999) getdisplay().print("kAh");
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 200);
|
||||
if(batCapacity <= 999) epd->print(batCapacity, 0);
|
||||
if(batCapacity > 999) epd->print(float(batCapacity/1000.0), 1);
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
if(batCapacity <= 999) epd->print("Ah");
|
||||
if(batCapacity > 999) epd->print("kAh");
|
||||
|
||||
// Show info
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(10, 235);
|
||||
getdisplay().print("Installed");
|
||||
getdisplay().setCursor(10, 255);
|
||||
getdisplay().print("Battery Type");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(10, 235);
|
||||
epd->print("Installed");
|
||||
epd->setCursor(10, 255);
|
||||
epd->print("Battery Type");
|
||||
|
||||
// Show battery with fill level
|
||||
batteryGraphic(150, 45, batPercentage, commonData->fgcolor, commonData->bgcolor);
|
||||
|
||||
// Show average settings
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(150, 145);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(150, 145);
|
||||
switch (average) {
|
||||
case 0:
|
||||
getdisplay().print("Avg: 1s");
|
||||
epd->print("Avg: 1s");
|
||||
break;
|
||||
case 1:
|
||||
getdisplay().print("Avg: 10s");
|
||||
epd->print("Avg: 10s");
|
||||
break;
|
||||
case 2:
|
||||
getdisplay().print("Avg: 60s");
|
||||
epd->print("Avg: 60s");
|
||||
break;
|
||||
case 3:
|
||||
getdisplay().print("Avg: 300s");
|
||||
epd->print("Avg: 300s");
|
||||
break;
|
||||
default:
|
||||
getdisplay().print("Avg: 1s");
|
||||
epd->print("Avg: 1s");
|
||||
break;
|
||||
}
|
||||
|
||||
// Show fill level in percent
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 200);
|
||||
getdisplay().print(batPercentage);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("%");
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(150, 200);
|
||||
epd->print(batPercentage);
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("%");
|
||||
|
||||
// Show time to full discharge
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 260);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(150, 260);
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(batRange < 9.9) getdisplay().print(batRange, 1);
|
||||
else getdisplay().print(batRange, 0);
|
||||
if(batRange < 9.9) epd->print(batRange, 1);
|
||||
else epd->print(batRange, 0);
|
||||
}
|
||||
else getdisplay().print("--");
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("h");
|
||||
else epd->print("--");
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("h");
|
||||
|
||||
// Show sensor type info
|
||||
String i2cAddr = "";
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(270, 60);
|
||||
if(powerSensor == "off") getdisplay().print("Internal");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(270, 60);
|
||||
if(powerSensor == "off") epd->print("Internal");
|
||||
if(powerSensor == "INA219"){
|
||||
getdisplay().print("INA219");
|
||||
epd->print("INA219");
|
||||
}
|
||||
if(powerSensor == "INA226"){
|
||||
getdisplay().print("INA226");
|
||||
epd->print("INA226");
|
||||
i2cAddr = " (0x" + String(INA226_I2C_ADDR1, HEX) + ")";
|
||||
}
|
||||
getdisplay().print(i2cAddr);
|
||||
getdisplay().setCursor(270, 80);
|
||||
getdisplay().print("Sensor Modul");
|
||||
epd->print(i2cAddr);
|
||||
epd->setCursor(270, 80);
|
||||
epd->print("Sensor Modul");
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 140);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(260, 140);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
@@ -293,46 +275,50 @@ public:
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
epd->print(value1,1);
|
||||
}
|
||||
else{
|
||||
// Check for valid real data, display also if hold values activated
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 <= 9.9) getdisplay().print(value1, 2);
|
||||
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
|
||||
if(value1 > 99.9) getdisplay().print(value1, 0);
|
||||
if(value1 <= 9.9) epd->print(value1, 2);
|
||||
if(value1 > 9.9 && value1 <= 99.9)epd->print(value1, 1);
|
||||
if(value1 > 99.9) epd->print(value1, 0);
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
epd->print(commonData->fmt->placeholder); // Missing bus data
|
||||
}
|
||||
}
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("V");
|
||||
|
||||
// Show actual current in A
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 200);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(260, 200);
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value2 <= 9.9) getdisplay().print(value2, 2);
|
||||
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
|
||||
if(value2 > 99.9) getdisplay().print(value2, 0);
|
||||
if(value2 <= 9.9) epd->print(value2, 2);
|
||||
if(value2 > 9.9 && value2 <= 99.9)epd->print(value2, 1);
|
||||
if(value2 > 99.9) epd->print(value2, 0);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("A");
|
||||
else {
|
||||
epd->print(commonData->fmt->placeholder);
|
||||
}
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("A");
|
||||
|
||||
// Show actual consumption in W
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 260);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(260, 260);
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value3 <= 9.9) getdisplay().print(value3, 2);
|
||||
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
|
||||
if(value3 > 99.9) getdisplay().print(value3, 0);
|
||||
if(value3 <= 9.9) epd->print(value3, 2);
|
||||
if(value3 > 9.9 && value3 <= 99.9)epd->print(value3, 1);
|
||||
if(value3 > 99.9) epd->print(value3, 0);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("W");
|
||||
else {
|
||||
epd->print(commonData->fmt->placeholder);
|
||||
}
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("W");
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -17,65 +18,65 @@ const int ShowSTW = 3;
|
||||
const int ShowSOG = 4;
|
||||
const int ShowDBS = 5;
|
||||
|
||||
const int Compass_X0 = 200; // X center point of compass band
|
||||
const int Compass_Y0 = 220; // Y 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
|
||||
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
|
||||
{
|
||||
private:
|
||||
int WhichDataCompass = ShowHDM;
|
||||
int WhichDataDisplay = ShowHDM;
|
||||
|
||||
public:
|
||||
PageCompass(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageCompass");
|
||||
public:
|
||||
PageCompass(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageCompass");
|
||||
}
|
||||
|
||||
virtual void setupKeys(){
|
||||
void setupKeys(){
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "CMP";
|
||||
commonData->keydata[1].label = "SRC";
|
||||
}
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key){
|
||||
// Code for keylock
|
||||
|
||||
if ( key == 1 ) {
|
||||
if (key == 1) {
|
||||
WhichDataCompass += 1;
|
||||
if ( WhichDataCompass > ShowCOG)
|
||||
WhichDataCompass = ShowHDM;
|
||||
return 0;
|
||||
}
|
||||
if ( key == 2 ) {
|
||||
}
|
||||
if (key == 2) {
|
||||
WhichDataDisplay += 1;
|
||||
if ( WhichDataDisplay > ShowDBS)
|
||||
if (WhichDataDisplay > ShowDBS)
|
||||
WhichDataDisplay = ShowHDM;
|
||||
}
|
||||
|
||||
if(key == 11){
|
||||
}
|
||||
if (key == 11) {
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
// 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];
|
||||
@@ -87,21 +88,15 @@ class PageCompass : public Page
|
||||
|
||||
for (int i = 0; i < HowManyValues; i++){
|
||||
bvalue = pageData.values[i];
|
||||
TheFormattedData = formatValue(bvalue, *commonData);
|
||||
TheFormattedData = commonData->fmt->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;
|
||||
DataUnits[i] = commonData->fmt->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);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageCompass: %d %s %f %s %s", i, DataName[i], DataValue[i], DataFormat[i], DataText[i] );
|
||||
}
|
||||
|
||||
if (bvalue == NULL) return PAGE_OK; // WTF why this statement?
|
||||
@@ -109,27 +104,27 @@ class PageCompass : public Page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
epd->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
|
||||
epd->fillRect(0, 130, 400, 2, commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(10, 70);
|
||||
epd->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);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(10, 120);
|
||||
epd->print(DataUnits[WhichDataDisplay]);
|
||||
epd->setCursor(190, 120);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic42pt7b);
|
||||
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(DataText[WhichDataDisplay]); // Real value as formated string
|
||||
epd->print(DataText[WhichDataDisplay]); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(OldDataText[WhichDataDisplay]); // Old value as formated string
|
||||
epd->print(OldDataText[WhichDataDisplay]); // Old value as formated string
|
||||
}
|
||||
if(DataValid[WhichDataDisplay] == true){
|
||||
OldDataText[WhichDataDisplay] = DataText[WhichDataDisplay]; // Save the old value
|
||||
@@ -148,14 +143,14 @@ class PageCompass : public Page
|
||||
char buffer[bsize+1];
|
||||
buffer[0]=0;
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(10, Compass_Y0-60);
|
||||
getdisplay().print(DataName[WhichDataCompass]); // Page name
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(10, Compass_Y0-60);
|
||||
epd->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);
|
||||
epd->fillRect(0, Compass_Y0, 400, 3, commonData->fgcolor);
|
||||
epd->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;
|
||||
@@ -164,7 +159,7 @@ class PageCompass : public Page
|
||||
else
|
||||
x1 = Compass_X0 - 20 * ( i + 1 );
|
||||
|
||||
getdisplay().fillRect(x1, Compass_Y0 -55, 10, 6, commonData->fgcolor);
|
||||
epd->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
|
||||
@@ -174,28 +169,28 @@ class PageCompass : public Page
|
||||
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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->fillRect(x0-1, Compass_Y0 - Compass_LineLength, 3, Compass_LineLength, commonData->fgcolor);
|
||||
}
|
||||
|
||||
getdisplay().fillRect(0, Compass_Y0, 400, 3, commonData->fgcolor);
|
||||
epd->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);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
|
||||
do {
|
||||
getdisplay().setCursor(x0 - 40, Compass_Y0 + 40);
|
||||
epd->setCursor(x0 - 40, Compass_Y0 + 40);
|
||||
snprintf(buffer,bsize,"%03.0f", AngleToDisplay);
|
||||
getdisplay().print(buffer);
|
||||
epd->print(buffer);
|
||||
AngleToDisplay += 20;
|
||||
if ( AngleToDisplay >= 360.0 )
|
||||
AngleToDisplay -= 360.0;
|
||||
@@ -208,7 +203,7 @@ class PageCompass : public Page
|
||||
|
||||
x0 = Compass_X0 + Delta_X + 4 * 5 * Compass_LineDelta;
|
||||
do {
|
||||
getdisplay().setCursor(x0 - 40, Compass_Y0 + 40);
|
||||
epd->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 )
|
||||
@@ -218,7 +213,7 @@ class PageCompass : public Page
|
||||
else if ( ( x0 - 40 ) > 325 )
|
||||
buffer[2] = 0;
|
||||
|
||||
getdisplay().print(buffer);
|
||||
epd->print(buffer);
|
||||
|
||||
AngleToDisplay -= 20;
|
||||
if ( AngleToDisplay < 0 )
|
||||
@@ -230,8 +225,8 @@ class PageCompass : public Page
|
||||
// x_test += 2;
|
||||
|
||||
// snprintf(buffer,bsize,"%03d", x_test);
|
||||
// getdisplay().setCursor(x_test, Compass_Y0 - 60);
|
||||
// getdisplay().print(buffer);
|
||||
// epd->setCursor(x_test, Compass_Y0 - 60);
|
||||
// epd->print(buffer);
|
||||
// if ( x_test > 390)
|
||||
// x_test = 320;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -5,13 +6,19 @@
|
||||
|
||||
class PageDST810 : public Page
|
||||
{
|
||||
private:
|
||||
String lengthformat;
|
||||
|
||||
public:
|
||||
PageDST810(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageDST810");
|
||||
PageDST810(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageDST810");
|
||||
|
||||
// Get config data
|
||||
lengthformat = config->getString(config->lengthFormat);
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key) {
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -20,9 +27,7 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
@@ -34,21 +39,14 @@ public:
|
||||
static String svalue4old = "";
|
||||
static String unit4old = "";
|
||||
|
||||
// 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 #1
|
||||
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
|
||||
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 = commonData->fmt->formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit1 = commonData->fmt->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 +54,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 = commonData->fmt->formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit2 = commonData->fmt->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 +63,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 = commonData->fmt->formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit3 = commonData->fmt->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 +72,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 = commonData->fmt->formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit4 = commonData->fmt->formatValue(bvalue4, *commonData).unit; // Unit of value
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
@@ -85,43 +83,43 @@ public:
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageDST810, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageDST810, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// ############### Value 1 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 55);
|
||||
getdisplay().print("Depth"); // Page name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 55);
|
||||
epd->print("Depth"); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 90);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 90);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit1); // Unit
|
||||
epd->print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit1old);
|
||||
epd->print(unit1old);
|
||||
}
|
||||
|
||||
// Set font
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 90);
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
epd->print(svalue1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Old value as formated string
|
||||
epd->print(svalue1old); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
@@ -131,35 +129,35 @@ public:
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 2 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 145);
|
||||
getdisplay().print("Speed"); // Page name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 145);
|
||||
epd->print("Speed"); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 180);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 180);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit2); // Unit
|
||||
epd->print(unit2); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit2old);
|
||||
epd->print(unit2old);
|
||||
}
|
||||
|
||||
// Setfont
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 180);
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
epd->print(svalue2); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Old value as formated string
|
||||
epd->print(svalue2old); // Old value as formated string
|
||||
}
|
||||
if(valid2 == true){
|
||||
svalue2old = svalue2; // Save the old value
|
||||
@@ -169,35 +167,35 @@ public:
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 3 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 220);
|
||||
getdisplay().print("Log"); // Page name
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 220);
|
||||
epd->print("Log"); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(20, 240);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit3); // Unit
|
||||
epd->print(unit3); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit3old);
|
||||
epd->print(unit3old);
|
||||
}
|
||||
|
||||
// Set font
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(80, 270);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(80, 270);
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
epd->print(svalue3); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue3old); // Old value as formated string
|
||||
epd->print(svalue3old); // Old value as formated string
|
||||
}
|
||||
if(valid3 == true){
|
||||
svalue3old = svalue3; // Save the old value
|
||||
@@ -207,35 +205,35 @@ public:
|
||||
// ############### Vertical Line ################
|
||||
|
||||
// Vertical line 3 pix
|
||||
getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
|
||||
epd->fillRect(200, 195, 3, 75, commonData->fgcolor);
|
||||
|
||||
// ############### Value 4 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(220, 220);
|
||||
getdisplay().print("Temp"); // Page name
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(220, 220);
|
||||
epd->print("Temp"); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(220, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(220, 240);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit4); // Unit
|
||||
epd->print(unit4); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit4old);
|
||||
epd->print(unit4old);
|
||||
}
|
||||
|
||||
// Set font
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(280, 270);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(280, 270);
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue4); // Real value as formated string
|
||||
epd->print(svalue4); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue4old); // Old value as formated string
|
||||
epd->print(svalue4old); // Old value as formated string
|
||||
}
|
||||
if(valid4 == true){
|
||||
svalue4old = svalue4; // Save the old value
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include <PCF8574.h> // PCF8574 modules from Horter
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
#include "images/OBP_400x300.xbm" // OBP Logo
|
||||
#ifdef BOARD_OBP60S3
|
||||
#include "images/OBP60_400x300.xbm" // MFD with logo
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
#include "images/OBP40_400x300.xbm" // MFD with logo
|
||||
#endif
|
||||
|
||||
class PageDigitalOut : public Page
|
||||
{
|
||||
|
||||
// Status values
|
||||
bool button1 = false;
|
||||
bool button2 = false;
|
||||
bool button3 = false;
|
||||
bool button4 = false;
|
||||
bool button5 = false;
|
||||
|
||||
public:
|
||||
PageDigitalOut(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageDigitalOut");
|
||||
}
|
||||
|
||||
// Set botton labels
|
||||
virtual void setupKeys(){
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "1";
|
||||
commonData->keydata[1].label = "2";
|
||||
commonData->keydata[2].label = "3";
|
||||
commonData->keydata[3].label = "4";
|
||||
commonData->keydata[4].label = "5";
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
// Code for button 1
|
||||
if(key == 1){
|
||||
button1 = !button1;
|
||||
setPCF8574PortPinModul1(0, button1 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||
return 0; // Commit the key
|
||||
}
|
||||
// Code for button 2
|
||||
if(key == 2){
|
||||
button2 = !button2;
|
||||
setPCF8574PortPinModul1(1, button2 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||
return 0; // Commit the key
|
||||
}
|
||||
// Code for button 3
|
||||
if(key == 3){
|
||||
button3 = !button3;
|
||||
setPCF8574PortPinModul1(2, button3 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||
return 0; // Commit the key
|
||||
}
|
||||
// Code for button 4
|
||||
if(key == 4){
|
||||
button4 = !button4;
|
||||
setPCF8574PortPinModul1(3, button4 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||
return 0; // Commit the key
|
||||
}
|
||||
// Code for button 5
|
||||
if(key == 5){
|
||||
button5 = !button5;
|
||||
setPCF8574PortPinModul1(4, button5 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
// 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);
|
||||
String name1 = config->getString(config->mod1Out1);
|
||||
String name2 = config->getString(config->mod1Out2);
|
||||
String name3 = config->getString(config->mod1Out3);
|
||||
String name4 = config->getString(config->mod1Out4);
|
||||
String name5 = config->getString(config->mod1Out5);
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageDigitalOut");
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
// Write text
|
||||
getdisplay().setCursor(100, 50 + 8);
|
||||
getdisplay().print(name1);
|
||||
getdisplay().setCursor(100, 100 + 8);
|
||||
getdisplay().print(name2);
|
||||
getdisplay().setCursor(100, 150 + 8);
|
||||
getdisplay().print(name3);
|
||||
getdisplay().setCursor(100,200 + 8);
|
||||
getdisplay().print(name4);
|
||||
getdisplay().setCursor(100, 250 + 8);
|
||||
getdisplay().print(name5);
|
||||
// Draw bottons
|
||||
drawButtonCenter(50, 50, 40, 27, "1", commonData->fgcolor, commonData->bgcolor, button1);
|
||||
drawButtonCenter(50, 100, 40, 27, "2", commonData->fgcolor, commonData->bgcolor, button2);
|
||||
drawButtonCenter(50, 150, 40, 27, "3", commonData->fgcolor, commonData->bgcolor, button3);
|
||||
drawButtonCenter(50, 200, 40, 27, "4", commonData->fgcolor, commonData->bgcolor, button4);
|
||||
drawButtonCenter(50, 250, 40, 27, "5", commonData->fgcolor, commonData->bgcolor, button5);
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page* createPage(CommonData &common){
|
||||
return new PageDigitalOut(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 registerPageDigitalOut(
|
||||
"DigitalOut", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
145
lib/obp60task/PageEPropulsion.cpp
Normal file
145
lib/obp60task/PageEPropulsion.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
/*
|
||||
Electric propulsion
|
||||
|
||||
- Current, voltage, power
|
||||
- 12, 24, 48 etc. Voltage
|
||||
- rpm
|
||||
- throttle position
|
||||
- controller state
|
||||
- error codes
|
||||
- temperature engine, controller, batteries
|
||||
|
||||
*/
|
||||
|
||||
class PageEPropulsion : public Page
|
||||
{
|
||||
private:
|
||||
char mode = 'N'; // (N)ormal, (C)onfig
|
||||
|
||||
void displayModeNormal(PageData &pageData) {
|
||||
|
||||
// TBD Boatvalues: ...
|
||||
|
||||
logger->logDebug(GwLog::DEBUG, "Drawing at PageEPropulsion");
|
||||
|
||||
// Title and corner value headings
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("Electric propulsion");
|
||||
|
||||
}
|
||||
|
||||
void displayModeConfig() {
|
||||
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(8, 48);
|
||||
epd->print("EPropulsion configuration");
|
||||
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
// TODO menu
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
PageEPropulsion(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG,"Instantiate PageEPropulsion");
|
||||
}
|
||||
|
||||
void setupKeys(){
|
||||
Page::setupKeys();
|
||||
}
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
int handleKey(int key){
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
} else {
|
||||
mode = 'N';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
int handleKey(int key){
|
||||
if (key == 1) { // Switch between normal and config mode
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
commonData->keydata[1].label = "EDIT";
|
||||
} else {
|
||||
mode = 'N';
|
||||
commonData->keydata[1].label = "ALARM";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
|
||||
void displayNew(PageData &pageData){
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
|
||||
// Logging boat values
|
||||
logger->logDebug(GwLog::LOG,"Drawing at PageEPropulsion; Mode=%c", mode);
|
||||
|
||||
// Set display in partial refresh mode
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height());
|
||||
|
||||
if (mode == 'N') {
|
||||
displayModeNormal(pageData);
|
||||
} else if (mode == 'C') {
|
||||
displayModeConfig();
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageEPropulsion(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 registerPageEPropulsion(
|
||||
"EPropulsion", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -66,25 +67,22 @@ static unsigned char fish_bits[] = {
|
||||
|
||||
class PageFluid : public Page
|
||||
{
|
||||
bool simulation = false;
|
||||
private:
|
||||
double simgoto;
|
||||
double simval;
|
||||
double simstep;
|
||||
bool holdvalues = false;
|
||||
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);
|
||||
public:
|
||||
PageFluid(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageFluid");
|
||||
simval = double(random(0, 100));
|
||||
simgoto = double(random(0, 100));
|
||||
simstep = (simgoto - simval) / 20.0;
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key) {
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -93,27 +91,22 @@ class PageFluid : public Page
|
||||
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);
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
// Old values for hold function
|
||||
static double value1old;
|
||||
|
||||
// Get config data
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
void displayNew(PageData &pageData) {
|
||||
fluidtype = config->getInt("page" + String(pageData.pageNumber) + "fluid", 0);
|
||||
logger->logDebug(GwLog::LOG, "New PageFluid: fluidtype=%d", fluidtype);
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
// Old values for hold function
|
||||
static double value1old;
|
||||
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0];
|
||||
String name1 = bvalue1->getName();
|
||||
@@ -132,23 +125,23 @@ class PageFluid : public Page
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid: value=%f", bvalue1->value);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageFluid: value=%f", bvalue1->value);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height());
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height());
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// descriptions
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 60);
|
||||
getdisplay().print("Fluid");
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 60);
|
||||
epd->print("Fluid");
|
||||
|
||||
getdisplay().setCursor(300, 60);
|
||||
getdisplay().print(xdrDelete(name1).substring(0, 6));
|
||||
epd->setCursor(300, 60);
|
||||
epd->print(xdrDelete(name1).substring(0, 6));
|
||||
|
||||
// analog instrument
|
||||
// scale from -120 to 120
|
||||
@@ -158,11 +151,11 @@ 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);
|
||||
epd->drawCircle(c.x, c.y, r+5, commonData->fgcolor);
|
||||
epd->fillCircle(c.x, c.y, r+2, commonData->fgcolor);
|
||||
epd->fillCircle(c.x, c.y, r-1, commonData->bgcolor);
|
||||
// center of pointer as dot
|
||||
getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
|
||||
epd->fillCircle(c.x, c.y, 8, commonData->fgcolor);
|
||||
|
||||
// value down centered
|
||||
char buffer[6];
|
||||
@@ -176,32 +169,32 @@ class PageFluid : public Page
|
||||
// draw symbol (as bitmap)
|
||||
switch (fluidtype) {
|
||||
case 0:
|
||||
getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData->fgcolor);
|
||||
epd->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);
|
||||
epd->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);
|
||||
// epd->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);
|
||||
epd->drawXBitmap(c.x-8, c.y-50, fish_bits, fish_width, fish_height, commonData->fgcolor);
|
||||
break;
|
||||
case 4:
|
||||
getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData->fgcolor);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->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);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
p = {c.x, c.y - r + 30};
|
||||
drawTextCenter(p.x, p.y, "1/2");
|
||||
pr = rotatePoint(c, p, -60);
|
||||
@@ -210,7 +203,7 @@ class PageFluid : public Page
|
||||
drawTextCenter(pr.x, pr.y, "3/4");
|
||||
|
||||
// empty and full
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
p = rotatePoint(c, {c.x, c.y - r + 30}, -130);
|
||||
drawTextCenter(p.x, p.y, "E");
|
||||
p = rotatePoint(c, {c.x, c.y - r + 30}, 130);
|
||||
@@ -236,7 +229,7 @@ class PageFluid : public Page
|
||||
continue;
|
||||
}
|
||||
p = rotatePoint(c, {c.x, c.y - r + 10}, angle);
|
||||
getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
|
||||
epd->fillCircle(p.x, p.y, 3, commonData->fgcolor);
|
||||
}
|
||||
|
||||
// pointer
|
||||
@@ -249,7 +242,7 @@ class PageFluid : public Page
|
||||
};
|
||||
fillPoly4(rotatePoints(c, pts, -120 + fluidlevel * 2.4), commonData->fgcolor);
|
||||
// Pointer axis is white
|
||||
getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
|
||||
epd->fillCircle(c.x, c.y, 6, commonData->bgcolor);
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
#include "BoatDataCalibration.h"
|
||||
#endif
|
||||
|
||||
class PageFourValues : public Page
|
||||
{
|
||||
public:
|
||||
PageFourValues(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues");
|
||||
private:
|
||||
String lengthformat;
|
||||
|
||||
public:
|
||||
PageFourValues(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageFourValues");
|
||||
|
||||
// Get config data
|
||||
lengthformat = config->getString(config->lengthFormat);
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key){
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -20,9 +31,17 @@ class PageFourValues : public Page
|
||||
return key;
|
||||
}
|
||||
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
@@ -33,105 +52,104 @@ class PageFourValues : public Page
|
||||
static String unit3old = "";
|
||||
static String svalue4old = "";
|
||||
static String unit4old = "";
|
||||
|
||||
// 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 #1
|
||||
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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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 = commonData->fmt->formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit1 = commonData->fmt->formatValue(bvalue1, *commonData).unit; // Unit of value
|
||||
|
||||
// Get boat values #2
|
||||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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 = commonData->fmt->formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit2 = commonData->fmt->formatValue(bvalue2, *commonData).unit; // Unit of value
|
||||
|
||||
// Get boat values #3
|
||||
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Third element in list
|
||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||
name3 = name3.substring(0, 6); // String length limit for value name
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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 = commonData->fmt->formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit3 = commonData->fmt->formatValue(bvalue3, *commonData).unit; // Unit of value
|
||||
|
||||
// Get boat values #4
|
||||
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Fourth element in list
|
||||
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
||||
name4 = name4.substring(0, 6); // String length limit for value name
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
String svalue4 = commonData->fmt->formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit4 = commonData->fmt->formatValue(bvalue4, *commonData).unit; // Unit of value
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageFourValues, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// ############### Value 1 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(20, 45);
|
||||
getdisplay().print(name1); // Page name
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(20, 45);
|
||||
epd->print(name1); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 65);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(20, 65);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit1); // Unit
|
||||
epd->print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit1old);
|
||||
epd->print(unit1old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 55);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(120, 55);
|
||||
}
|
||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 58);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(150, 58);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 65);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(180, 65);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
epd->print(svalue1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Old value as formated string
|
||||
epd->print(svalue1old); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
@@ -141,45 +159,45 @@ class PageFourValues : public Page
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 80, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 80, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 2 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(20, 113);
|
||||
getdisplay().print(name2); // Page name
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(20, 113);
|
||||
epd->print(name2); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 133);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(20, 133);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit2); // Unit
|
||||
epd->print(unit2); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit2old);
|
||||
epd->print(unit2old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 123);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(120, 123);
|
||||
}
|
||||
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 123);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(150, 123);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 133);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(180, 133);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
epd->print(svalue2); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Old value as formated string
|
||||
epd->print(svalue2old); // Old value as formated string
|
||||
}
|
||||
if(valid2 == true){
|
||||
svalue2old = svalue2; // Save the old value
|
||||
@@ -189,45 +207,45 @@ class PageFourValues : public Page
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 146, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 146, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 3 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(20, 181);
|
||||
getdisplay().print(name3); // Page name
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(20, 181);
|
||||
epd->print(name3); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 201);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(20, 201);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit3); // Unit
|
||||
epd->print(unit3); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit3old);
|
||||
epd->print(unit3old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 191);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(120, 191);
|
||||
}
|
||||
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 191);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(150, 191);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 201);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(180, 201);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
epd->print(svalue3); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue3old); // Old value as formated string
|
||||
epd->print(svalue3old); // Old value as formated string
|
||||
}
|
||||
if(valid3 == true){
|
||||
svalue3old = svalue3; // Save the old value
|
||||
@@ -237,45 +255,45 @@ class PageFourValues : public Page
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 214, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 214, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 4 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(20, 249);
|
||||
getdisplay().print(name4); // Page name
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(20, 249);
|
||||
epd->print(name4); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 269);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(20, 269);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit4); // Unit
|
||||
epd->print(unit4); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit4old);
|
||||
epd->print(unit4old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 259);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(120, 259);
|
||||
}
|
||||
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 259);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(150, 259);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 269);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(180, 269);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue4); // Real value as formated string
|
||||
epd->print(svalue4); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue4old); // Old value as formated string
|
||||
epd->print(svalue4old); // Old value as formated string
|
||||
}
|
||||
if(valid4 == true){
|
||||
svalue4old = svalue4; // Save the old value
|
||||
@@ -284,6 +302,11 @@ class PageFourValues : public Page
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
void leavePage(PageData &pageData) {
|
||||
logger->logDebug(GwLog::LOG, "Leaving PageFourvalues");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "BoatDataCalibration.h"
|
||||
|
||||
class PageFourValues2 : public Page
|
||||
{
|
||||
public:
|
||||
PageFourValues2(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues2");
|
||||
private:
|
||||
String lengthformat;
|
||||
|
||||
public:
|
||||
PageFourValues2(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageFourValues2");
|
||||
|
||||
// Get config data
|
||||
lengthformat = config->getString(config->lengthFormat);
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key) {
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock; // Toggle keylock
|
||||
@@ -20,9 +28,17 @@ class PageFourValues2 : public Page
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
@@ -33,105 +49,104 @@ class PageFourValues2 : public Page
|
||||
static String unit3old = "";
|
||||
static String svalue4old = "";
|
||||
static String unit4old = "";
|
||||
|
||||
// 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 #1
|
||||
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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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 = commonData->fmt->formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit1 = commonData->fmt->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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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 = commonData->fmt->formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit2 = commonData->fmt->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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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 = commonData->fmt->formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit3 = commonData->fmt->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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
String svalue4 = commonData->fmt->formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit4 = commonData->fmt->formatValue(bvalue4, *commonData).unit; // Unit of value
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues2, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageFourValues2, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// ############### Value 1 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 55);
|
||||
getdisplay().print(name1); // Page name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 55);
|
||||
epd->print(name1); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 90);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 90);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit1); // Unit
|
||||
epd->print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit1old);
|
||||
epd->print(unit1old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(100, 90);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(100, 90);
|
||||
}
|
||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(180, 77);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(180, 77);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 90);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
epd->print(svalue1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Old value as formated string
|
||||
epd->print(svalue1old); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
@@ -141,45 +156,45 @@ class PageFourValues2 : public Page
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 105, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 2 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 145);
|
||||
getdisplay().print(name2); // Page name
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 145);
|
||||
epd->print(name2); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 180);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 180);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit2); // Unit
|
||||
epd->print(unit2); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit2old);
|
||||
epd->print(unit2old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(100, 180);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(100, 180);
|
||||
}
|
||||
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(180, 158);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(180, 158);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
epd->setCursor(180, 180);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
epd->print(svalue2); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Old value as formated string
|
||||
epd->print(svalue2old); // Old value as formated string
|
||||
}
|
||||
if(valid2 == true){
|
||||
svalue2old = svalue2; // Save the old value
|
||||
@@ -189,45 +204,45 @@ class PageFourValues2 : public Page
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
epd->fillRect(0, 195, 400, 3, commonData->fgcolor);
|
||||
|
||||
// ############### Value 3 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 220);
|
||||
getdisplay().print(name3); // Page name
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(20, 220);
|
||||
epd->print(name3); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(20, 240);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit3); // Unit
|
||||
epd->print(unit3); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit3old);
|
||||
epd->print(unit3old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(50, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(50, 240);
|
||||
}
|
||||
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(100, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(100, 240);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(80, 270);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(80, 270);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
epd->print(svalue3); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue3old); // Old value as formated string
|
||||
epd->print(svalue3old); // Old value as formated string
|
||||
}
|
||||
if(valid3 == true){
|
||||
svalue3old = svalue3; // Save the old value
|
||||
@@ -237,45 +252,45 @@ class PageFourValues2 : public Page
|
||||
// ############### Vertical Line ################
|
||||
|
||||
// Vertical line 3 pix
|
||||
getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
|
||||
epd->fillRect(200, 195, 3, 75, commonData->fgcolor);
|
||||
|
||||
// ############### Value 4 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(220, 220);
|
||||
getdisplay().print(name4); // Page name
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(220, 220);
|
||||
epd->print(name4); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(220, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(220, 240);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit4); // Unit
|
||||
epd->print(unit4); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(unit4old);
|
||||
epd->print(unit4old);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(250, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(250, 240);
|
||||
}
|
||||
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(300, 240);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(300, 240);
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(280, 270);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(280, 270);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue4); // Real value as formated string
|
||||
epd->print(svalue4); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue4old); // Old value as formated string
|
||||
epd->print(svalue4old); // Old value as formated string
|
||||
}
|
||||
if(valid4 == true){
|
||||
svalue4old = svalue4; // Save the old value
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -6,12 +7,23 @@
|
||||
|
||||
class PageGenerator : public Page
|
||||
{
|
||||
private:
|
||||
String batVoltage;
|
||||
int genPower;
|
||||
String powerSensor;
|
||||
|
||||
public:
|
||||
PageGenerator(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageGenerator");
|
||||
PageGenerator(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageGenerator");
|
||||
|
||||
// Get config data
|
||||
batVoltage = config->getString(config->batteryVoltage);
|
||||
genPower = config->getInt(config->genPower);
|
||||
powerSensor = config->getString(config->usePowSensor3);
|
||||
}
|
||||
virtual int handleKey(int key){
|
||||
|
||||
int handleKey(int key){
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -20,20 +32,8 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData)
|
||||
{
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
// Get config data
|
||||
bool simulation = config->getBool(config->useSimuData);
|
||||
bool holdvalues = config->getBool(config->holdvalues);
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String batVoltage = config->getString(config->batteryVoltage);
|
||||
int genPower = config->getInt(config->genPower);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String powerSensor = config->getString(config->usePowSensor3);
|
||||
|
||||
double value1 = 0; // Solar voltage
|
||||
double value2 = 0; // Solar current
|
||||
double value3 = 0; // Solar output power
|
||||
@@ -60,100 +60,95 @@ public:
|
||||
bool valid1 = true;
|
||||
|
||||
// Optical warning by limit violation
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
// Over voltage
|
||||
if(value1 > 14.8 && batVoltage == "12V"){
|
||||
setBlinkingLED(true);
|
||||
}
|
||||
if(value1 <= 14.8 && batVoltage == "12V"){
|
||||
if (flashLED == "Limit Violation") {
|
||||
// Over voltage?
|
||||
if (batVoltage == "12V") {
|
||||
setBlinkingLED(value1 > 14.8);
|
||||
} else if (batVoltage == "24V") {
|
||||
setBlinkingLED(value1 > 29.6);
|
||||
} else {
|
||||
setBlinkingLED(false);
|
||||
}
|
||||
if(value1 > 29.6 && batVoltage == "24V"){
|
||||
setBlinkingLED(true);
|
||||
}
|
||||
if(value1 <= 29.6 && batVoltage == "24V"){
|
||||
setBlinkingLED(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Logging voltage value
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageGenerator, Type:%iW %s:=%f", genPower, name1.c_str(), value1);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageGenerator, Type:%iW %s:=%f", genPower, name1.c_str(), value1);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(10, 65);
|
||||
getdisplay().print("Power");
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(12, 82);
|
||||
getdisplay().print("Generator");
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(10, 65);
|
||||
epd->print("Power");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(12, 82);
|
||||
epd->print("Generator");
|
||||
|
||||
// Show voltage type
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 140);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 140);
|
||||
int bvoltage = 0;
|
||||
if(String(batVoltage) == "12V") bvoltage = 12;
|
||||
else bvoltage = 24;
|
||||
getdisplay().print(bvoltage);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
epd->print(bvoltage);
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("V");
|
||||
|
||||
// Show solar power
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
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);
|
||||
if(genPower <= 999) getdisplay().print("W");
|
||||
if(genPower > 999) getdisplay().print("kW");
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 200);
|
||||
if(genPower <= 999) epd->print(genPower, 0);
|
||||
if(genPower > 999) epd->print(float(genPower/1000.0), 1);
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
if(genPower <= 999) epd->print("W");
|
||||
if(genPower > 999) epd->print("kW");
|
||||
|
||||
// Show info
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(10, 235);
|
||||
getdisplay().print("Installed");
|
||||
getdisplay().setCursor(10, 255);
|
||||
getdisplay().print("Power Modul");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(10, 235);
|
||||
epd->print("Installed");
|
||||
epd->setCursor(10, 255);
|
||||
epd->print("Power Modul");
|
||||
|
||||
// Show generator
|
||||
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().print("%");
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(150, 235);
|
||||
getdisplay().print("Load");
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(150, 200);
|
||||
epd->print(genPercentage);
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("%");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(150, 235);
|
||||
epd->print("Load");
|
||||
|
||||
// Show sensor type info
|
||||
String i2cAddr = "";
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(270, 60);
|
||||
if(powerSensor == "off") getdisplay().print("Internal");
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(270, 60);
|
||||
if(powerSensor == "off") epd->print("Internal");
|
||||
if(powerSensor == "INA219"){
|
||||
getdisplay().print("INA219");
|
||||
epd->print("INA219");
|
||||
i2cAddr = " (0x" + String(INA219_I2C_ADDR3, HEX) + ")";
|
||||
}
|
||||
if(powerSensor == "INA226"){
|
||||
getdisplay().print("INA226");
|
||||
epd->print("INA226");
|
||||
i2cAddr = " (0x" + String(INA226_I2C_ADDR3, HEX) + ")";
|
||||
}
|
||||
getdisplay().print(i2cAddr);
|
||||
getdisplay().setCursor(270, 80);
|
||||
getdisplay().print("Sensor Modul");
|
||||
epd->print(i2cAddr);
|
||||
epd->setCursor(270, 80);
|
||||
epd->print("Sensor Modul");
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 140);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(260, 140);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
@@ -162,46 +157,59 @@ public:
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
epd->print(value1,1);
|
||||
}
|
||||
else{
|
||||
// Check for valid real data, display also if hold values activated
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 <= 9.9) getdisplay().print(value1, 2);
|
||||
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
|
||||
if(value1 > 99.9) getdisplay().print(value1, 0);
|
||||
if(value1 <= 9.9) epd->print(value1, 2);
|
||||
if(value1 > 9.9 && value1 <= 99.9)epd->print(value1, 1);
|
||||
if(value1 > 99.9) epd->print(value1, 0);
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
epd->print(commonData->fmt->placeholder); // Missing bus data
|
||||
}
|
||||
}
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("V");
|
||||
|
||||
// Show actual current in A
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 200);
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value2 <= 9.9) getdisplay().print(value2, 2);
|
||||
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
|
||||
if(value2 > 99.9) getdisplay().print(value2, 0);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(260, 200);
|
||||
if ((powerSensor == "INA219" || powerSensor == "INA226") && (simulation == false)) {
|
||||
// TODO use formatter for this?
|
||||
if (value2 <= 9.9) {
|
||||
epd->print(value2, 2);
|
||||
} else if (value2 <= 99.9) {
|
||||
epd->print(value2, 1);
|
||||
} else {
|
||||
epd->print(value2, 0);
|
||||
}
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("A");
|
||||
else {
|
||||
epd->print(commonData->fmt->placeholder);
|
||||
}
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("A");
|
||||
|
||||
// Show actual consumption in W
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 260);
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value3 <= 9.9) getdisplay().print(value3, 2);
|
||||
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
|
||||
if(value3 > 99.9) getdisplay().print(value3, 0);
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(260, 260);
|
||||
if ((powerSensor == "INA219" || powerSensor == "INA226") && (simulation == false)) {
|
||||
if(value3 <= 9.9) {
|
||||
epd->print(value3, 2);
|
||||
} else if (value3 <= 99.9) {
|
||||
epd->print(value3, 1);
|
||||
} else {
|
||||
epd->print(value3, 0);
|
||||
}
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("W");
|
||||
else {
|
||||
epd->print(commonData->fmt->placeholder);
|
||||
}
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->print("W");
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -5,14 +6,24 @@
|
||||
|
||||
class PageKeelPosition : public Page
|
||||
{
|
||||
private:
|
||||
String lengthformat;
|
||||
String rotsensor;
|
||||
String rotfunction;
|
||||
|
||||
public:
|
||||
PageKeelPosition(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageKeelPosition");
|
||||
PageKeelPosition(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageKeelPosition");
|
||||
|
||||
// Get config data
|
||||
lengthformat = config->getString(config->lengthFormat);
|
||||
rotsensor = config->getString(config->useRotSensor);
|
||||
rotfunction = config->getString(config->rotFunction);
|
||||
}
|
||||
|
||||
// Key functions
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key){
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -21,23 +32,21 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData)
|
||||
{
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
double value1 = 0;
|
||||
double value1old = 0;
|
||||
|
||||
// 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);
|
||||
String rotsensor = config->getString(config->useRotSensor);
|
||||
String rotfunction = config->getString(config->rotFunction);
|
||||
|
||||
// Get boat values for Keel position
|
||||
bool valid1 = commonData->data.validRotAngle; // Valid information
|
||||
if(simulation == false && rotsensor == "AS5600" && rotfunction == "Keel"){
|
||||
@@ -55,20 +64,14 @@ public:
|
||||
value1old = value1; // Save old value
|
||||
}
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageKeelPosition, Keel:%f", value1);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageKeelPosition, Keel:%f", value1);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
//*******************************************************************************************
|
||||
|
||||
@@ -76,9 +79,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
|
||||
epd->fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
|
||||
epd->fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
|
||||
epd->fillRect(0, 30, 400, 122, commonData->bgcolor); // Delete half top circle
|
||||
|
||||
for(int i=90; i<=270; i=i+10)
|
||||
{
|
||||
@@ -105,17 +108,17 @@ public:
|
||||
// Print text centered on position x, y
|
||||
int16_t x1, y1; // Return values of getTextBounds
|
||||
uint16_t w, h; // Return values of getTextBounds
|
||||
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
getdisplay().setCursor(x-w/2, y+h/2);
|
||||
epd->getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
epd->setCursor(x-w/2, y+h/2);
|
||||
if(i % 30 == 0){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().print(ii);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->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);
|
||||
epd->fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
float sinx=sin(i/180.0*pi);
|
||||
float cosx=cos(i/180.0*pi);
|
||||
|
||||
@@ -126,10 +129,10 @@ public:
|
||||
float xx2 = +dx;
|
||||
float yy1 = -(rInstrument-10);
|
||||
float yy2 = -(rInstrument+10);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
epd->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);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
|
||||
epd->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);
|
||||
}
|
||||
@@ -163,7 +166,7 @@ public:
|
||||
float xx2 = startwidth;
|
||||
float yy1 = -startwidth;
|
||||
float yy2 = -(rInstrument * 0.6);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
epd->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);
|
||||
// Inverted pointer
|
||||
@@ -173,36 +176,36 @@ public:
|
||||
float ix2 = -endwidth;
|
||||
float iy1 = -(rInstrument * 0.6);
|
||||
float iy2 = -endwidth;
|
||||
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
|
||||
epd->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);
|
||||
|
||||
// Draw counterweight
|
||||
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
|
||||
epd->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
|
||||
epd->fillCircle(200, 140, startwidth + 22, commonData->bgcolor);
|
||||
epd->fillCircle(200, 140, startwidth + 20, commonData->fgcolor); // Boat circle
|
||||
epd->fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData->bgcolor); // Delete half top of boat circle
|
||||
epd->fillRect(150, 150, 100, 4, commonData->fgcolor); // Water line
|
||||
|
||||
// Print label
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(100, 70);
|
||||
getdisplay().print("Keel Position"); // Label
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(100, 70);
|
||||
epd->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().setCursor(175, 110);
|
||||
getdisplay().print(unit1); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(175, 110);
|
||||
epd->print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
// Print Unit of keel position
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(145, 110);
|
||||
getdisplay().print("No sensor data"); // Info missing sensor
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(145, 110);
|
||||
epd->print("No sensor data"); // Info missing sensor
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
|
||||
@@ -1,508 +0,0 @@
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "NetworkClient.h" // Network connection
|
||||
#include "ImageDecoder.h" // Image decoder for navigation map
|
||||
|
||||
#include "Logo_OBP_400x300_sw.h"
|
||||
|
||||
// Defines for reading of navigation map
|
||||
#define JSON_BUFFER 30000 // Max buffer size for JSON content (30 kB picture + values)
|
||||
NetworkClient net(JSON_BUFFER); // Define network client
|
||||
ImageDecoder decoder; // Define image decoder
|
||||
|
||||
class PageNavigation : public Page
|
||||
{
|
||||
// Values for buttons
|
||||
bool firstRun = true; // Detect the first page run
|
||||
int zoom = 15; // Default zoom level
|
||||
bool showValues = false; // Show values HDT, SOG, DBT in navigation map
|
||||
|
||||
private:
|
||||
uint8_t* imageBackupData = nullptr;
|
||||
int imageBackupWidth = 0;
|
||||
int imageBackupHeight = 0;
|
||||
size_t imageBackupSize = 0;
|
||||
bool hasImageBackup = false;
|
||||
|
||||
public:
|
||||
PageNavigation(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageNavigation");
|
||||
imageBackupData = (uint8_t*)heap_caps_malloc((GxEPD_WIDTH * GxEPD_HEIGHT), MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
// Set botton labels
|
||||
virtual void setupKeys(){
|
||||
Page::setupKeys();
|
||||
commonData->keydata[0].label = "ZOOM -";
|
||||
commonData->keydata[1].label = "ZOOM +";
|
||||
commonData->keydata[4].label = "VALUES";
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
// Code for zoom -
|
||||
if(key == 1){
|
||||
zoom --; // Zoom -
|
||||
if(zoom <7){
|
||||
zoom = 7;
|
||||
}
|
||||
return 0; // Commit the key
|
||||
}
|
||||
// Code for zoom -
|
||||
if(key == 2){
|
||||
zoom ++; // Zoom +
|
||||
if(zoom >17){
|
||||
zoom = 17;
|
||||
}
|
||||
return 0; // Commit the key
|
||||
}
|
||||
if(key == 5){
|
||||
showValues = !showValues; // Toggle show values
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
// 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);
|
||||
String mapsource = config->getString(config->mapsource);
|
||||
String ipAddress = config->getString(config->ipAddress);
|
||||
int localPort = config->getInt(config->localPort);
|
||||
String mapType = config->getString(config->maptype);
|
||||
int zoomLevel = config->getInt(config->zoomlevel);
|
||||
bool grid = config->getBool(config->grid);
|
||||
String orientation = config->getString(config->orientation);
|
||||
int refreshDistance = config->getInt(config->refreshDistance);
|
||||
bool showValuesMap = config->getBool(config->showvalues);
|
||||
bool ownHeading = config->getBool(config->ownheading);
|
||||
|
||||
if(firstRun == true){
|
||||
zoom = zoomLevel; // Over write zoom level with setup value
|
||||
showValues = showValuesMap; // Over write showValues with setup value
|
||||
firstRun = false; // Restet variable
|
||||
}
|
||||
|
||||
// Local variables
|
||||
String server = "norbert-walter.dnshome.de";
|
||||
int port = 80;
|
||||
int mType = 1;
|
||||
int dType = 1;
|
||||
int mapRot = 0;
|
||||
int symbolRot = 0;
|
||||
int mapGrid = 0;
|
||||
|
||||
|
||||
// Old values for hold function
|
||||
static double value1old = 0;
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
static double value2old = 0;
|
||||
static String svalue2old = "";
|
||||
static String unit2old = "";
|
||||
static double value3old = 0; // Deg
|
||||
static String svalue3old = "";
|
||||
static String unit3old = "";
|
||||
static double value4old = 0;
|
||||
static String svalue4old = "";
|
||||
static String unit4old = "";
|
||||
static double value5old = 0;
|
||||
static String svalue5old = "";
|
||||
static String unit5old = "";
|
||||
static double value6old = 0;
|
||||
static String svalue6old = "";
|
||||
static String unit6old = "";
|
||||
|
||||
static double latitude = 0;
|
||||
static double latitudeold = 0;
|
||||
static double longitude = 0;
|
||||
static double longitudeold = 0;
|
||||
static double trueHeading = 0;
|
||||
static double magneticHeading = 0;
|
||||
static double speedOverGround = 0;
|
||||
static double depthBelowTransducer = 0;
|
||||
static int lostCounter = 0; // Counter for connection lost to the map server (increment by each page refresh)
|
||||
int imgWidth = 0;
|
||||
int imgHeight = 0;
|
||||
|
||||
// Get boat values #1 Latitude
|
||||
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
|
||||
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 #2 Longitude
|
||||
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
|
||||
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
|
||||
|
||||
// Get boat values #3 HDT
|
||||
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
|
||||
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
|
||||
|
||||
// Get boat values #4 HDM
|
||||
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
|
||||
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
|
||||
|
||||
// Get boat values #5 SOG
|
||||
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
|
||||
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
|
||||
|
||||
// Get boat values #6 DBT
|
||||
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
|
||||
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
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageNavigation, %s: %f, %s: %f, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4, name5.c_str(), value5, name6.c_str(), value6);
|
||||
|
||||
// Set variables
|
||||
//***********************************************************
|
||||
|
||||
// Latitude
|
||||
if(valid1){
|
||||
latitude = value1;
|
||||
latitudeold = value1;
|
||||
value3old = value1;
|
||||
}
|
||||
else{
|
||||
latitude = value1old;
|
||||
}
|
||||
// Longitude
|
||||
if(valid2){
|
||||
longitude = value2;
|
||||
longitudeold = value2;
|
||||
value2old = value2;
|
||||
}
|
||||
else{
|
||||
longitude = value2old;
|
||||
}
|
||||
// HDT value (True Heading, GPS)
|
||||
if(valid3){
|
||||
trueHeading = (value3 * 360) / (2 * PI);
|
||||
value3old = trueHeading;
|
||||
}
|
||||
else{
|
||||
trueHeading = value3old;
|
||||
}
|
||||
// HDM value (Magnetic Heading)
|
||||
if(valid4){
|
||||
magneticHeading = (value4 * 360) / (2 * PI);
|
||||
value4old = magneticHeading;
|
||||
}
|
||||
else{
|
||||
speedOverGround = value4old;
|
||||
}
|
||||
// SOG value (Speed Over Ground)
|
||||
if(valid5){
|
||||
speedOverGround = value5;
|
||||
value5old = value5;
|
||||
}
|
||||
else{
|
||||
speedOverGround = value5old;
|
||||
}
|
||||
// DBT value (Depth Below Transducer)
|
||||
if(valid6){
|
||||
depthBelowTransducer = value6;
|
||||
value6old = value6;
|
||||
}
|
||||
else{
|
||||
depthBelowTransducer = value6old;
|
||||
}
|
||||
|
||||
// Prepare config values for URL
|
||||
//***********************************************************
|
||||
|
||||
// Server settings
|
||||
if(mapsource == "OBP Service"){
|
||||
server = "norbert-walter.dnshome.de";
|
||||
port = 80;
|
||||
}
|
||||
else if(mapsource == "Local Service"){
|
||||
server = String(ipAddress);
|
||||
port = localPort;
|
||||
}
|
||||
else{
|
||||
server = "norbert-walter.dnshome.de";
|
||||
port = 80;
|
||||
}
|
||||
|
||||
// Type of navigation map
|
||||
if(mapType == "Open Street Map"){
|
||||
mType = 1; // Map type
|
||||
dType = 1; // Dithering type
|
||||
}
|
||||
else if(mapType == "Google Street"){
|
||||
mType = 3;
|
||||
dType = 2;
|
||||
}
|
||||
else if(mapType == "Open Topo Map"){
|
||||
mType = 5;
|
||||
dType = 2;
|
||||
}
|
||||
else if(mapType == "Stadimaps Toner"){
|
||||
mType = 7;
|
||||
dType = 1;
|
||||
}
|
||||
else if(mapType == "Free Nautical Chart"){
|
||||
mType = 9;
|
||||
dType = 1;
|
||||
}
|
||||
else{
|
||||
mType = 1;
|
||||
dType = 1;
|
||||
}
|
||||
|
||||
// Map grid on/off
|
||||
if(grid == true){
|
||||
mapGrid = 1;
|
||||
}
|
||||
else{
|
||||
mapGrid = 0;
|
||||
}
|
||||
|
||||
// Map orientation
|
||||
if(orientation == "North Direction"){
|
||||
mapRot = 0;
|
||||
// If true heading available then use HDT oterwise HDM
|
||||
if(valid3 == true){
|
||||
symbolRot = trueHeading;
|
||||
}
|
||||
else{
|
||||
symbolRot = magneticHeading;
|
||||
}
|
||||
}
|
||||
else if(orientation == "Travel Direction"){
|
||||
// If true heading available then use HDT oterwise HDM
|
||||
if(valid3 == true){
|
||||
mapRot = trueHeading;
|
||||
symbolRot = trueHeading;
|
||||
}
|
||||
else{
|
||||
mapRot = magneticHeading;
|
||||
symbolRot = magneticHeading;
|
||||
}
|
||||
}
|
||||
else{
|
||||
mapRot = 0;
|
||||
// If true heading available then use HDT oterwise HDM
|
||||
if(valid3 == true){
|
||||
symbolRot = trueHeading;
|
||||
}
|
||||
else{
|
||||
symbolRot = magneticHeading;
|
||||
}
|
||||
}
|
||||
|
||||
// Load navigation map
|
||||
//***********************************************************
|
||||
|
||||
// URL to OBP Maps Converter
|
||||
// For more details see: https://github.com/norbert-walter/maps-converter
|
||||
String url = String("http://") + server + ":" + port + // OBP Server
|
||||
String("/get_image_json?") + // Service: Output B&W picture as JSON (Base64 + gzip)
|
||||
"zoom=" + zoom + // Default zoom level: 15
|
||||
"&lat=" + String(latitude, 6) + // Latitude
|
||||
"&lon=" + String(longitude, 6) + // Longitude
|
||||
"&mrot=" + mapRot + // Rotation angle navigation map in degree
|
||||
"&mtype=" + mType + // Default Map: Open Street Map
|
||||
"&dtype=" + dType + // Dithering type: Atkinson dithering
|
||||
"&width=400" + // With navigation map
|
||||
"&height=250" + // Height navigation map
|
||||
"&cutout=0" + // No picture cutouts
|
||||
"&tab=0" + // No tab size
|
||||
"&border=2" + // Border line size: 2 pixel
|
||||
"&symbol=2" + // Symbol: Triangle
|
||||
"&srot=" + symbolRot + // Symbol rotation angle
|
||||
"&ssize=15" + // Symbole size: 15 pixel
|
||||
"&grid=" + mapGrid // Show grid: On
|
||||
;
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// ############### Draw Navigation Map ################
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
// If a network connection to URL then load the navigation map
|
||||
if (net.fetchAndDecompressJson(url)) {
|
||||
|
||||
auto& json = net.json(); // Extract JSON content
|
||||
int numPix = json["number_pixels"] | 0; // Read number of pixels
|
||||
imgWidth = json["width"] | 0; // Read width of image
|
||||
imgHeight = json["height"] | 0; // Read height og image
|
||||
|
||||
const char* b64src = json["picture_base64"].as<const char*>(); // Read picture as Base64 content
|
||||
size_t b64len = strlen(b64src); // Calculate length of Base64 content
|
||||
// Copy Base64 content in PSRAM
|
||||
char* b64 = (char*) heap_caps_malloc(b64len + 1, MALLOC_CAP_SPIRAM); // Allcate PSRAM for Base64 content
|
||||
if (!b64) {
|
||||
LOG_DEBUG(GwLog::ERROR,"Error PageNavigation: PSRAM alloc base64 failed");
|
||||
return PAGE_UPDATE;
|
||||
}
|
||||
memcpy(b64, b64src, b64len + 1); // Copy Base64 content in PSRAM
|
||||
|
||||
// Set image buffer in PSRAM
|
||||
//size_t imgSize = getdisplay().width() * getdisplay().height();
|
||||
size_t imgSize = numPix; // Calculate image size
|
||||
uint8_t* imageData = (uint8_t*) heap_caps_malloc(imgSize, MALLOC_CAP_SPIRAM); // Allocate PSRAM for image
|
||||
if (!imageData) {
|
||||
LOG_DEBUG(GwLog::ERROR,"Error PageNavigation: PPSRAM alloc image buffer failed");
|
||||
free(b64);
|
||||
return PAGE_UPDATE;
|
||||
}
|
||||
|
||||
// Decode Base64 content to image
|
||||
size_t decodedSize = 0;
|
||||
decoder.decodeBase64(b64, imageData, imgSize, decodedSize);
|
||||
|
||||
// Copy actual navigation man to ackup map
|
||||
imageBackupWidth = imgWidth;
|
||||
imageBackupHeight = imgHeight;
|
||||
imageBackupSize = imgSize;
|
||||
if (decodedSize > 0) {
|
||||
memcpy(imageBackupData, imageData, decodedSize);
|
||||
imageBackupSize = decodedSize;
|
||||
}
|
||||
hasImageBackup = true;
|
||||
lostCounter = 0;
|
||||
|
||||
// Show image (navigation map)
|
||||
getdisplay().drawBitmap(0, 25, imageData, imgWidth, imgHeight, commonData->fgcolor);
|
||||
|
||||
// Clean PSRAM
|
||||
free(b64);
|
||||
free(imageData);
|
||||
}
|
||||
// If no network connection then use backup navigation map
|
||||
else{
|
||||
// Show backup image (backup navigation map)
|
||||
if (hasImageBackup) {
|
||||
getdisplay().drawBitmap(0, 25, imageBackupData, imageBackupWidth, imageBackupHeight, commonData->fgcolor);
|
||||
}
|
||||
|
||||
// Show info: Connection lost when 5 page refreshes has a connection lost to the map server
|
||||
// Short connection losts are uncritical
|
||||
if(lostCounter >= 5){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().fillRect(200, 250 , 200, 25, commonData->fgcolor); // Black rect
|
||||
getdisplay().fillRect(202, 252 , 196, 21, commonData->bgcolor); // White rect
|
||||
getdisplay().setCursor(210, 270);
|
||||
getdisplay().print("Map server lost");
|
||||
}
|
||||
|
||||
lostCounter++; // Increment lost counter
|
||||
}
|
||||
|
||||
|
||||
// ############### Draw Values ################
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
|
||||
// Show zoom level
|
||||
getdisplay().fillRect(355, 25 , 45, 25, commonData->fgcolor); // Black rect
|
||||
getdisplay().fillRect(357, 27 , 41, 21, commonData->bgcolor); // White rect
|
||||
getdisplay().setCursor(364, 45);
|
||||
getdisplay().print(zoom);
|
||||
// If true heading available then use HDT oterwise HDM
|
||||
if(showValues == true){
|
||||
// Frame
|
||||
getdisplay().fillRect(0, 25 , 130, 65, commonData->fgcolor); // Black rect
|
||||
getdisplay().fillRect(2, 27 , 126, 61, commonData->bgcolor); // White rect
|
||||
if(valid3 == true){
|
||||
// HDT
|
||||
getdisplay().setCursor(10, 45);
|
||||
getdisplay().print(name3);
|
||||
getdisplay().setCursor(70, 45);
|
||||
getdisplay().print(svalue3);
|
||||
}
|
||||
else{
|
||||
// HDM
|
||||
getdisplay().setCursor(10, 45);
|
||||
getdisplay().print(name4);
|
||||
getdisplay().setCursor(70, 45);
|
||||
getdisplay().print(svalue4);
|
||||
}
|
||||
// SOG
|
||||
getdisplay().setCursor(10, 65);
|
||||
getdisplay().print(name5);
|
||||
getdisplay().setCursor(70, 65);
|
||||
getdisplay().print(svalue5);
|
||||
// DBT
|
||||
getdisplay().setCursor(10, 85);
|
||||
getdisplay().print(name6);
|
||||
getdisplay().setCursor(70, 85);
|
||||
getdisplay().print(svalue6);
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageNavigation(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 registerPageNavigation(
|
||||
"Navigation", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"LAT","LON","HDT","HDM","SOG","DBT"}, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -1,228 +1,37 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "OBPDataOperations.h"
|
||||
#include "OBPcharts.h"
|
||||
|
||||
class PageOneValue : public Page {
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
#include "BoatDataCalibration.h"
|
||||
#endif
|
||||
|
||||
class PageOneValue : public Page
|
||||
{
|
||||
private:
|
||||
GwLog* logger;
|
||||
|
||||
enum PageMode {
|
||||
VALUE,
|
||||
BOTH,
|
||||
CHART
|
||||
};
|
||||
enum DisplayMode {
|
||||
FULL,
|
||||
HALF
|
||||
};
|
||||
|
||||
static constexpr char HORIZONTAL = 'H';
|
||||
static constexpr char VERTICAL = 'V';
|
||||
static constexpr int8_t FULL_SIZE = 0;
|
||||
static constexpr int8_t HALF_SIZE_TOP = 1;
|
||||
static constexpr int8_t HALF_SIZE_BOTTOM = 2;
|
||||
|
||||
static constexpr bool PRNT_NAME = true;
|
||||
static constexpr bool NO_PRNT_NAME = false;
|
||||
static constexpr bool PRNT_VALUE = true;
|
||||
static constexpr bool NO_PRNT_VALUE = false;
|
||||
|
||||
int width; // Screen width
|
||||
int height; // Screen height
|
||||
|
||||
bool keylock = false; // Keylock
|
||||
PageMode pageMode = VALUE; // Page display mode
|
||||
int8_t dataIntv = 1; // Update interval for wind history chart:
|
||||
// (1)|(2)|(3)|(4)|(8) x 240 seconds for 4, 8, 12, 16, 32 min. history chart
|
||||
|
||||
// String lengthformat;
|
||||
bool useSimuData;
|
||||
bool holdValues;
|
||||
String flashLED;
|
||||
String backlightMode;
|
||||
String tempFormat;
|
||||
|
||||
// Old values for hold function
|
||||
String sValue1Old = "";
|
||||
String unit1Old = "";
|
||||
|
||||
// Data buffer pointer (owned by HstryBuffers)
|
||||
RingBuffer<uint16_t>* dataHstryBuf = nullptr;
|
||||
std::unique_ptr<Chart> dataChart; // Chart object
|
||||
|
||||
// display data value in display <mode> [FULL|HALF]
|
||||
void showData(GwApi::BoatValue* bValue1, DisplayMode mode)
|
||||
{
|
||||
int nameXoff, nameYoff, unitXoff, unitYoff, value1Xoff, value1Yoff;
|
||||
const GFXfont *nameFnt, *unitFnt, *valueFnt1, *valueFnt2, *valueFnt3;
|
||||
|
||||
if (mode == FULL) { // full size data display
|
||||
nameXoff = 0;
|
||||
nameYoff = 0;
|
||||
nameFnt = &Ubuntu_Bold32pt8b;
|
||||
unitXoff = 0;
|
||||
unitYoff = 0;
|
||||
unitFnt = &Ubuntu_Bold20pt8b;
|
||||
value1Xoff = 0;
|
||||
value1Yoff = 0;
|
||||
valueFnt1 = &Ubuntu_Bold20pt8b;
|
||||
valueFnt2 = &Ubuntu_Bold32pt8b;
|
||||
valueFnt3 = &DSEG7Classic_BoldItalic60pt7b;
|
||||
} else { // half size data and chart display
|
||||
nameXoff = -10;
|
||||
nameYoff = -34;
|
||||
nameFnt = &Ubuntu_Bold20pt8b;
|
||||
unitXoff = -295;
|
||||
unitYoff = -119;
|
||||
unitFnt = &Ubuntu_Bold12pt8b;
|
||||
valueFnt1 = &Ubuntu_Bold12pt8b;
|
||||
value1Xoff = 153;
|
||||
value1Yoff = -119;
|
||||
valueFnt2 = &Ubuntu_Bold20pt8b;
|
||||
valueFnt3 = &DSEG7Classic_BoldItalic42pt7b;
|
||||
}
|
||||
|
||||
String name1 = xdrDelete(bValue1->getName()); // 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
|
||||
|
||||
// Show name
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
getdisplay().setFont(nameFnt);
|
||||
getdisplay().setCursor(20 + nameXoff, 100 + nameYoff);
|
||||
getdisplay().print(name1); // name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(unitFnt);
|
||||
getdisplay().setCursor(305 + unitXoff, 240 + unitYoff);
|
||||
|
||||
if (holdValues) {
|
||||
getdisplay().print(unit1Old); // name
|
||||
} else {
|
||||
getdisplay().print(unit1); // name
|
||||
}
|
||||
|
||||
// Switch font depending on value format and adjust position
|
||||
if (bValue1->getFormat() == "formatLatitude" || bValue1->getFormat() == "formatLongitude") {
|
||||
getdisplay().setFont(valueFnt1);
|
||||
getdisplay().setCursor(20 + value1Xoff, 180 + value1Yoff);
|
||||
} else if (bValue1->getFormat() == "formatTime" || bValue1->getFormat() == "formatDate") {
|
||||
getdisplay().setFont(valueFnt2);
|
||||
getdisplay().setCursor(20 + value1Xoff, 200 + value1Yoff);
|
||||
} else {
|
||||
getdisplay().setFont(valueFnt3);
|
||||
getdisplay().setCursor(20 + value1Xoff, 240 + value1Yoff);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if (!holdValues || useSimuData) {
|
||||
getdisplay().print(sValue1); // Real value as formated string
|
||||
} else {
|
||||
getdisplay().print(sValue1Old); // Old value as formated string
|
||||
}
|
||||
|
||||
if (valid1 == true) {
|
||||
sValue1Old = sValue1; // Save the old value
|
||||
unit1Old = unit1; // Save the old unit
|
||||
}
|
||||
}
|
||||
String lengthformat;
|
||||
|
||||
public:
|
||||
PageOneValue(CommonData& common)
|
||||
PageOneValue(CommonData &common) : Page(common)
|
||||
{
|
||||
commonData = &common;
|
||||
logger = commonData->logger;
|
||||
LOG_DEBUG(GwLog::LOG, "Instantiate PageOneValue");
|
||||
|
||||
width = getdisplay().width(); // Screen width
|
||||
height = getdisplay().height(); // Screen height
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageOneValue");
|
||||
|
||||
// Get config data
|
||||
// lengthformat = commonData->config->getString(commonData->config->lengthFormat);
|
||||
useSimuData = commonData->config->getBool(commonData->config->useSimuData);
|
||||
holdValues = commonData->config->getBool(commonData->config->holdvalues);
|
||||
flashLED = commonData->config->getString(commonData->config->flashLED);
|
||||
backlightMode = commonData->config->getString(commonData->config->backlight);
|
||||
tempFormat = commonData->config->getString(commonData->config->tempFormat); // [K|°C|°F]
|
||||
lengthformat = config->getString(config->lengthFormat);
|
||||
}
|
||||
|
||||
virtual void setupKeys()
|
||||
{
|
||||
Page::setupKeys();
|
||||
|
||||
#if defined BOARD_OBP60S3
|
||||
constexpr int ZOOM_KEY = 4;
|
||||
#elif defined BOARD_OBP40S3
|
||||
constexpr int ZOOM_KEY = 1;
|
||||
#endif
|
||||
|
||||
if (dataHstryBuf) { // show "Mode" key only if chart supported boat data type is available
|
||||
commonData->keydata[0].label = "MODE";
|
||||
commonData->keydata[ZOOM_KEY].label = "ZOOM";
|
||||
} else {
|
||||
commonData->keydata[0].label = "";
|
||||
commonData->keydata[ZOOM_KEY].label = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Key functions
|
||||
virtual int handleKey(int key)
|
||||
{
|
||||
if (dataHstryBuf) { // if boat data type supports charts
|
||||
|
||||
// Set page mode: value | value/half chart | full chart
|
||||
if (key == 1) {
|
||||
switch (pageMode) {
|
||||
case VALUE:
|
||||
pageMode = BOTH;
|
||||
break;
|
||||
case BOTH:
|
||||
pageMode = CHART;
|
||||
break;
|
||||
case CHART:
|
||||
pageMode = VALUE;
|
||||
break;
|
||||
}
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Set time frame to show for history chart
|
||||
#if defined BOARD_OBP60S3
|
||||
if (key == 5) {
|
||||
#elif defined BOARD_OBP40S3
|
||||
if (key == 2) {
|
||||
#endif
|
||||
if (dataIntv == 1) {
|
||||
dataIntv = 2;
|
||||
} else if (dataIntv == 2) {
|
||||
dataIntv = 3;
|
||||
} else if (dataIntv == 3) {
|
||||
dataIntv = 4;
|
||||
} else if (dataIntv == 4) {
|
||||
dataIntv = 8;
|
||||
} else {
|
||||
dataIntv = 1;
|
||||
}
|
||||
return 0; // Commit the key
|
||||
}
|
||||
}
|
||||
|
||||
// Keylock function
|
||||
if (key == 11) { // Code for keylock
|
||||
int handleKey(int key) {
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
virtual void displayNew(PageData& pageData)
|
||||
{
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
@@ -230,71 +39,84 @@ public:
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
// buffer initialization will fail, if page is default page, because <displayNew> is not executed at system start for default page
|
||||
if (!dataChart) { // Create chart objects if they don't exist
|
||||
};
|
||||
|
||||
GwApi::BoatValue* bValue1 = pageData.values[0]; // Page boat data element
|
||||
String bValName1 = bValue1->getName(); // Value name
|
||||
String bValFormat = bValue1->getFormat(); // Value format
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
dataHstryBuf = pageData.hstryBuffers->getBuffer(bValName1);
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
|
||||
if (dataHstryBuf) {
|
||||
dataChart.reset(new Chart(*dataHstryBuf, Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: Created chart objects for %s", bValName1);
|
||||
} else {
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: No chart objects available for %s", bValName1);
|
||||
}
|
||||
}
|
||||
|
||||
// Get boat values
|
||||
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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
String svalue1 = commonData->fmt->formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit1 = commonData->fmt->formatValue(bvalue1, *commonData).unit; // Unit of value
|
||||
|
||||
setupKeys(); // adjust <mode> key depending on chart supported boat data type
|
||||
}
|
||||
|
||||
int displayPage(PageData& pageData)
|
||||
{
|
||||
LOG_DEBUG(GwLog::LOG, "Display PageOneValue");
|
||||
|
||||
// Get boat value for page
|
||||
GwApi::BoatValue* bValue1 = pageData.values[0]; // Page boat data element
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if (String(flashLED) == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
if (bValue1 == NULL)
|
||||
return PAGE_OK; // no data, no page to display
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: printing %s, %.3f", bValue1->getName().c_str(), bValue1->value);
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageOneValue, %s: %f", name1.c_str(), value1);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
getdisplay().setPartialWindow(0, 0, width, height); // Set partial update
|
||||
/// Set display in partial refresh mode
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
if (pageMode == VALUE || dataHstryBuf == nullptr) {
|
||||
// show only data value; ignore other pageMode options if no chart supported boat data history buffer is available
|
||||
showData(bValue1, FULL);
|
||||
// Show name
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold32pt8b);
|
||||
epd->setCursor(20, 100);
|
||||
epd->print(name1); // Page name
|
||||
|
||||
} else if (pageMode == CHART) { // show only data chart
|
||||
if (dataChart) {
|
||||
dataChart->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue1);
|
||||
}
|
||||
// Show unit
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(270, 100);
|
||||
if(holdvalues == false){
|
||||
epd->print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
epd->print(unit1old);
|
||||
}
|
||||
|
||||
} else if (pageMode == BOTH) { // show data value and chart
|
||||
showData(bValue1, HALF);
|
||||
if (dataChart) {
|
||||
dataChart->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, NO_PRNT_NAME, NO_PRNT_VALUE, *bValue1);
|
||||
}
|
||||
// Switch font if format for any values
|
||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
||||
epd->setFont(&Ubuntu_Bold20pt8b);
|
||||
epd->setCursor(20, 180);
|
||||
}
|
||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
||||
epd->setFont(&Ubuntu_Bold32pt8b);
|
||||
epd->setCursor(20, 200);
|
||||
}
|
||||
else{
|
||||
epd->setFont(&DSEG7Classic_BoldItalic60pt7b);
|
||||
epd->setCursor(20, 240);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
epd->print(svalue1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
epd->print(svalue1old); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
unit1old = unit1; // Save the old unit
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page* createPage(CommonData& common)
|
||||
{
|
||||
static Page* createPage(CommonData &common){
|
||||
return new PageOneValue(common);
|
||||
}
|
||||
|
||||
@@ -306,10 +128,10 @@ static Page* createPage(CommonData& common)
|
||||
* this will be number of BoatValue pointers in pageData.values
|
||||
*/
|
||||
PageDescription registerPageOneValue(
|
||||
"OneValue", // Page name
|
||||
createPage, // Action
|
||||
1, // Number of bus values depends on selection in Web configuration
|
||||
true // Show display header on/off
|
||||
"OneValue", // Page name
|
||||
createPage, // Action
|
||||
1, // Number of bus values depends on selection in Web configuration
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -5,14 +6,30 @@
|
||||
|
||||
class PageRollPitch : public Page
|
||||
{
|
||||
private:
|
||||
String lengthformat;
|
||||
int rolllimit;
|
||||
String roffset;
|
||||
double rolloffset;
|
||||
String poffset;
|
||||
double pitchoffset;
|
||||
|
||||
public:
|
||||
PageRollPitch(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageRollPitch");
|
||||
PageRollPitch(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageRollPitch");
|
||||
|
||||
// Get config data
|
||||
String lengthformat = config->getString(config->lengthFormat);
|
||||
rolllimit = config->getInt(config->rollLimit);
|
||||
roffset = config->getString(config->rollOffset);
|
||||
rolloffset = roffset.toFloat() / 360 * (2 * M_PI);
|
||||
poffset = config->getString(config->pitchOffset);
|
||||
pitchoffset = poffset.toFloat() / 360 * (2 * M_PI);
|
||||
}
|
||||
|
||||
// Key functions
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key){
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -21,9 +38,7 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
double value1 = 0;
|
||||
double value2 = 0;
|
||||
@@ -32,19 +47,6 @@ public:
|
||||
String svalue2 = "";
|
||||
String svalue2old = "";
|
||||
|
||||
|
||||
// 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);
|
||||
int rolllimit = config->getInt(config->rollLimit);
|
||||
String roffset = config->getString(config->rollOffset);
|
||||
double rolloffset = roffset.toFloat()/360*(2*M_PI);
|
||||
String poffset = config->getString(config->pitchOffset);
|
||||
double pitchoffset = poffset.toFloat()/360*(2*M_PI);
|
||||
|
||||
// Get boat values for roll
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (xdrRoll)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
@@ -97,71 +99,70 @@ public:
|
||||
}
|
||||
|
||||
// Optical warning by limit violation
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
if (flashLED == "Limit Violation") {
|
||||
// Limits for roll
|
||||
if(value1*360/(2*M_PI) >= -1*rolllimit && value1*360/(2*M_PI) <= rolllimit){
|
||||
if (value1*360/(2*M_PI) >= -1*rolllimit && value1*360/(2*M_PI) <= rolllimit) {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
setBlinkingLED(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageRollPitch, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageRollPitch, %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
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// Show roll limit
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 65);
|
||||
getdisplay().print(rolllimit); // Value
|
||||
//getdisplay().print(svalue1); // Value
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 65);
|
||||
epd->print(rolllimit); // Value
|
||||
//epd->print(svalue1); // Value
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 95);
|
||||
getdisplay().print("Limit"); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(10, 115);
|
||||
getdisplay().print("DEG");
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(10, 95);
|
||||
epd->print("Limit"); // Name
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(10, 115);
|
||||
epd->print("DEG");
|
||||
|
||||
// Horizintal separator left
|
||||
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
|
||||
epd->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().setCursor(10, 220);
|
||||
getdisplay().print(name1); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(10, 190);
|
||||
getdisplay().print("Deg");
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 270);
|
||||
if(holdvalues == false) epd->print(svalue1); // Value
|
||||
else epd->print(svalue1old);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(10, 220);
|
||||
epd->print(name1); // Name
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(10, 190);
|
||||
epd->print("Deg");
|
||||
|
||||
// Horizintal separator right
|
||||
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
|
||||
epd->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().setCursor(335, 220);
|
||||
getdisplay().print(name2); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(335, 190);
|
||||
getdisplay().print("Deg");
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(295, 270);
|
||||
if(holdvalues == false) epd->print(svalue2); // Value
|
||||
else epd->print(svalue2old);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(335, 220);
|
||||
epd->print(name2); // Name
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(335, 190);
|
||||
epd->print("Deg");
|
||||
|
||||
//*******************************************************************************************
|
||||
|
||||
@@ -169,8 +170,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
|
||||
epd->fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
|
||||
epd->fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
|
||||
|
||||
for(int i=0; i<360; i=i+10)
|
||||
{
|
||||
@@ -194,17 +195,17 @@ public:
|
||||
// Print text centered on position x, y
|
||||
int16_t x1, y1; // Return values of getTextBounds
|
||||
uint16_t w, h; // Return values of getTextBounds
|
||||
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
getdisplay().setCursor(x-w/2, y+h/2);
|
||||
epd->getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
epd->setCursor(x-w/2, y+h/2);
|
||||
if(i % 20 == 0){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().print(ii);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->print(ii);
|
||||
}
|
||||
|
||||
// Draw sub scale with dots
|
||||
float x1c = 200 + rInstrument*sin(i/180.0*M_PI);
|
||||
float y1c = 150 - rInstrument*cos(i/180.0*M_PI);
|
||||
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
epd->fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
float sinx=sin(i/180.0*M_PI);
|
||||
float cosx=cos(i/180.0*M_PI);
|
||||
|
||||
@@ -215,10 +216,10 @@ public:
|
||||
float xx2 = +dx;
|
||||
float yy1 = -(rInstrument-10);
|
||||
float yy2 = -(rInstrument+10);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
epd->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);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
|
||||
epd->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);
|
||||
}
|
||||
@@ -239,7 +240,7 @@ public:
|
||||
float xx2 = startwidth;
|
||||
float yy1 = -startwidth;
|
||||
float yy2 = -(rInstrument * 0.7);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
epd->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);
|
||||
// Inverted pointer
|
||||
@@ -249,28 +250,28 @@ public:
|
||||
float ix2 = -endwidth;
|
||||
float iy1 = -(rInstrument * 0.7);
|
||||
float iy2 = -endwidth;
|
||||
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
|
||||
epd->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);
|
||||
|
||||
// Draw counterweight
|
||||
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
|
||||
epd->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
|
||||
epd->fillCircle(200, 150, startwidth + 22, commonData->bgcolor);
|
||||
epd->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)
|
||||
epd->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
|
||||
epd->fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor); // Clear half top side of boat circle (left triangle)
|
||||
epd->fillRect(150, 160, 100, 4, commonData->fgcolor); // Water line
|
||||
|
||||
// Draw roll pointer
|
||||
startwidth = 4; // Start width of pointer
|
||||
@@ -283,7 +284,7 @@ public:
|
||||
float xx2 = startwidth;
|
||||
float yy1 = -startwidth;
|
||||
float yy2 = -(rInstrument - 15);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
epd->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);
|
||||
// Inverted pointer
|
||||
@@ -293,15 +294,15 @@ public:
|
||||
float ix2 = -endwidth;
|
||||
float iy1 = -(rInstrument - 15);
|
||||
float iy2 = -endwidth;
|
||||
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
|
||||
epd->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);
|
||||
}
|
||||
else{
|
||||
// Print sensor info
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(145, 200);
|
||||
getdisplay().print("No sensor data"); // Info missing sensor
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(145, 200);
|
||||
epd->print("No sensor data"); // Info missing sensor
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
#include "BoatDataCalibration.h"
|
||||
#endif
|
||||
|
||||
class PageRudderPosition : public Page
|
||||
{
|
||||
private:
|
||||
String lengthformat;
|
||||
|
||||
public:
|
||||
PageRudderPosition(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Show PageRudderPosition");
|
||||
PageRudderPosition(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageRudderPosition");
|
||||
|
||||
// Get config data
|
||||
String lengthformat = config->getString(config->lengthFormat);
|
||||
}
|
||||
|
||||
// Key functions
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key) {
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -21,68 +32,64 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
static String unit1old = "";
|
||||
double value1 = 0.1;
|
||||
double value1old = 0.1;
|
||||
|
||||
// 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 rudder position
|
||||
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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
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 = commonData->fmt->formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit1 = commonData->fmt->formatValue(bvalue1, *commonData).unit; // Unit of value
|
||||
|
||||
if(valid1 == true){
|
||||
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;
|
||||
if (simulation == true) {
|
||||
value1 = (3 + float(random(0, 50)) / 10.0) / 360 * 2 * M_PI;
|
||||
unit1 = "Deg";
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
value1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageRudderPosition, %s:%f", name1.c_str(), value1);
|
||||
// Log boat values
|
||||
logger->logDebug(GwLog::LOG, "Drawing at PageRudderPosition, %s:%f", name1.c_str(), value1);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
//*******************************************************************************************
|
||||
|
||||
// Draw RudderPosition
|
||||
int rInstrument = 110; // Radius of RudderPosition
|
||||
float pi = 3.141592;
|
||||
const 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
|
||||
epd->fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
|
||||
epd->fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
|
||||
epd->fillRect(0, 30, 400, 122, commonData->bgcolor); // Delete half top circle
|
||||
|
||||
for(int i=90; i<=270; i=i+10)
|
||||
{
|
||||
@@ -90,51 +97,50 @@ public:
|
||||
float x = 200 + (rInstrument-30)*sin(i/180.0*pi); // x-coordinate dots
|
||||
float y = 150 - (rInstrument-30)*cos(i/180.0*pi); // y-coordinate cots
|
||||
const char *ii = " ";
|
||||
switch (i)
|
||||
{
|
||||
case 0: ii=" "; break; // Use a blank for a empty scale value
|
||||
case 30 : ii=" "; break;
|
||||
case 60 : ii=" "; break;
|
||||
case 90 : ii="45"; break;
|
||||
case 120 : ii="30"; break;
|
||||
case 150 : ii="15"; break;
|
||||
case 180 : ii="0"; break;
|
||||
case 210 : ii="15"; break;
|
||||
case 240 : ii="30"; break;
|
||||
case 270 : ii="45"; break;
|
||||
case 300 : ii=" "; break;
|
||||
case 330 : ii=" "; break;
|
||||
default: break;
|
||||
switch (i) {
|
||||
case 0: ii=" "; break; // Use a blank for a empty scale value
|
||||
case 30 : ii=" "; break;
|
||||
case 60 : ii=" "; break;
|
||||
case 90 : ii="45"; break;
|
||||
case 120 : ii="30"; break;
|
||||
case 150 : ii="15"; break;
|
||||
case 180 : ii="0"; break;
|
||||
case 210 : ii="15"; break;
|
||||
case 240 : ii="30"; break;
|
||||
case 270 : ii="45"; break;
|
||||
case 300 : ii=" "; break;
|
||||
case 330 : ii=" "; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Print text centered on position x, y
|
||||
int16_t x1, y1; // Return values of getTextBounds
|
||||
uint16_t w, h; // Return values of getTextBounds
|
||||
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
getdisplay().setCursor(x-w/2, y+h/2);
|
||||
epd->getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
epd->setCursor(x-w/2, y+h/2);
|
||||
if(i % 30 == 0){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().print(ii);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->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);
|
||||
epd->fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
float sinx=sin(i/180.0*pi);
|
||||
float cosx=cos(i/180.0*pi);
|
||||
|
||||
// Draw sub scale with lines (two triangles)
|
||||
if(i % 30 == 0){
|
||||
float dx=2; // Line thickness = 2*dx+1
|
||||
float dx = 2; // Line thickness = 2*dx+1
|
||||
float xx1 = -dx;
|
||||
float xx2 = +dx;
|
||||
float yy1 = -(rInstrument-10);
|
||||
float yy2 = -(rInstrument+10);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
epd->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);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
|
||||
epd->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);
|
||||
}
|
||||
@@ -142,28 +148,28 @@ public:
|
||||
}
|
||||
|
||||
// Print label
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(80, 70);
|
||||
getdisplay().print("Rudder Position"); // Label
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(80, 70);
|
||||
epd->print("Rudder Position"); // Label
|
||||
|
||||
// Print Unit in RudderPosition
|
||||
if(valid1 == true || simulation == true){
|
||||
if(holdvalues == false){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(175, 110);
|
||||
getdisplay().print(unit1); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(175, 110);
|
||||
epd->print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(175, 110);
|
||||
getdisplay().print(unit1old); // Unit
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(175, 110);
|
||||
epd->print(unit1old); // Unit
|
||||
}
|
||||
}
|
||||
else{
|
||||
// Print Unit of keel position
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(145, 110);
|
||||
getdisplay().print("No sensor data"); // Info missing sensor
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(145, 110);
|
||||
epd->print("No sensor data"); // Info missing sensor
|
||||
}
|
||||
|
||||
// Calculate rudder position
|
||||
@@ -186,7 +192,7 @@ public:
|
||||
float xx2 = startwidth;
|
||||
float yy1 = -startwidth;
|
||||
float yy2 = -(rInstrument * 0.5);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
epd->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);
|
||||
// Inverted pointer
|
||||
@@ -196,14 +202,14 @@ public:
|
||||
float ix2 = -endwidth;
|
||||
float iy1 = -(rInstrument * 0.5);
|
||||
float iy2 = -endwidth;
|
||||
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
|
||||
epd->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);
|
||||
}
|
||||
|
||||
// Center circle
|
||||
getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
|
||||
getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
|
||||
epd->fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
|
||||
epd->fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
#include "BoatDataCalibration.h"
|
||||
#endif
|
||||
|
||||
const int SixValues_x1 = 5;
|
||||
const int SixValues_DeltaX = 200;
|
||||
|
||||
@@ -13,13 +18,13 @@ const int HowManyValues = 6;
|
||||
|
||||
class PageSixValues : public Page
|
||||
{
|
||||
public:
|
||||
PageSixValues(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageSixValues");
|
||||
public:
|
||||
PageSixValues(CommonData &common) : Page(common)
|
||||
{
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageSixValues");
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
int handleKey(int key) {
|
||||
// Code for keylock
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -28,129 +33,133 @@ class PageSixValues : public Page
|
||||
return key;
|
||||
}
|
||||
|
||||
int 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
|
||||
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 PAGE_OK; // WTF why this statement?
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
|
||||
// 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
|
||||
#ifdef ENABLE_CALIBRATION
|
||||
calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated
|
||||
#endif
|
||||
DataValue[i] = bvalue->value; // Value as double in SI unit
|
||||
DataValid[i] = bvalue->valid;
|
||||
DataText[i] = commonData->fmt->formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
DataUnits[i] = commonData->fmt->formatValue(bvalue, *commonData).unit;
|
||||
DataFormat[i] = bvalue->getFormat(); // Unit of value
|
||||
}
|
||||
|
||||
if (bvalue == NULL) return PAGE_OK; // WTF why this statement?
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
epd->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
|
||||
epd->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
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(x0, y0+25);
|
||||
epd->print(DataName[ValueIndex]); // Page name
|
||||
|
||||
// Show unit
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(x0, y0+72);
|
||||
if (holdvalues == false) {
|
||||
epd->print(DataUnits[ValueIndex]); // Unit
|
||||
} else {
|
||||
epd->print(OldDataUnits[ValueIndex]);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
if (DataFormat[ValueIndex] == "formatLatitude" || DataFormat[ValueIndex] == "formatLongitude") {
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(x0+10, y0+60);
|
||||
}
|
||||
else if (DataFormat[ValueIndex] == "formatTime" || DataFormat[ValueIndex] == "formatDate") {
|
||||
epd->setFont(&Ubuntu_Bold16pt8b);
|
||||
epd->setCursor(x0+20,y0+55);
|
||||
}
|
||||
// pressure in hPa
|
||||
else if (DataFormat[ValueIndex] == "formatXdr:P:P") {
|
||||
epd->setFont(&DSEG7Classic_BoldItalic26pt7b);
|
||||
epd->setCursor(x0+5, y0+70);
|
||||
}
|
||||
// RPM
|
||||
else if (DataFormat[ValueIndex] == "formatXdr:T:R") {
|
||||
epd->setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
epd->setCursor(x0+25, y0+70);
|
||||
}
|
||||
else {
|
||||
epd->setFont(&DSEG7Classic_BoldItalic26pt7b);
|
||||
if (DataText[ValueIndex][0] == '-' ) {
|
||||
epd->setCursor(x0+25, y0+70);
|
||||
} else {
|
||||
epd->setCursor(x0+65, y0+70);
|
||||
}
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if (holdvalues == false) {
|
||||
epd->print(DataText[ValueIndex]); // Real value as formated string
|
||||
} else{
|
||||
epd->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
|
||||
}
|
||||
} // for j
|
||||
// Vertical line 3 pix
|
||||
epd->fillRect(SixValues_x1+SixValues_DeltaX-8, SixValues_y1+i*SixValues_DeltaY, 3, SixValues_DeltaY, commonData->fgcolor);
|
||||
} // for i
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageSixValues(common);
|
||||
}/**
|
||||
|
||||
@@ -14,20 +14,15 @@
|
||||
class PageSkyView : public Page
|
||||
{
|
||||
private:
|
||||
String flashLED;
|
||||
GwBoatData *bd;
|
||||
|
||||
public:
|
||||
PageSkyView(CommonData &common)
|
||||
PageSkyView(CommonData &common) : Page(common)
|
||||
{
|
||||
commonData = &common;
|
||||
|
||||
// task name access is for example purpose only
|
||||
TaskHandle_t currentTaskHandle = xTaskGetCurrentTaskHandle();
|
||||
const char* taskName = pcTaskGetName(currentTaskHandle);
|
||||
common.logger->logDebug(GwLog::LOG, "Instantiate PageSkyView in task '%s'", taskName);
|
||||
|
||||
flashLED = common.config->getString(common.config->flashLED);
|
||||
logger->logDebug(GwLog::LOG, "Instantiate PageSkyView in task '%s'", taskName);
|
||||
}
|
||||
|
||||
int handleKey(int key) {
|
||||
@@ -57,7 +52,6 @@ public:
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData) {
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
std::vector<GwSatInfo> sats;
|
||||
int nSat = bd->SatInfo->getNumSats();
|
||||
@@ -73,111 +67,109 @@ public:
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
epd->setPartialWindow(0, 0, epd->width(), epd->height()); // Set partial update
|
||||
|
||||
// current position
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
|
||||
|
||||
GwApi::BoatValue *bv_lat = pageData.values[0];
|
||||
String sv_lat = commonData->fmt->formatValue(bv_lat, *commonData).svalue;
|
||||
//epd->setCursor(300, 40);
|
||||
//epd->print(sv_lat);
|
||||
|
||||
GwApi::BoatValue *bv_lon = pageData.values[1];
|
||||
String sv_lon = commonData->fmt->formatValue(bv_lon, *commonData).svalue;
|
||||
//epd->setCursor(300, 60);
|
||||
//epd->print(sv_lon);
|
||||
|
||||
GwApi::BoatValue *bv_hdop = pageData.values[2];
|
||||
String sv_hdop = commonData->fmt->formatValue(bv_hdop, *commonData).svalue;
|
||||
//epd->setCursor(300, 80);
|
||||
//epd->print(sv_hdop);
|
||||
|
||||
// sky view
|
||||
Point c = {130, 148};
|
||||
uint16_t r = 120;
|
||||
uint16_t r = 125;
|
||||
uint16_t r1 = r / 2;
|
||||
|
||||
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, r1, commonData->fgcolor);
|
||||
epd->fillCircle(c.x, c.y, r, commonData->bgcolor);
|
||||
epd->drawCircle(c.x, c.y, r + 1, commonData->fgcolor);
|
||||
epd->drawCircle(c.x, c.y, r + 2, commonData->fgcolor);
|
||||
epd->drawCircle(c.x, c.y, r1, commonData->fgcolor);
|
||||
|
||||
// separation lines
|
||||
getdisplay().drawLine(c.x - r, c.y, c.x + r, c.y, commonData->fgcolor);
|
||||
getdisplay().drawLine(c.x, c.y - r, c.x, c.y + r, commonData->fgcolor);
|
||||
epd->drawLine(c.x - r, c.y, c.x + r, c.y, commonData->fgcolor);
|
||||
epd->drawLine(c.x, c.y - r, c.x, c.y + r, commonData->fgcolor);
|
||||
Point p = {c.x, c.y - r};
|
||||
Point p1, p2;
|
||||
p1 = rotatePoint(c, p, 45);
|
||||
p2 = rotatePoint(c, p, 45 + 180);
|
||||
getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData->fgcolor);
|
||||
epd->drawLine(p1.x, p1.y, p2.x, p2.y, commonData->fgcolor);
|
||||
p1 = rotatePoint(c, p, -45);
|
||||
p2 = rotatePoint(c, p, -45 + 180);
|
||||
getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData->fgcolor);
|
||||
epd->drawLine(p1.x, p1.y, p2.x, p2.y, commonData->fgcolor);
|
||||
|
||||
// directions
|
||||
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
|
||||
getdisplay().getTextBounds("N", 0, 150, &x1, &y1, &w, &h);
|
||||
getdisplay().setCursor(c.x - w / 2, c.y - r + h + 3);
|
||||
getdisplay().print("N");
|
||||
epd->getTextBounds("N", 0, 150, &x1, &y1, &w, &h);
|
||||
epd->setCursor(c.x - w / 2, c.y - r + h + 2);
|
||||
epd->print("N");
|
||||
|
||||
getdisplay().getTextBounds("S", 0, 150, &x1, &y1, &w, &h);
|
||||
getdisplay().setCursor(c.x - w / 2, c.y + r - 3);
|
||||
getdisplay().print("S");
|
||||
epd->getTextBounds("S", 0, 150, &x1, &y1, &w, &h);
|
||||
epd->setCursor(c.x - w / 2, c.y + r - 2);
|
||||
epd->print("S");
|
||||
|
||||
getdisplay().getTextBounds("E", 0, 150, &x1, &y1, &w, &h);
|
||||
getdisplay().setCursor(c.x + r - w - 3, c.y + h / 2);
|
||||
getdisplay().print("E");
|
||||
epd->getTextBounds("E", 0, 150, &x1, &y1, &w, &h);
|
||||
epd->setCursor(c.x + r - w - 2, c.y + h / 2);
|
||||
epd->print("E");
|
||||
|
||||
getdisplay().getTextBounds("W", 0, 150, &x1, &y1, &w, &h);
|
||||
getdisplay().setCursor(c.x - r + 3 , c.y + h / 2);
|
||||
getdisplay().print("W");
|
||||
epd->getTextBounds("W", 0, 150, &x1, &y1, &w, &h);
|
||||
epd->setCursor(c.x - r + 2 , c.y + h / 2);
|
||||
epd->print("W");
|
||||
|
||||
// show satellites in "map"
|
||||
getdisplay().setFont(&IBM8x8px);
|
||||
epd->setFont(&Atari6px);
|
||||
for (int i = 0; i < nSat; i++) {
|
||||
float arad = (sats[i].Azimut * M_PI / 180.0) + M_PI;
|
||||
float arad = sats[i].Azimut * M_PI / 180.0;
|
||||
float erad = sats[i].Elevation * M_PI / 180.0;
|
||||
uint16_t x = c.x + sin(arad) * erad * r1;
|
||||
uint16_t y = c.y + cos(arad) * erad * r1;
|
||||
getdisplay().fillRect(x-4, y-4, 8, 8, commonData->fgcolor);
|
||||
getdisplay().setCursor(x-7, y+12);
|
||||
getdisplay().printf("%02d", static_cast<int>(sats[i].PRN));
|
||||
uint16_t x = c.x + sin(arad) * erad * r;
|
||||
uint16_t y = c.y + cos(arad) * erad * r;
|
||||
epd->drawRect(x-4, y-4, 8, 8, commonData->fgcolor);
|
||||
// Add Sat number
|
||||
epd->setCursor(x+5, y);
|
||||
char buffer[3];
|
||||
snprintf(buffer, 3, "%02d", static_cast<int>(sats[i].PRN));
|
||||
epd->print(String(buffer));
|
||||
}
|
||||
|
||||
// Signal / Noise bars
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(325, 34);
|
||||
getdisplay().print("SNR");
|
||||
// getdisplay().drawRect(270, 20, 125, 257, commonData->fgcolor);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(325, 34);
|
||||
epd->print("SNR");
|
||||
epd->drawRect(270, 20, 125, 257, commonData->fgcolor);
|
||||
int maxsat = std::min(nSat, 12);
|
||||
for (int i = 0; i < maxsat; i++) {
|
||||
uint16_t y = 29 + (i + 1) * 20;
|
||||
getdisplay().setCursor(276, y);
|
||||
epd->setCursor(276, y);
|
||||
char buffer[3];
|
||||
snprintf(buffer, 3, "%02d", static_cast<int>(sats[i].PRN));
|
||||
getdisplay().print(String(buffer));
|
||||
getdisplay().drawRect(305, y-12, 85, 14, commonData->fgcolor);
|
||||
getdisplay().setCursor(315, y);
|
||||
epd->print(String(buffer));
|
||||
epd->drawRect(305, y-12, 85, 14, commonData->fgcolor);
|
||||
epd->setCursor(315, y);
|
||||
// TODO SNR as number or as bar via mode key?
|
||||
if (sats[i].SNR <= 100) {
|
||||
// getdisplay().print(sats[i].SNR);
|
||||
getdisplay().fillRect(307, y-10, int(81 * sats[i].SNR / 100.0), 10, commonData->fgcolor);
|
||||
// epd->print(sats[i].SNR);
|
||||
epd->fillRect(307, y-10, int(81 * sats[i].SNR / 100.0), 10, commonData->fgcolor);
|
||||
} else {
|
||||
getdisplay().print("n/a");
|
||||
epd->print("n/a");
|
||||
}
|
||||
}
|
||||
|
||||
// Show SatInfo and HDOP
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
|
||||
getdisplay().setCursor(220, 34);
|
||||
getdisplay().print("Sat:");
|
||||
|
||||
GwApi::BoatValue *bv_satinfo = pageData.values[0]; // SatInfo
|
||||
String sval_satinfo = formatValue(bv_satinfo, *commonData).svalue;
|
||||
getdisplay().setCursor(220, 49);
|
||||
getdisplay().print(sval_satinfo);
|
||||
|
||||
getdisplay().setCursor(220, 254);
|
||||
getdisplay().print("HDOP:");
|
||||
|
||||
GwApi::BoatValue *bv_hdop = pageData.values[1]; // HDOP
|
||||
double hdop = formatValue(bv_hdop, *commonData).value * 4; // 4 is factor for UERE (translation in meter)
|
||||
char sval_hdop[20];
|
||||
dtostrf(hdop, 0, 1, sval_hdop); // Only one prefix
|
||||
strcat(sval_hdop, "m");
|
||||
getdisplay().setCursor(220, 269);
|
||||
getdisplay().print(sval_hdop);
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
@@ -197,7 +189,7 @@ PageDescription registerPageSkyView(
|
||||
"SkyView", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"SatInfo", "HDOP"}, // Bus values we need in the page
|
||||
{"LAT", "LON", "HDOP"}, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user