mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-03-28 18:06:37 +01:00
Compare commits
66 Commits
tracker
...
da975b5175
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da975b5175 | ||
|
|
cd3c99d509 | ||
|
|
86a078690a | ||
|
|
4747336a69 | ||
|
|
84736e6769 | ||
|
|
1557126823 | ||
|
|
9ff5ae36db | ||
|
|
2d4f49659d | ||
|
|
559042da78 | ||
|
|
2b6fc09b7e | ||
|
|
2e836bc750 | ||
|
|
f838194f06 | ||
|
|
784cc15b8f | ||
|
|
69754b85fd | ||
|
|
2deaf07ea4 | ||
|
|
362338a7dd | ||
|
|
41a8e7d078 | ||
|
|
d655674529 | ||
|
|
142f6ca774 | ||
|
|
c6276cdcff | ||
|
|
213812ed14 | ||
|
|
b54acbae42 | ||
|
|
3ce1e31e64 | ||
|
|
69367b91d7 | ||
|
|
6edf847958 | ||
|
|
fe78fb434b | ||
|
|
fc097b09fe | ||
|
|
a392d88445 | ||
|
|
f08a119f40 | ||
|
|
ae2b7047f5 | ||
|
|
eab7d74aef | ||
|
|
0f50b614eb | ||
|
|
1b55439135 | ||
|
|
625f9c087e | ||
|
|
3fa7ca5e99 | ||
|
|
9935cb54a6 | ||
|
|
b31addf852 | ||
|
|
a9007a6b6f | ||
|
|
0972f12b9e | ||
|
|
f8378c3a2b | ||
|
|
e02ca265ae | ||
|
|
16f9f9217d | ||
|
|
f77107616d | ||
|
|
942ca28ab5 | ||
|
|
a90689228d | ||
|
|
489ee7ed09 | ||
|
|
dd5f05922a | ||
|
|
469a81f87d | ||
|
|
81825370c0 | ||
|
|
bcc24ee99d | ||
|
|
470c0e5f4d | ||
|
|
9a792b49db | ||
| 8f851a4b61 | |||
|
|
f46a43d7fd | ||
| 84e99365f7 | |||
|
|
e5950f95fd | ||
|
|
d0076f336d | ||
|
|
d94c4bbbdb | ||
|
|
6ef7681a40 | ||
|
|
16b8a0dacd | ||
|
|
b3e2dea45b | ||
|
|
34a289048f | ||
|
|
df1bd498ae | ||
|
|
de448974d9 | ||
|
|
6b91400cfc | ||
|
|
1abcb158ec |
14
lib/obp60task/ImageDecoder.cpp
Normal file
14
lib/obp60task/ImageDecoder.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
9
lib/obp60task/ImageDecoder.h
Normal file
9
lib/obp60task/ImageDecoder.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class ImageDecoder {
|
||||||
|
public:
|
||||||
|
bool decodeBase64(const String& base64, uint8_t* outBuffer, size_t outSize, size_t& decodedSize);
|
||||||
|
};
|
||||||
181
lib/obp60task/NetworkClient.cpp
Normal file
181
lib/obp60task/NetworkClient.cpp
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
27
lib/obp60task/NetworkClient.h
Normal file
27
lib/obp60task/NetworkClient.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#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,9 @@
|
|||||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <PCF8574.h> // Driver for PCF8574 output modul from Horter
|
|
||||||
#include <Wire.h> // I2C
|
#include <Wire.h> // I2C
|
||||||
#include <RTClib.h> // Driver for DS1388 RTC
|
#include <RTClib.h> // Driver for DS1388 RTC
|
||||||
|
#include <PCF8574.h> // PCF8574 modules from Horter
|
||||||
#include "SunRise.h" // Lib for sunrise and sunset calculation
|
#include "SunRise.h" // Lib for sunrise and sunset calculation
|
||||||
#include "Pagedata.h"
|
#include "Pagedata.h"
|
||||||
#include "OBP60Hardware.h"
|
#include "OBP60Hardware.h"
|
||||||
@@ -24,11 +24,10 @@
|
|||||||
#include "fonts/Ubuntu_Bold20pt8b.h"
|
#include "fonts/Ubuntu_Bold20pt8b.h"
|
||||||
#include "fonts/Ubuntu_Bold32pt8b.h"
|
#include "fonts/Ubuntu_Bold32pt8b.h"
|
||||||
#include "fonts/Atari16px8b.h" // Key label font
|
#include "fonts/Atari16px8b.h" // Key label font
|
||||||
|
#include "fonts/IBM8x8px.h"
|
||||||
|
|
||||||
// E-Ink Display
|
// E-Ink Display
|
||||||
#define GxEPD_WIDTH 400 // Display width
|
// Definition for e-paper width an height refer OBP60Hardware.h
|
||||||
#define GxEPD_HEIGHT 300 // Display height
|
|
||||||
|
|
||||||
#ifdef DISPLAY_GDEW042T2
|
#ifdef DISPLAY_GDEW042T2
|
||||||
// Set display type and SPI pins for display
|
// 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)
|
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)
|
||||||
@@ -89,10 +88,11 @@ void hardwareInit(GwApi *api)
|
|||||||
|
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
// Init PCF8574 digital outputs
|
// Init PCF8574 digital outputs
|
||||||
Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz
|
Wire.setClock(I2C_SPEED_LOW); // Set I2C clock on 10 kHz
|
||||||
if(pcf8574_Out.begin()){ // Initialize PCF8574
|
if(pcf8574_Out.begin()){ // Initialize PCF8574
|
||||||
pcf8574_Out.write8(255); // Clear all outputs
|
pcf8574_Out.write8(255); // Clear all outputs
|
||||||
}
|
}
|
||||||
|
Wire.setClock(I2C_SPEED); // Set I2C clock on 100 kHz
|
||||||
fram = Adafruit_FRAM_I2C();
|
fram = Adafruit_FRAM_I2C();
|
||||||
if (esp_reset_reason() == ESP_RST_POWERON) {
|
if (esp_reset_reason() == ESP_RST_POWERON) {
|
||||||
// help initialize FRAM
|
// help initialize FRAM
|
||||||
@@ -193,6 +193,15 @@ void powerInit(String powermode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPCF8574PortPin(uint pin, uint8_t value){
|
||||||
|
Wire.setClock(I2C_SPEED_LOW); // Set I2C clock on 10 kHz
|
||||||
|
if(pcf8574_Out.begin()){ // Check available and initialize PCF8574
|
||||||
|
pcf8574_Out.write(pin, value); // Toggle pin
|
||||||
|
}
|
||||||
|
Wire.setClock(I2C_SPEED); // Set I2C clock on 100 kHz
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void setPortPin(uint pin, bool value){
|
void setPortPin(uint pin, bool value){
|
||||||
pinMode(pin, OUTPUT);
|
pinMode(pin, OUTPUT);
|
||||||
digitalWrite(pin, value);
|
digitalWrite(pin, value);
|
||||||
@@ -433,7 +442,7 @@ void drawTextRalign(int16_t x, int16_t y, String text) {
|
|||||||
int16_t x1, y1;
|
int16_t x1, y1;
|
||||||
uint16_t w, h;
|
uint16_t w, h;
|
||||||
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
|
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
|
||||||
getdisplay().setCursor(x - w, y);
|
getdisplay().setCursor(x - w - 1, y); // '-1' required since some strings wrap around w/o it
|
||||||
getdisplay().print(text);
|
getdisplay().print(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,4 +913,30 @@ void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUM
|
|||||||
imageBuffer.clear();
|
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
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include <GxEPD2_BW.h> // E-paper lib V2
|
#include <GxEPD2_BW.h> // E-paper lib V2
|
||||||
#include <Adafruit_FRAM_I2C.h> // I2C FRAM
|
#include <Adafruit_FRAM_I2C.h> // I2C FRAM
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#ifdef BOARD_OBP40S3
|
#ifdef BOARD_OBP40S3
|
||||||
#include "esp_vfs_fat.h"
|
#include "esp_vfs_fat.h"
|
||||||
@@ -30,6 +31,9 @@
|
|||||||
#define FRAM_BAROGRAPH_START 0x0400
|
#define FRAM_BAROGRAPH_START 0x0400
|
||||||
#define FRAM_BAROGRAPH_END 0x13FF
|
#define FRAM_BAROGRAPH_END 0x13FF
|
||||||
|
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
#define EARTH_RADIUS 6371000.0
|
||||||
|
|
||||||
extern Adafruit_FRAM_I2C fram;
|
extern Adafruit_FRAM_I2C fram;
|
||||||
extern bool hasFRAM;
|
extern bool hasFRAM;
|
||||||
extern bool hasSDCard;
|
extern bool hasSDCard;
|
||||||
@@ -51,6 +55,7 @@ extern const GFXfont Ubuntu_Bold16pt8b;
|
|||||||
extern const GFXfont Ubuntu_Bold20pt8b;
|
extern const GFXfont Ubuntu_Bold20pt8b;
|
||||||
extern const GFXfont Ubuntu_Bold32pt8b;
|
extern const GFXfont Ubuntu_Bold32pt8b;
|
||||||
extern const GFXfont Atari16px;
|
extern const GFXfont Atari16px;
|
||||||
|
extern const GFXfont IBM8x8px;
|
||||||
|
|
||||||
// Global functions
|
// Global functions
|
||||||
#ifdef DISPLAY_GDEW042T2
|
#ifdef DISPLAY_GDEW042T2
|
||||||
@@ -84,8 +89,8 @@ uint8_t getLastPage();
|
|||||||
void hardwareInit(GwApi *api);
|
void hardwareInit(GwApi *api);
|
||||||
void powerInit(String powermode);
|
void powerInit(String powermode);
|
||||||
|
|
||||||
|
void setPCF8574PortPin(uint pin, uint8_t value);// Set PCF8574 port pin
|
||||||
void setPortPin(uint pin, bool value); // Set port pin for extension port
|
void setPortPin(uint pin, bool value); // Set port pin for extension port
|
||||||
|
|
||||||
void togglePortPin(uint pin); // Toggle extension port pin
|
void togglePortPin(uint pin); // Toggle extension port pin
|
||||||
|
|
||||||
Color colorMapping(const String &colorString); // Color mapping string to CHSV colors
|
Color colorMapping(const String &colorString); // Color mapping string to CHSV colors
|
||||||
|
|||||||
@@ -49,12 +49,22 @@ String formatLongitude(double lon) {
|
|||||||
return String(degree, 0) + "\x90 " + String(minute, 4) + "' " + ((lon > 0) ? "E" : "W");
|
return String(degree, 0) + "\x90 " + String(minute, 4) + "' " + ((lon > 0) ? "E" : "W");
|
||||||
}
|
}
|
||||||
|
|
||||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
// 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){
|
||||||
GwLog *logger = commondata.logger;
|
GwLog *logger = commondata.logger;
|
||||||
FormattedData result;
|
FormattedData result;
|
||||||
static int dayoffset = 0;
|
static int dayoffset = 0;
|
||||||
double rawvalue = 0;
|
double rawvalue = 0;
|
||||||
|
|
||||||
|
result.cvalue = value->value;
|
||||||
|
|
||||||
// Load configuration values
|
// Load configuration values
|
||||||
String stimeZone = commondata.config->getString(commondata.config->timeZone); // [UTC -14.00...+12.00]
|
String stimeZone = commondata.config->getString(commondata.config->timeZone); // [UTC -14.00...+12.00]
|
||||||
double timeZone = stimeZone.toDouble();
|
double timeZone = stimeZone.toDouble();
|
||||||
@@ -64,9 +74,15 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
String windspeedFormat = commondata.config->getString(commondata.config->windspeedFormat); // [m/s|km/h|kn|bft]
|
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 tempFormat = commondata.config->getString(commondata.config->tempFormat); // [K|°C|°F]
|
||||||
String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US]
|
String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US]
|
||||||
bool usesimudata = commondata.config->getBool(commondata.config->useSimuData); // [on|off]
|
|
||||||
String precision = commondata.config->getString(commondata.config->valueprecision); // [1|2]
|
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 boat value not valid
|
||||||
if (! value->valid && !usesimudata){
|
if (! value->valid && !usesimudata){
|
||||||
result.svalue = "---";
|
result.svalue = "---";
|
||||||
@@ -77,9 +93,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
const char* fmt_dec_10;
|
const char* fmt_dec_10;
|
||||||
const char* fmt_dec_100;
|
const char* fmt_dec_100;
|
||||||
if (precision == "1") {
|
if (precision == "1") {
|
||||||
fmt_dec_1 = "%3.1f";
|
//
|
||||||
fmt_dec_10 = "%3.0f";
|
//All values are displayed using a DSEG7* font. In this font, ' ' is a very short space, and '.' takes up no space at all.
|
||||||
fmt_dec_100 = "%3.0f";
|
//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
|
||||||
} else {
|
} else {
|
||||||
fmt_dec_1 = "%3.2f";
|
fmt_dec_1 = "%3.2f";
|
||||||
fmt_dec_10 = "%3.1f";
|
fmt_dec_10 = "%3.1f";
|
||||||
@@ -149,6 +169,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
val = modf(val*3600.0/60.0, &intmin);
|
val = modf(val*3600.0/60.0, &intmin);
|
||||||
modf(val*60.0,&intsec);
|
modf(val*60.0,&intsec);
|
||||||
snprintf(buffer, bsize, "%02.0f:%02.0f:%02.0f", inthr, intmin, intsec);
|
snprintf(buffer, bsize, "%02.0f:%02.0f:%02.0f", inthr, intmin, intsec);
|
||||||
|
result.cvalue = timeInSeconds;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
static long sec;
|
static long sec;
|
||||||
@@ -158,6 +179,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
}
|
}
|
||||||
sec = sec % 60;
|
sec = sec % 60;
|
||||||
snprintf(buffer, bsize, "11:36:%02i", int(sec));
|
snprintf(buffer, bsize, "11:36:%02i", int(sec));
|
||||||
|
result.cvalue = sec;
|
||||||
lasttime = millis();
|
lasttime = millis();
|
||||||
}
|
}
|
||||||
if(timeZone == 0){
|
if(timeZone == 0){
|
||||||
@@ -178,6 +200,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, "%3.0f", rawvalue);
|
snprintf(buffer, bsize, "%3.0f", rawvalue);
|
||||||
}
|
}
|
||||||
result.unit = "";
|
result.unit = "";
|
||||||
|
result.cvalue = rawvalue;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatCourse" || value->getFormat() == "formatWind"){
|
else if (value->getFormat() == "formatCourse" || value->getFormat() == "formatWind"){
|
||||||
@@ -187,14 +210,15 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
rawvalue = value->value;
|
rawvalue = value->value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
course = 2.53 + float(random(0, 10) / 100.0);
|
course = M_PI_2 + float(random(-17, 17) / 100.0); // create random course/wind values with 90° +/- 10°
|
||||||
rawvalue = course;
|
rawvalue = course;
|
||||||
}
|
}
|
||||||
course = course * 57.2958; // Unit conversion form rad to deg
|
course = course * RAD_TO_DEG; // Unit conversion form rad to deg
|
||||||
|
|
||||||
// Format 3 numbers with prefix zero
|
// Format 3 numbers with prefix zero
|
||||||
snprintf(buffer,bsize,"%03.0f",course);
|
snprintf(buffer,bsize,"%03.0f",course);
|
||||||
result.unit = "Deg";
|
result.unit = "Deg";
|
||||||
|
result.cvalue = course;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW")){
|
else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW")){
|
||||||
@@ -204,7 +228,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
rawvalue = value->value;
|
rawvalue = value->value;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
rawvalue = 4.0 + float(random(0, 40));
|
rawvalue = 4.0 + float(random(-30, 40) / 10.0); // create random speed values from [1..8] m/s
|
||||||
speed = rawvalue;
|
speed = rawvalue;
|
||||||
}
|
}
|
||||||
if (String(speedFormat) == "km/h"){
|
if (String(speedFormat) == "km/h"){
|
||||||
@@ -228,6 +252,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
else {
|
else {
|
||||||
snprintf(buffer, bsize, fmt_dec_100, speed);
|
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")){
|
else if (value->getFormat() == "formatKnots" && (value->getName() == "AWS" || value->getName() == "TWS" || value->getName() == "MaxAws" || value->getName() == "MaxTws")){
|
||||||
@@ -237,7 +262,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
rawvalue = value->value;
|
rawvalue = value->value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rawvalue = 4.0 + float(random(0, 40));
|
rawvalue = 4.0 + float(random(0, 40) / 10.0); // create random wind speed values from [4..8] m/s
|
||||||
speed = rawvalue;
|
speed = rawvalue;
|
||||||
}
|
}
|
||||||
if (String(windspeedFormat) == "km/h"){
|
if (String(windspeedFormat) == "km/h"){
|
||||||
@@ -298,16 +323,18 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, "%2.0f", speed);
|
snprintf(buffer, bsize, "%2.0f", speed);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (speed < 10){
|
speed = std::round(speed * 100) / 100; // in rare cases, speed could be 9.9999 kn instead of 10.0 kn
|
||||||
|
if (speed < 10.0){
|
||||||
snprintf(buffer, bsize, fmt_dec_1, speed);
|
snprintf(buffer, bsize, fmt_dec_1, speed);
|
||||||
}
|
}
|
||||||
else if (speed < 100){
|
else if (speed < 100.0){
|
||||||
snprintf(buffer, bsize, fmt_dec_10, speed);
|
snprintf(buffer, bsize, fmt_dec_10, speed);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(buffer, bsize, fmt_dec_100, speed);
|
snprintf(buffer, bsize, fmt_dec_100, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result.cvalue = speed;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatRot"){
|
else if (value->getFormat() == "formatRot"){
|
||||||
@@ -334,6 +361,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
if (rotation <= -10 || rotation >= 10){
|
if (rotation <= -10 || rotation >= 10){
|
||||||
snprintf(buffer, bsize, "%3.0f", rotation);
|
snprintf(buffer, bsize, "%3.0f", rotation);
|
||||||
}
|
}
|
||||||
|
result.cvalue = rotation;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatDop"){
|
else if (value->getFormat() == "formatDop"){
|
||||||
@@ -359,6 +387,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
else {
|
else {
|
||||||
snprintf(buffer, bsize, fmt_dec_100, dop);
|
snprintf(buffer, bsize, fmt_dec_100, dop);
|
||||||
}
|
}
|
||||||
|
result.cvalue = dop;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatLatitude"){
|
else if (value->getFormat() == "formatLatitude"){
|
||||||
@@ -383,6 +412,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
rawvalue = 35.0 + float(random(0, 10)) / 10000.0;
|
rawvalue = 35.0 + float(random(0, 10)) / 10000.0;
|
||||||
snprintf(buffer, bsize, " 51\" %2.4f' N", rawvalue);
|
snprintf(buffer, bsize, " 51\" %2.4f' N", rawvalue);
|
||||||
}
|
}
|
||||||
|
result.cvalue = rawvalue;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatLongitude"){
|
else if (value->getFormat() == "formatLongitude"){
|
||||||
@@ -407,6 +437,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
rawvalue = 6.0 + float(random(0, 10)) / 100000.0;
|
rawvalue = 6.0 + float(random(0, 10)) / 100000.0;
|
||||||
snprintf(buffer, bsize, " 15\" %2.4f'", rawvalue);
|
snprintf(buffer, bsize, " 15\" %2.4f'", rawvalue);
|
||||||
}
|
}
|
||||||
|
result.cvalue = rawvalue;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatDepth"){
|
else if (value->getFormat() == "formatDepth"){
|
||||||
@@ -416,7 +447,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
rawvalue = value->value;
|
rawvalue = value->value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rawvalue = 18.0 + float(random(0, 100)) / 10.0;
|
rawvalue = 18.0 + float(random(0, 100)) / 10.0; // create random depth values from [18..28] metres
|
||||||
depth = rawvalue;
|
depth = rawvalue;
|
||||||
}
|
}
|
||||||
if(String(lengthFormat) == "ft"){
|
if(String(lengthFormat) == "ft"){
|
||||||
@@ -435,6 +466,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
else {
|
else {
|
||||||
snprintf(buffer, bsize, fmt_dec_100, depth);
|
snprintf(buffer, bsize, fmt_dec_100, depth);
|
||||||
}
|
}
|
||||||
|
result.cvalue = depth;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXte"){
|
else if (value->getFormat() == "formatXte"){
|
||||||
@@ -467,6 +499,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
if(xte >= 100){
|
if(xte >= 100){
|
||||||
snprintf(buffer,bsize,"%3.0f",xte);
|
snprintf(buffer,bsize,"%3.0f",xte);
|
||||||
}
|
}
|
||||||
|
result.cvalue = xte;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "kelvinToC"){
|
else if (value->getFormat() == "kelvinToC"){
|
||||||
@@ -499,6 +532,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
else {
|
else {
|
||||||
snprintf(buffer, bsize, fmt_dec_100, temp);
|
snprintf(buffer, bsize, fmt_dec_100, temp);
|
||||||
}
|
}
|
||||||
|
result.cvalue = temp;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "mtr2nm"){
|
else if (value->getFormat() == "mtr2nm"){
|
||||||
@@ -531,6 +565,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
else {
|
else {
|
||||||
snprintf(buffer, bsize, fmt_dec_100, distance);
|
snprintf(buffer, bsize, fmt_dec_100, distance);
|
||||||
}
|
}
|
||||||
|
result.cvalue = distance;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
// Special XDR formats
|
// Special XDR formats
|
||||||
@@ -549,6 +584,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
}
|
}
|
||||||
snprintf(buffer, bsize, "%4.0f", pressure);
|
snprintf(buffer, bsize, "%4.0f", pressure);
|
||||||
result.unit = "hPa";
|
result.unit = "hPa";
|
||||||
|
result.cvalue = pressure;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:P:B"){
|
else if (value->getFormat() == "formatXdr:P:B"){
|
||||||
@@ -564,6 +600,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
}
|
}
|
||||||
snprintf(buffer, bsize, "%4.0f", pressure);
|
snprintf(buffer, bsize, "%4.0f", pressure);
|
||||||
result.unit = "mBar";
|
result.unit = "mBar";
|
||||||
|
result.cvalue = pressure;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:U:V"){
|
else if (value->getFormat() == "formatXdr:U:V"){
|
||||||
@@ -583,6 +620,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_10, voltage);
|
snprintf(buffer, bsize, fmt_dec_10, voltage);
|
||||||
}
|
}
|
||||||
result.unit = "V";
|
result.unit = "V";
|
||||||
|
result.cvalue = voltage;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:I:A"){
|
else if (value->getFormat() == "formatXdr:I:A"){
|
||||||
@@ -605,6 +643,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, current);
|
snprintf(buffer, bsize, fmt_dec_100, current);
|
||||||
}
|
}
|
||||||
result.unit = "A";
|
result.unit = "A";
|
||||||
|
result.cvalue = current;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:C:K"){
|
else if (value->getFormat() == "formatXdr:C:K"){
|
||||||
@@ -627,6 +666,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, temperature);
|
snprintf(buffer, bsize, fmt_dec_100, temperature);
|
||||||
}
|
}
|
||||||
result.unit = "Deg C";
|
result.unit = "Deg C";
|
||||||
|
result.cvalue = temperature;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:C:C"){
|
else if (value->getFormat() == "formatXdr:C:C"){
|
||||||
@@ -649,6 +689,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, temperature);
|
snprintf(buffer, bsize, fmt_dec_100, temperature);
|
||||||
}
|
}
|
||||||
result.unit = "Deg C";
|
result.unit = "Deg C";
|
||||||
|
result.cvalue = temperature;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:H:P"){
|
else if (value->getFormat() == "formatXdr:H:P"){
|
||||||
@@ -671,6 +712,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, humidity);
|
snprintf(buffer, bsize, fmt_dec_100, humidity);
|
||||||
}
|
}
|
||||||
result.unit = "%";
|
result.unit = "%";
|
||||||
|
result.cvalue = humidity;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:V:P"){
|
else if (value->getFormat() == "formatXdr:V:P"){
|
||||||
@@ -693,6 +735,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, volume);
|
snprintf(buffer, bsize, fmt_dec_100, volume);
|
||||||
}
|
}
|
||||||
result.unit = "%";
|
result.unit = "%";
|
||||||
|
result.cvalue = volume;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:V:M"){
|
else if (value->getFormat() == "formatXdr:V:M"){
|
||||||
@@ -715,6 +758,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, volume);
|
snprintf(buffer, bsize, fmt_dec_100, volume);
|
||||||
}
|
}
|
||||||
result.unit = "l";
|
result.unit = "l";
|
||||||
|
result.cvalue = volume;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:R:I"){
|
else if (value->getFormat() == "formatXdr:R:I"){
|
||||||
@@ -737,6 +781,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, flow);
|
snprintf(buffer, bsize, fmt_dec_100, flow);
|
||||||
}
|
}
|
||||||
result.unit = "l/min";
|
result.unit = "l/min";
|
||||||
|
result.cvalue = flow;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:G:"){
|
else if (value->getFormat() == "formatXdr:G:"){
|
||||||
@@ -759,6 +804,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, generic);
|
snprintf(buffer, bsize, fmt_dec_100, generic);
|
||||||
}
|
}
|
||||||
result.unit = "";
|
result.unit = "";
|
||||||
|
result.cvalue = generic;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:A:P"){
|
else if (value->getFormat() == "formatXdr:A:P"){
|
||||||
@@ -781,6 +827,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, dplace);
|
snprintf(buffer, bsize, fmt_dec_100, dplace);
|
||||||
}
|
}
|
||||||
result.unit = "%";
|
result.unit = "%";
|
||||||
|
result.cvalue = dplace;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:A:D"){
|
else if (value->getFormat() == "formatXdr:A:D"){
|
||||||
@@ -801,6 +848,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer,bsize,"%3.0f",angle);
|
snprintf(buffer,bsize,"%3.0f",angle);
|
||||||
}
|
}
|
||||||
result.unit = "Deg";
|
result.unit = "Deg";
|
||||||
|
result.cvalue = angle;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
else if (value->getFormat() == "formatXdr:T:R"){
|
else if (value->getFormat() == "formatXdr:T:R"){
|
||||||
@@ -823,6 +871,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, rpm);
|
snprintf(buffer, bsize, fmt_dec_100, rpm);
|
||||||
}
|
}
|
||||||
result.unit = "rpm";
|
result.unit = "rpm";
|
||||||
|
result.cvalue = rpm;
|
||||||
}
|
}
|
||||||
//########################################################
|
//########################################################
|
||||||
// Default format
|
// Default format
|
||||||
@@ -838,6 +887,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
snprintf(buffer, bsize, fmt_dec_100, value->value);
|
snprintf(buffer, bsize, fmt_dec_100, value->value);
|
||||||
}
|
}
|
||||||
result.unit = "";
|
result.unit = "";
|
||||||
|
result.cvalue = value->value;
|
||||||
}
|
}
|
||||||
buffer[bsize] = 0;
|
buffer[bsize] = 0;
|
||||||
result.value = rawvalue; // Return value is only necessary in case of simulation of graphic pointer
|
result.value = rawvalue; // Return value is only necessary in case of simulation of graphic pointer
|
||||||
@@ -845,4 +895,30 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
result = convertValue(value, "dummy", format, commondata);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
// Direction pin for RS485 NMEA0183
|
// Direction pin for RS485 NMEA0183
|
||||||
#define OBP_DIRECTION_PIN 18
|
#define OBP_DIRECTION_PIN 18
|
||||||
// I2C
|
// I2C
|
||||||
#define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
|
#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 OBP_I2C_SDA 47
|
#define OBP_I2C_SDA 47
|
||||||
#define OBP_I2C_SCL 21
|
#define OBP_I2C_SCL 21
|
||||||
// DS1388 RTC
|
// DS1388 RTC
|
||||||
@@ -42,6 +43,8 @@
|
|||||||
#define OBP_SPI_DIN 48
|
#define OBP_SPI_DIN 48
|
||||||
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
|
#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 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)
|
// GPS (NEO-6M, NEO-M8N, ATGM336H)
|
||||||
#define OBP_GPS_RX 2
|
#define OBP_GPS_RX 2
|
||||||
@@ -82,7 +85,8 @@
|
|||||||
// Direction pin for RS485 NMEA0183
|
// Direction pin for RS485 NMEA0183
|
||||||
#define OBP_DIRECTION_PIN 8
|
#define OBP_DIRECTION_PIN 8
|
||||||
// I2C
|
// I2C
|
||||||
#define I2C_SPEED 100000UL // 100kHz clock speed on I2C bus
|
#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 OBP_I2C_SDA 21
|
#define OBP_I2C_SDA 21
|
||||||
#define OBP_I2C_SCL 38
|
#define OBP_I2C_SCL 38
|
||||||
// DS1388 RTC
|
// DS1388 RTC
|
||||||
@@ -119,6 +123,8 @@
|
|||||||
#define OBP_SPI_DIN 11
|
#define OBP_SPI_DIN 11
|
||||||
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
|
#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 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
|
// SPI SD-Card
|
||||||
#define SD_SPI_CS GPIO_NUM_10
|
#define SD_SPI_CS GPIO_NUM_10
|
||||||
#define SD_SPI_MOSI GPIO_NUM_40
|
#define SD_SPI_MOSI GPIO_NUM_40
|
||||||
|
|||||||
@@ -1,152 +1,126 @@
|
|||||||
#include "OBPDataOperations.h"
|
#include "OBPDataOperations.h"
|
||||||
|
#include "BoatDataCalibration.h" // Functions lib for data instance calibration
|
||||||
|
|
||||||
// --- Class HstryBuf ---------------
|
// --- Class HstryBuf ---------------
|
||||||
// Init history buffers for selected boat data
|
HstryBuf::HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLog* log)
|
||||||
void HstryBuf::init(BoatValueList* boatValues, GwLog *log) {
|
: logger(log)
|
||||||
|
, boatDataName(name)
|
||||||
|
{
|
||||||
|
hstryBuf.resize(size);
|
||||||
|
boatValue = boatValues->findValueOrCreate(name);
|
||||||
|
}
|
||||||
|
|
||||||
logger = log;
|
void HstryBuf::init(const String& format, int updFreq, int mltplr, double minVal, double maxVal)
|
||||||
|
{
|
||||||
int hstryUpdFreq = 1000; // Update frequency for history buffers in ms
|
hstryBuf.setMetaData(boatDataName, format, updFreq, mltplr, minVal, maxVal);
|
||||||
int hstryMinVal = 0; // Minimum value for these history buffers
|
hstryMin = minVal;
|
||||||
twdHstryMax = 6283; // Max value for wind direction (TWD, AWD) in rad [0...2*PI], shifted by 1000 for 3 decimals
|
hstryMax = maxVal;
|
||||||
twsHstryMax = 65000; // Max value for wind speed (TWS, AWS) in m/s [0..65], shifted by 1000 for 3 decimals
|
if (!boatValue->valid) {
|
||||||
awdHstryMax = twdHstryMax;
|
boatValue->setFormat(format);
|
||||||
awsHstryMax = twsHstryMax;
|
boatValue->value = std::numeric_limits<double>::max(); // mark current value invalid
|
||||||
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);
|
||||||
|
|
||||||
|
} else if (useSimuData) { // add simulated value to history buffer
|
||||||
|
double simValue = formatValue(tmpBVal.get(), common).value; // simulated value is generated at <formatValue>
|
||||||
|
add(simValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --- 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
|
// collect boat values for true wind calculation
|
||||||
awaBVal = boatValues->findValueOrCreate("AWA");
|
// should all have been already created at true wind object initialization
|
||||||
hdtBVal = boatValues->findValueOrCreate("HDT");
|
// potentially to be moved to history buffer handling
|
||||||
hdmBVal = boatValues->findValueOrCreate("HDM");
|
awaBVal = boatValueList->findValueOrCreate("AWA");
|
||||||
varBVal = boatValues->findValueOrCreate("VAR");
|
hdtBVal = boatValueList->findValueOrCreate("HDT");
|
||||||
cogBVal = boatValues->findValueOrCreate("COG");
|
hdmBVal = boatValueList->findValueOrCreate("HDM");
|
||||||
sogBVal = boatValues->findValueOrCreate("SOG");
|
varBVal = boatValueList->findValueOrCreate("VAR");
|
||||||
|
cogBVal = boatValueList->findValueOrCreate("COG");
|
||||||
|
sogBVal = boatValueList->findValueOrCreate("SOG");
|
||||||
|
awdBVal = boatValueList->findValueOrCreate("AWD");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle history buffers for TWD, TWS, AWD, AWS
|
// Create history buffer for boat data type
|
||||||
//void HstryBuf::handleHstryBuf(GwApi* api, BoatValueList* boatValues, bool useSimuData) {
|
void HstryBuffers::addBuffer(const String& name)
|
||||||
void HstryBuf::handleHstryBuf(bool useSimuData) {
|
{
|
||||||
|
if (HstryBuffers::getBuffer(name) != nullptr) { // buffer for this data type already exists
|
||||||
static int16_t twd = 20; //initial value only relevant if we use simulation data
|
return;
|
||||||
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
|
if (bufferParams.find(name) == bufferParams.end()) { // requested boat data type is not supported in list of <bufferParams>
|
||||||
GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here
|
return;
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (twsBVal->valid) {
|
hstryBuffers[name] = std::unique_ptr<HstryBuf>(new HstryBuf(name, size, boatValueList, logger));
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (awaBVal->valid) {
|
// Initialize metadata for buffer
|
||||||
if (hdtBVal->valid) {
|
String valueFormat = bufferParams[name].format; // Data format of boat data type
|
||||||
hdt = hdtBVal->value; // Use HDT if available
|
// String valueFormat = boatValueList->findValueOrCreate(name)->getFormat().c_str(); // Unfortunately, format is not yet available during system initialization
|
||||||
} else {
|
int hstryUpdFreq = bufferParams[name].hstryUpdFreq; // Update frequency for history buffers in ms
|
||||||
hdt = WindUtils::calcHDT(&hdmBVal->value, &varBVal->value, &cogBVal->value, &sogBVal->value);
|
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
|
||||||
|
|
||||||
awd = awaBVal->value + hdt;
|
hstryBuffers[name]->init(valueFormat, hstryUpdFreq, mltplr, bufferMinVal, bufferMaxVal);
|
||||||
awd = WindUtils::to2PI(awd);
|
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);
|
||||||
calBVal = new GwApi::BoatValue("AWD"); // temporary solution for calibration of history buffer values
|
}
|
||||||
calBVal->value = awd;
|
|
||||||
calBVal->setFormat(awdBVal->getFormat());
|
// Handle all registered history buffers
|
||||||
calBVal->valid = true;
|
void HstryBuffers::handleHstryBufs(bool useSimuData, CommonData& common)
|
||||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
{
|
||||||
awdBVal->value = calBVal->value;
|
for (auto& bufMap : hstryBuffers) {
|
||||||
awdBVal->valid = true;
|
auto& buf = bufMap.second;
|
||||||
awd = std::round(calBVal->value * 1000.0);
|
buf->handle(useSimuData, common);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- Class HstryBuf ---------------
|
|
||||||
|
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 WindUtils --------------
|
// --- Class WindUtils --------------
|
||||||
double WindUtils::to2PI(double a)
|
double WindUtils::to2PI(double a)
|
||||||
{
|
{
|
||||||
a = fmod(a, 2 * M_PI);
|
a = fmod(a, M_TWOPI);
|
||||||
if (a < 0.0) {
|
if (a < 0.0) {
|
||||||
a += 2 * M_PI;
|
a += M_TWOPI;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -162,18 +136,18 @@ double WindUtils::toPI(double a)
|
|||||||
|
|
||||||
double WindUtils::to360(double a)
|
double WindUtils::to360(double a)
|
||||||
{
|
{
|
||||||
a = fmod(a, 360);
|
a = fmod(a, 360.0);
|
||||||
if (a < 0.0) {
|
if (a < 0.0) {
|
||||||
a += 360;
|
a += 360.0;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
double WindUtils::to180(double a)
|
double WindUtils::to180(double a)
|
||||||
{
|
{
|
||||||
a += 180;
|
a += 180.0;
|
||||||
a = to360(a);
|
a = to360(a);
|
||||||
a -= 180;
|
a -= 180.0;
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -205,14 +179,14 @@ void WindUtils::addPolar(const double* phi1, const double* r1,
|
|||||||
|
|
||||||
void WindUtils::calcTwdSA(const double* AWA, const double* AWS,
|
void WindUtils::calcTwdSA(const double* AWA, const double* AWS,
|
||||||
const double* CTW, const double* STW, const double* HDT,
|
const double* CTW, const double* STW, const double* HDT,
|
||||||
double* TWD, double* TWS, double* TWA)
|
double* TWD, double* TWS, double* TWA, double* AWD)
|
||||||
{
|
{
|
||||||
double awd = *AWA + *HDT;
|
*AWD = *AWA + *HDT;
|
||||||
awd = to2PI(awd);
|
*AWD = to2PI(*AWD);
|
||||||
double stw = -*STW;
|
double stw = -*STW;
|
||||||
addPolar(&awd, AWS, CTW, &stw, TWD, TWS);
|
addPolar(AWD, AWS, CTW, &stw, TWD, TWS);
|
||||||
|
|
||||||
// Normalize TWD and TWA to 0-360°
|
// Normalize TWD and TWA to 0-360°/2PI
|
||||||
*TWD = to2PI(*TWD);
|
*TWD = to2PI(*TWD);
|
||||||
*TWA = toPI(*TWD - *HDT);
|
*TWA = toPI(*TWD - *HDT);
|
||||||
}
|
}
|
||||||
@@ -234,12 +208,12 @@ double WindUtils::calcHDT(const double* hdmVal, const double* varVal, const doub
|
|||||||
return hdt;
|
return hdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
bool WindUtils::calcWinds(const double* awaVal, const double* awsVal,
|
||||||
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal)
|
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal, double* awdVal)
|
||||||
{
|
{
|
||||||
double stw, hdt, ctw;
|
double stw, hdt, ctw;
|
||||||
double twd, tws, twa;
|
double twd, tws, twa, awd;
|
||||||
double minSogVal = 0.1; // SOG below this value (m/s) is assumed to be data noise from GPS sensor
|
double minSogVal = 0.1; // SOG below this value (m/s) is assumed to be data noise from GPS sensor
|
||||||
|
|
||||||
if (*hdtVal != DBL_MAX) {
|
if (*hdtVal != DBL_MAX) {
|
||||||
@@ -263,60 +237,80 @@ bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
|||||||
// If STW and SOG are not available, we cannot calculate true wind
|
// If STW and SOG are not available, we cannot calculate true wind
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Serial.println("\ncalcTrueWind: HDT: " + String(hdt) + ", CTW: " + String(ctw) + ", STW: " + String(stw));
|
// LOG_DEBUG(GwLog::DEBUG, "WindUtils:calcWinds: HDT: %.1f, CTW %.1f, STW %.1f", hdt, ctw, stw);
|
||||||
|
|
||||||
if ((*awaVal == DBL_MAX) || (*awsVal == DBL_MAX)) {
|
if ((*awaVal == DBL_MAX) || (*awsVal == DBL_MAX)) {
|
||||||
// Cannot calculate true wind without valid AWA, AWS; other checks are done earlier
|
// Cannot calculate true wind without valid AWA, AWS; other checks are done earlier
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
calcTwdSA(awaVal, awsVal, &ctw, &stw, &hdt, &twd, &tws, &twa);
|
calcTwdSA(awaVal, awsVal, &ctw, &stw, &hdt, &twd, &tws, &twa, &awd);
|
||||||
*twdVal = twd;
|
*twdVal = twd;
|
||||||
*twsVal = tws;
|
*twsVal = tws;
|
||||||
*twaVal = twa;
|
*twaVal = twa;
|
||||||
|
*awdVal = awd;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate true wind data and add to obp60task boat data list
|
// Calculate true wind data and add to obp60task boat data list
|
||||||
bool WindUtils::addTrueWind(GwApi* api, BoatValueList* boatValues, GwLog* log) {
|
bool WindUtils::addWinds()
|
||||||
|
{
|
||||||
|
double twd, tws, twa, awd, hdt;
|
||||||
|
bool twCalculated = false;
|
||||||
|
bool awdCalculated = false;
|
||||||
|
|
||||||
GwLog* logger = 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);
|
||||||
|
|
||||||
double awaVal, awsVal, cogVal, stwVal, sogVal, hdtVal, hdmVal, varVal;
|
// Check if TWD can be calculated from TWA and HDT/HDM
|
||||||
double twd, tws, twa;
|
if (twaBVal->valid) {
|
||||||
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 (!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->value = twd;
|
||||||
twdBVal->valid = true;
|
twdBVal->valid = true;
|
||||||
}
|
}
|
||||||
if (!twsBVal->valid) {
|
|
||||||
twsBVal->value = tws;
|
} else {
|
||||||
twsBVal->valid = true;
|
// 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 (!twaBVal->valid) {
|
|
||||||
twaBVal->value = twa;
|
if (twCalculated) { // Replace values only, if successfully calculated and not already available
|
||||||
twaBVal->valid = true;
|
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->valid = true;
|
||||||
|
}
|
||||||
|
if (!awdBVal->valid) {
|
||||||
|
awdBVal->value = awd;
|
||||||
|
awdBVal->valid = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_DEBUG(GwLog::DEBUG,"obp60task addTrueWind: isCalculated %d, TWD %.1f, TWA %.1f, TWS %.1f", isCalculated, twdBVal->value * RAD_TO_DEG,
|
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);
|
twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852, awdBVal->value * RAD_TO_DEG);
|
||||||
|
|
||||||
return isCalculated;
|
return twCalculated;
|
||||||
}
|
}
|
||||||
// --- Class WindUtils --------------
|
// --- End Class WindUtils --------------
|
||||||
@@ -1,68 +1,89 @@
|
|||||||
|
// Function lib for history buffer handling, true wind calculation, and other operations on boat data
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <N2kMessages.h>
|
|
||||||
#include "OBPRingBuffer.h"
|
#include "OBPRingBuffer.h"
|
||||||
#include "BoatDataCalibration.h" // Functions lib for data instance calibration
|
#include "Pagedata.h"
|
||||||
#include "obp60task.h"
|
#include "obp60task.h"
|
||||||
#include <math.h>
|
#include <map>
|
||||||
|
|
||||||
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 {
|
class HstryBuf {
|
||||||
private:
|
private:
|
||||||
GwLog *logger;
|
RingBuffer<uint16_t> hstryBuf; // Circular buffer to store history values
|
||||||
|
String boatDataName;
|
||||||
|
double hstryMin;
|
||||||
|
double hstryMax;
|
||||||
|
GwApi::BoatValue* boatValue;
|
||||||
|
GwLog* logger;
|
||||||
|
|
||||||
RingBuffer<int16_t> twdHstry; // Circular buffer to store true wind direction values
|
friend class HstryBuffers;
|
||||||
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:
|
public:
|
||||||
tBoatHstryData hstryBufList;
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
HstryBuf(){
|
class HstryBuffers {
|
||||||
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; // Generate history buffers of zero size
|
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(int size) {
|
|
||||||
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry};
|
// Define buffer parameters for supported boat data type
|
||||||
hstryBufList.twdHstry->resize(960); // store 960 TWD values for 16 minutes history
|
std::map<String, HistoryParams> bufferParams = {
|
||||||
hstryBufList.twsHstry->resize(960);
|
{ "AWA", { 1000, 10000, 0.0, M_TWOPI, "formatWind" } },
|
||||||
hstryBufList.awdHstry->resize(960);
|
{ "AWD", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||||
hstryBufList.awsHstry->resize(960);
|
{ "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
|
||||||
};
|
};
|
||||||
void init(BoatValueList* boatValues, GwLog *log);
|
|
||||||
void handleHstryBuf(bool useSimuData);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
class WindUtils {
|
class WindUtils {
|
||||||
private:
|
private:
|
||||||
GwApi::BoatValue *twdBVal, *twsBVal, *twaBVal;
|
GwApi::BoatValue *twaBVal, *twsBVal, *twdBVal;
|
||||||
GwApi::BoatValue *awaBVal, *awsBVal, *cogBVal, *stwBVal, *sogBVal, *hdtBVal, *hdmBVal, *varBVal;
|
GwApi::BoatValue *awaBVal, *awsBVal, *awdBVal, *cogBVal, *stwBVal, *sogBVal, *hdtBVal, *hdmBVal, *varBVal;
|
||||||
static constexpr double DBL_MAX = std::numeric_limits<double>::max();
|
static constexpr double DBL_MAX = std::numeric_limits<double>::max();
|
||||||
|
GwLog* logger;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WindUtils(BoatValueList* boatValues){
|
WindUtils(BoatValueList* boatValues, GwLog* log)
|
||||||
twdBVal = boatValues->findValueOrCreate("TWD");
|
: logger(log)
|
||||||
twsBVal = boatValues->findValueOrCreate("TWS");
|
{
|
||||||
twaBVal = boatValues->findValueOrCreate("TWA");
|
twaBVal = boatValues->findValueOrCreate("TWA");
|
||||||
|
twsBVal = boatValues->findValueOrCreate("TWS");
|
||||||
|
twdBVal = boatValues->findValueOrCreate("TWD");
|
||||||
awaBVal = boatValues->findValueOrCreate("AWA");
|
awaBVal = boatValues->findValueOrCreate("AWA");
|
||||||
awsBVal = boatValues->findValueOrCreate("AWS");
|
awsBVal = boatValues->findValueOrCreate("AWS");
|
||||||
|
awdBVal = boatValues->findValueOrCreate("AWD");
|
||||||
cogBVal = boatValues->findValueOrCreate("COG");
|
cogBVal = boatValues->findValueOrCreate("COG");
|
||||||
stwBVal = boatValues->findValueOrCreate("STW");
|
stwBVal = boatValues->findValueOrCreate("STW");
|
||||||
sogBVal = boatValues->findValueOrCreate("SOG");
|
sogBVal = boatValues->findValueOrCreate("SOG");
|
||||||
@@ -70,6 +91,7 @@ public:
|
|||||||
hdmBVal = boatValues->findValueOrCreate("HDM");
|
hdmBVal = boatValues->findValueOrCreate("HDM");
|
||||||
varBVal = boatValues->findValueOrCreate("VAR");
|
varBVal = boatValues->findValueOrCreate("VAR");
|
||||||
};
|
};
|
||||||
|
|
||||||
static double to2PI(double a);
|
static double to2PI(double a);
|
||||||
static double toPI(double a);
|
static double toPI(double a);
|
||||||
static double to360(double a);
|
static double to360(double a);
|
||||||
@@ -81,10 +103,10 @@ public:
|
|||||||
double* phi, double* r);
|
double* phi, double* r);
|
||||||
void calcTwdSA(const double* AWA, const double* AWS,
|
void calcTwdSA(const double* AWA, const double* AWS,
|
||||||
const double* CTW, const double* STW, const double* HDT,
|
const double* CTW, const double* STW, const double* HDT,
|
||||||
double* TWD, double* TWS, double* TWA);
|
double* TWD, double* TWS, double* TWA, double* AWD);
|
||||||
static double calcHDT(const double* hdmVal, const double* varVal, const double* cogVal, const double* sogVal);
|
static double calcHDT(const double* hdmVal, const double* varVal, const double* cogVal, const double* sogVal);
|
||||||
bool calcTrueWind(const double* awaVal, const double* awsVal,
|
bool calcWinds(const double* awaVal, const double* awsVal,
|
||||||
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal);
|
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal, double* awdVal);
|
||||||
bool addTrueWind(GwApi* api, BoatValueList* boatValues, GwLog *log);
|
bool addWinds();
|
||||||
};
|
};
|
||||||
@@ -1,15 +1,44 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "FreeRTOS.h"
|
||||||
#include "GwSynchronized.h"
|
#include "GwSynchronized.h"
|
||||||
#include <algorithm>
|
|
||||||
#include <limits>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "WString.h"
|
#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; }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class RingBuffer {
|
class RingBuffer {
|
||||||
private:
|
private:
|
||||||
std::vector<T> buffer; // THE buffer vector
|
std::vector<T, PSRAMAllocator<T>> buffer; // THE buffer vector, allocated in PSRAM
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
size_t head; // Points to the next insertion position
|
size_t head; // Points to the next insertion position
|
||||||
size_t first; // Points to the first (oldest) valid element
|
size_t first; // Points to the first (oldest) valid element
|
||||||
@@ -18,49 +47,52 @@ private:
|
|||||||
bool is_Full; // Indicates that all buffer elements are used and ringing is in use
|
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 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
|
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;
|
mutable SemaphoreHandle_t bufLocker;
|
||||||
|
|
||||||
// metadata for buffer
|
// metadata for buffer
|
||||||
String dataName; // Name of boat data in buffer
|
String dataName; // Name of boat data in buffer
|
||||||
String dataFmt; // Format of boat data in buffer
|
String dataFmt; // Format of boat data in buffer
|
||||||
int updFreq; // Update frequency in milliseconds
|
int updFreq; // Update frequency in milliseconds
|
||||||
T smallest; // Value range of buffer: smallest value; needs to be => MIN_VAL
|
double mltplr; // Multiplier which transforms original <double> value into buffer type format
|
||||||
T largest; // Value range of buffer: biggest value; needs to be < MAX_VAL, since MAX_VAL indicates invalid entries
|
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
|
||||||
|
|
||||||
void initCommon();
|
void initCommon();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RingBuffer();
|
RingBuffer();
|
||||||
RingBuffer(size_t size);
|
RingBuffer(size_t size);
|
||||||
void setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue); // Set meta data for buffer
|
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, T& minValue, T& maxValue); // Get meta data of buffer
|
bool getMetaData(String& name, String& format, int& updateFrequency, double& multiplier, double& minValue, double& maxValue); // Get meta data of buffer
|
||||||
bool getMetaData(String& name, String& format);
|
bool getMetaData(String& name, String& format);
|
||||||
String getName() const; // Get buffer name
|
String getName() const; // Get buffer name
|
||||||
String getFormat() const; // Get buffer data format
|
String getFormat() const; // Get buffer data format
|
||||||
void add(const T& value); // Add a new value to buffer
|
void add(const double& 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)
|
double 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
|
double getFirst() const; // Get the first (oldest) value in buffer
|
||||||
T getLast() const; // Get the last (newest) value in buffer
|
double getLast() const; // Get the last (newest) value in buffer
|
||||||
T getMin() const; // Get the lowest value in buffer
|
double getMin() const; // Get the lowest value in buffer
|
||||||
T getMin(size_t amount) const; // Get minimum value of the last <amount> values of buffer
|
double getMin(size_t amount) const; // Get minimum value of the last <amount> values of buffer
|
||||||
T getMax() const; // Get the highest value in buffer
|
double getMax() const; // Get the highest value in buffer
|
||||||
T getMax(size_t amount) const; // Get maximum value of the last <amount> values of buffer
|
double 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
|
double 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
|
double 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
|
double 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
|
double 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 getCapacity() const; // Get the buffer capacity (maximum size)
|
||||||
size_t getCurrentSize() const; // Get the current number of elements in buffer
|
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 getFirstIdx() const; // Get the index of oldest value in buffer
|
||||||
size_t getLastIdx() const; // Get the index of newest value in buffer
|
size_t getLastIdx() const; // Get the index of newest value in buffer
|
||||||
bool isEmpty() const; // Check if buffer is empty
|
bool isEmpty() const; // Check if buffer is empty
|
||||||
bool isFull() const; // Check if buffer is full
|
bool isFull() const; // Check if buffer is full
|
||||||
T getMinVal() const; // Get lowest possible value for buffer
|
double getMinVal() const; // Get lowest possible value for buffer
|
||||||
T getMaxVal() const; // Get highest possible value for buffer; used for unset/invalid buffer data
|
double getMaxVal() const; // Get highest possible value for buffer; used for unset/invalid buffer data
|
||||||
void clear(); // Clear buffer
|
void clear(); // Clear buffer
|
||||||
void resize(size_t size); // Delete buffer and set new size
|
void resize(size_t size); // Delete buffer and set new size
|
||||||
T operator[](size_t index) const; // Operator[] for convenient access (same as get())
|
double operator[](size_t index) const; // Operator[] for convenient access (same as get())
|
||||||
std::vector<T> getAllValues() const; // Get all current values as a vector
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "OBPRingBuffer.tpp"
|
#include "OBPRingBuffer.tpp"
|
||||||
@@ -1,14 +1,21 @@
|
|||||||
#include "OBPRingBuffer.h"
|
#include "OBPRingBuffer.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void RingBuffer<T>::initCommon() {
|
void RingBuffer<T>::initCommon()
|
||||||
|
{
|
||||||
MIN_VAL = std::numeric_limits<T>::lowest();
|
MIN_VAL = std::numeric_limits<T>::lowest();
|
||||||
MAX_VAL = std::numeric_limits<T>::max();
|
MAX_VAL = std::numeric_limits<T>::max();
|
||||||
|
dblMIN_VAL = static_cast<double>(MIN_VAL);
|
||||||
|
dblMAX_VAL = static_cast<double>(MAX_VAL);
|
||||||
dataName = "";
|
dataName = "";
|
||||||
dataFmt = "";
|
dataFmt = "";
|
||||||
updFreq = -1;
|
updFreq = -1;
|
||||||
smallest = MIN_VAL;
|
mltplr = 1;
|
||||||
largest = MAX_VAL;
|
smallest = dblMIN_VAL;
|
||||||
|
largest = dblMAX_VAL;
|
||||||
bufLocker = xSemaphoreCreateMutex();
|
bufLocker = xSemaphoreCreateMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,24 +42,27 @@ RingBuffer<T>::RingBuffer(size_t size)
|
|||||||
, is_Full(false)
|
, is_Full(false)
|
||||||
{
|
{
|
||||||
initCommon();
|
initCommon();
|
||||||
|
|
||||||
|
buffer.reserve(size);
|
||||||
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values
|
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specify meta data of buffer content
|
// Specify meta data of buffer content
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue)
|
void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency, double multiplier, double minValue, double maxValue)
|
||||||
{
|
{
|
||||||
GWSYNCHRONIZED(&bufLocker);
|
GWSYNCHRONIZED(&bufLocker);
|
||||||
dataName = name;
|
dataName = name;
|
||||||
dataFmt = format;
|
dataFmt = format;
|
||||||
updFreq = updateFrequency;
|
updFreq = updateFrequency;
|
||||||
smallest = std::max(MIN_VAL, minValue);
|
mltplr = multiplier;
|
||||||
largest = std::min(MAX_VAL, maxValue);
|
smallest = std::max(dblMIN_VAL, minValue);
|
||||||
|
largest = std::min(dblMAX_VAL, maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get meta data of buffer content
|
// Get meta data of buffer content
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequency, T& minValue, T& maxValue)
|
bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequency, double& multiplier, double& minValue, double& maxValue)
|
||||||
{
|
{
|
||||||
if (dataName == "" || dataFmt == "" || updFreq == -1) {
|
if (dataName == "" || dataFmt == "" || updFreq == -1) {
|
||||||
return false; // Meta data not set
|
return false; // Meta data not set
|
||||||
@@ -62,6 +72,7 @@ bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequen
|
|||||||
name = dataName;
|
name = dataName;
|
||||||
format = dataFmt;
|
format = dataFmt;
|
||||||
updateFrequency = updFreq;
|
updateFrequency = updFreq;
|
||||||
|
multiplier = mltplr;
|
||||||
minValue = smallest;
|
minValue = smallest;
|
||||||
maxValue = largest;
|
maxValue = largest;
|
||||||
return true;
|
return true;
|
||||||
@@ -97,13 +108,13 @@ String RingBuffer<T>::getFormat() const
|
|||||||
|
|
||||||
// Add a new value to buffer
|
// Add a new value to buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void RingBuffer<T>::add(const T& value)
|
void RingBuffer<T>::add(const double& value)
|
||||||
{
|
{
|
||||||
GWSYNCHRONIZED(&bufLocker);
|
GWSYNCHRONIZED(&bufLocker);
|
||||||
if (value < smallest || value > largest) {
|
if (value < smallest || value > largest) {
|
||||||
buffer[head] = MAX_VAL; // Store MAX_VAL if value is out of range
|
buffer[head] = MAX_VAL; // Store MAX_VAL if value is out of range
|
||||||
} else {
|
} else {
|
||||||
buffer[head] = value;
|
buffer[head] = static_cast<T>(std::round(value * mltplr));
|
||||||
}
|
}
|
||||||
last = head;
|
last = head;
|
||||||
|
|
||||||
@@ -115,63 +126,63 @@ void RingBuffer<T>::add(const T& value)
|
|||||||
is_Full = true;
|
is_Full = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Serial.printf("Ringbuffer: value %.3f, multiplier: %.1f, buffer: %d\n", value, mltplr, buffer[head]);
|
||||||
head = (head + 1) % capacity;
|
head = (head + 1) % capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get value at specific position (0-based index from oldest to newest)
|
// Get value at specific position (0-based index from oldest to newest)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::get(size_t index) const
|
double RingBuffer<T>::get(size_t index) const
|
||||||
{
|
{
|
||||||
GWSYNCHRONIZED(&bufLocker);
|
GWSYNCHRONIZED(&bufLocker);
|
||||||
if (isEmpty() || index < 0 || index >= count) {
|
if (isEmpty() || index < 0 || index >= count) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t realIndex = (first + index) % capacity;
|
size_t realIndex = (first + index) % capacity;
|
||||||
return buffer[realIndex];
|
return static_cast<double>(buffer[realIndex] / mltplr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operator[] for convenient access (same as get())
|
// Operator[] for convenient access (same as get())
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::operator[](size_t index) const
|
double RingBuffer<T>::operator[](size_t index) const
|
||||||
{
|
{
|
||||||
return get(index);
|
return get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the first (oldest) value in the buffer
|
// Get the first (oldest) value in the buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getFirst() const
|
double RingBuffer<T>::getFirst() const
|
||||||
{
|
{
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
return get(0);
|
return get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the last (newest) value in the buffer
|
// Get the last (newest) value in the buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getLast() const
|
double RingBuffer<T>::getLast() const
|
||||||
{
|
{
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
return get(count - 1);
|
return get(count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the lowest value in the buffer
|
// Get the lowest value in the buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMin() const
|
double RingBuffer<T>::getMin() const
|
||||||
{
|
{
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
T minVal = MAX_VAL;
|
double minVal = dblMAX_VAL;
|
||||||
T value;
|
double value;
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
value = get(i);
|
value = get(i);
|
||||||
if (value < minVal && value != MAX_VAL) {
|
if (value < minVal && value != dblMAX_VAL) {
|
||||||
minVal = value;
|
minVal = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,19 +191,19 @@ T RingBuffer<T>::getMin() const
|
|||||||
|
|
||||||
// Get minimum value of the last <amount> values of buffer
|
// Get minimum value of the last <amount> values of buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMin(size_t amount) const
|
double RingBuffer<T>::getMin(size_t amount) const
|
||||||
{
|
{
|
||||||
if (isEmpty() || amount <= 0) {
|
if (isEmpty() || amount <= 0) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
if (amount > count)
|
if (amount > count)
|
||||||
amount = count;
|
amount = count;
|
||||||
|
|
||||||
T minVal = MAX_VAL;
|
double minVal = dblMAX_VAL;
|
||||||
T value;
|
double value;
|
||||||
for (size_t i = 0; i < amount; i++) {
|
for (size_t i = 0; i < amount; i++) {
|
||||||
value = get(count - 1 - i);
|
value = get(count - 1 - i);
|
||||||
if (value < minVal && value != MAX_VAL) {
|
if (value < minVal && value != dblMAX_VAL) {
|
||||||
minVal = value;
|
minVal = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,75 +212,81 @@ T RingBuffer<T>::getMin(size_t amount) const
|
|||||||
|
|
||||||
// Get the highest value in the buffer
|
// Get the highest value in the buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMax() const
|
double RingBuffer<T>::getMax() const
|
||||||
{
|
{
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
T maxVal = MIN_VAL;
|
double maxVal = dblMIN_VAL;
|
||||||
T value;
|
double value;
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
value = get(i);
|
value = get(i);
|
||||||
if (value > maxVal && value != MAX_VAL) {
|
if (value > maxVal && value != dblMAX_VAL) {
|
||||||
maxVal = value;
|
maxVal = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
|
||||||
|
maxVal = dblMAX_VAL;
|
||||||
|
}
|
||||||
return maxVal;
|
return maxVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get maximum value of the last <amount> values of buffer
|
// Get maximum value of the last <amount> values of buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMax(size_t amount) const
|
double RingBuffer<T>::getMax(size_t amount) const
|
||||||
{
|
{
|
||||||
if (isEmpty() || amount <= 0) {
|
if (isEmpty() || amount <= 0) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
if (amount > count)
|
if (amount > count)
|
||||||
amount = count;
|
amount = count;
|
||||||
|
|
||||||
T maxVal = MIN_VAL;
|
double maxVal = dblMIN_VAL;
|
||||||
T value;
|
double value;
|
||||||
for (size_t i = 0; i < amount; i++) {
|
for (size_t i = 0; i < amount; i++) {
|
||||||
value = get(count - 1 - i);
|
value = get(count - 1 - i);
|
||||||
if (value > maxVal && value != MAX_VAL) {
|
if (value > maxVal && value != dblMAX_VAL) {
|
||||||
maxVal = value;
|
maxVal = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
|
||||||
|
maxVal = dblMAX_VAL;
|
||||||
|
}
|
||||||
return maxVal;
|
return maxVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get mid value between <min> and <max> value in the buffer
|
// Get mid value between <min> and <max> value in the buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMid() const
|
double RingBuffer<T>::getMid() const
|
||||||
{
|
{
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (getMin() + getMax()) / static_cast<T>(2);
|
return (getMin() + getMax()) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get mid value between <min> and <max> value of the last <amount> values of buffer
|
// Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMid(size_t amount) const
|
double RingBuffer<T>::getMid(size_t amount) const
|
||||||
{
|
{
|
||||||
if (isEmpty() || amount <= 0) {
|
if (isEmpty() || amount <= 0) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount > count)
|
if (amount > count)
|
||||||
amount = count;
|
amount = count;
|
||||||
|
|
||||||
return (getMin(amount) + getMax(amount)) / static_cast<T>(2);
|
return (getMin(amount) + getMax(amount)) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the median value in the buffer
|
// Get the median value in the buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMedian() const
|
double RingBuffer<T>::getMedian() const
|
||||||
{
|
{
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a temporary vector with current valid elements
|
// Create a temporary vector with current valid elements
|
||||||
@@ -285,20 +302,20 @@ T RingBuffer<T>::getMedian() const
|
|||||||
|
|
||||||
if (count % 2 == 1) {
|
if (count % 2 == 1) {
|
||||||
// Odd number of elements
|
// Odd number of elements
|
||||||
return temp[count / 2];
|
return static_cast<double>(temp[count / 2]);
|
||||||
} else {
|
} else {
|
||||||
// Even number of elements - return average of middle two
|
// Even number of elements - return average of middle two
|
||||||
// Note: For integer types, this truncates. For floating point, it's exact.
|
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||||
return (temp[count / 2 - 1] + temp[count / 2]) / 2;
|
return static_cast<double>((temp[count / 2 - 1] + temp[count / 2]) / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the median value of the last <amount> values of buffer
|
// Get the median value of the last <amount> values of buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMedian(size_t amount) const
|
double RingBuffer<T>::getMedian(size_t amount) const
|
||||||
{
|
{
|
||||||
if (isEmpty() || amount <= 0) {
|
if (isEmpty() || amount <= 0) {
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
if (amount > count)
|
if (amount > count)
|
||||||
amount = count;
|
amount = count;
|
||||||
@@ -308,7 +325,7 @@ T RingBuffer<T>::getMedian(size_t amount) const
|
|||||||
temp.reserve(amount);
|
temp.reserve(amount);
|
||||||
|
|
||||||
for (size_t i = 0; i < amount; i++) {
|
for (size_t i = 0; i < amount; i++) {
|
||||||
temp.push_back(get(i));
|
temp.push_back(get(count - 1 - i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort to find median
|
// Sort to find median
|
||||||
@@ -316,11 +333,11 @@ T RingBuffer<T>::getMedian(size_t amount) const
|
|||||||
|
|
||||||
if (amount % 2 == 1) {
|
if (amount % 2 == 1) {
|
||||||
// Odd number of elements
|
// Odd number of elements
|
||||||
return temp[amount / 2];
|
return static_cast<double>(temp[amount / 2]);
|
||||||
} else {
|
} else {
|
||||||
// Even number of elements - return average of middle two
|
// Even number of elements - return average of middle two
|
||||||
// Note: For integer types, this truncates. For floating point, it's exact.
|
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||||
return (temp[amount / 2 - 1] + temp[amount / 2]) / 2;
|
return static_cast<double>((temp[amount / 2 - 1] + temp[amount / 2]) / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,16 +385,16 @@ bool RingBuffer<T>::isFull() const
|
|||||||
|
|
||||||
// Get lowest possible value for buffer
|
// Get lowest possible value for buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMinVal() const
|
double RingBuffer<T>::getMinVal() const
|
||||||
{
|
{
|
||||||
return MIN_VAL;
|
return dblMIN_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get highest possible value for buffer; used for unset/invalid buffer data
|
// Get highest possible value for buffer; used for unset/invalid buffer data
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMaxVal() const
|
double RingBuffer<T>::getMaxVal() const
|
||||||
{
|
{
|
||||||
return MAX_VAL;
|
return dblMAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear buffer
|
// Clear buffer
|
||||||
@@ -405,19 +422,41 @@ void RingBuffer<T>::resize(size_t newSize)
|
|||||||
is_Full = false;
|
is_Full = false;
|
||||||
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
|
buffer.reserve(newSize);
|
||||||
buffer.resize(newSize, MAX_VAL);
|
buffer.resize(newSize, MAX_VAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all current values as a vector
|
// Get all current values in native buffer format as a vector
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::vector<T> RingBuffer<T>::getAllValues() const
|
std::vector<double> RingBuffer<T>::getAllValues() const
|
||||||
{
|
{
|
||||||
std::vector<T> result;
|
std::vector<double> result;
|
||||||
result.reserve(count);
|
result.reserve(count);
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
result.push_back(get(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;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <PubSubClient.h>
|
|
||||||
#include "OBPTrackerTask.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Regatta Hero: use PubSubClient preferred over MQTTClient. Less
|
|
||||||
functionality but smaller and easier.
|
|
||||||
|
|
||||||
JSON-data to send to server:
|
|
||||||
Payload = {
|
|
||||||
"passcode": "[code]",
|
|
||||||
"orgid": "[orgname]",
|
|
||||||
"raceid": "[raceid]",
|
|
||||||
"gps": {
|
|
||||||
"lat": 47.823938240041436,
|
|
||||||
"lon": 8.1386857025205,
|
|
||||||
"speed": 5.5,
|
|
||||||
"odo": 1000,
|
|
||||||
"age": 1000,
|
|
||||||
"bat": 0.7,
|
|
||||||
"timestamp": "2011-10-05T14:48:00.000Z"
|
|
||||||
},
|
|
||||||
"boat": {
|
|
||||||
"boatid": "c32d8b45-92fe-44f6-8b61-42c2107dfe45",
|
|
||||||
"sailno": "GER 11",
|
|
||||||
"team": "OBP60team",
|
|
||||||
"boatclass": "One off",
|
|
||||||
"handicap": 114.0,
|
|
||||||
"club": "BSC",
|
|
||||||
"boatname": "Delfin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mqttClient.state()
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
void mqttCallback(char *topic, byte *payload, unsigned int length) {
|
|
||||||
|
|
||||||
if (String(topic) == "hero/race") {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void trackerTask(void *param) {
|
|
||||||
TrackerData *data = (TrackerData *)param;
|
|
||||||
|
|
||||||
// TCP client connection is needed
|
|
||||||
GwApi::Status status;
|
|
||||||
data->api->getStatus(status);
|
|
||||||
if (status.wifiClientConnected) {
|
|
||||||
data->logger->logDebug(GwLog::ERROR, "No WiFi connection. Cannot start tracker task.");
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
WiFiClient wificlient;
|
|
||||||
PubSubClient mqtt(wificlient);
|
|
||||||
|
|
||||||
String broker = "mqtt.regattahero.com";
|
|
||||||
String mqttUsername = "obp60";
|
|
||||||
String mqttPassword = "23qwecv";
|
|
||||||
// String mqttClientID = generateClientID();
|
|
||||||
|
|
||||||
mqtt.setServer(broker.c_str(), 1883);
|
|
||||||
mqtt.setBufferSize(2048); // Erhöht die maximale Payload-Größe auf 512 Bytes *** TODO WTF?
|
|
||||||
mqtt.setCallback(mqttCallback);
|
|
||||||
// mqtt.connect(mqttClientID.c_str(), mqttUsername.c_str(), mqttPassword.c_str())
|
|
||||||
|
|
||||||
String subRaceStatus = "regattahero/racestatus/[orgname]/#";
|
|
||||||
// mqtt.subscribe(subRaceStatus.c_str());
|
|
||||||
|
|
||||||
String subOrgStatus = "regattahero/orgstatus/[orgname]/#";
|
|
||||||
// mqtt.subscribe(subOrgStatus.c_str());
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
delay(1000); // Loop time one second
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void createTrackerTask(TrackerData *param) {
|
|
||||||
TaskHandle_t xHandle = NULL;
|
|
||||||
if (xTaskCreate(trackerTask, "tracker", configMINIMAL_STACK_SIZE + 2048, param, configMAX_PRIORITIES-1, &xHandle)) {
|
|
||||||
param->logger->logDebug(GwLog::ERROR, "Failed to create tracker task!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
#pragma once
|
|
||||||
#include "GwApi.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
GwApi *api = nullptr;
|
|
||||||
GwLog *logger = nullptr;
|
|
||||||
} TrackerData;
|
|
||||||
|
|
||||||
void createTrackerTask(TrackerData *param);
|
|
||||||
805
lib/obp60task/OBPcharts.cpp
Normal file
805
lib/obp60task/OBPcharts.cpp
Normal file
@@ -0,0 +1,805 @@
|
|||||||
|
// 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 ---------------
|
||||||
116
lib/obp60task/OBPcharts.h
Normal file
116
lib/obp60task/OBPcharts.h
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// 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
|
||||||
|
};
|
||||||
131
lib/obp60task/PageDigitalOut.cpp
Normal file
131
lib/obp60task/PageDigitalOut.cpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
setPCF8574PortPin(0, button1 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||||
|
return 0; // Commit the key
|
||||||
|
}
|
||||||
|
// Code for button 2
|
||||||
|
if(key == 2){
|
||||||
|
button2 = !button2;
|
||||||
|
setPCF8574PortPin(1, button2 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||||
|
return 0; // Commit the key
|
||||||
|
}
|
||||||
|
// Code for button 3
|
||||||
|
if(key == 3){
|
||||||
|
button3 = !button3;
|
||||||
|
setPCF8574PortPin(2, button3 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||||
|
return 0; // Commit the key
|
||||||
|
}
|
||||||
|
// Code for button 4
|
||||||
|
if(key == 4){
|
||||||
|
button4 = !button4;
|
||||||
|
setPCF8574PortPin(3, button4 ? 0 : 1); // Attention! Inverse logic for PCF8574
|
||||||
|
return 0; // Commit the key
|
||||||
|
}
|
||||||
|
// Code for button 5
|
||||||
|
if(key == 5){
|
||||||
|
button5 = !button5;
|
||||||
|
setPCF8574PortPin(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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
getdisplay().fillRoundRect(200, 250 , 200, 25, 5, commonData->fgcolor); // Black rect
|
||||||
|
getdisplay().fillRoundRect(202, 252 , 196, 21, 5, commonData->bgcolor); // White rect
|
||||||
|
getdisplay().setCursor(210, 270);
|
||||||
|
getdisplay().print("Map server lost");
|
||||||
|
|
||||||
|
// Set botton labels
|
||||||
|
commonData->keydata[0].label = "BTN 1";
|
||||||
|
commonData->keydata[1].label = "BTN 2";
|
||||||
|
commonData->keydata[2].label = "BTN 3";
|
||||||
|
commonData->keydata[3].label = "BTN 4";
|
||||||
|
commonData->keydata[4].label = "BTN 5";
|
||||||
|
|
||||||
|
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
|
||||||
505
lib/obp60task/PageNavigation.cpp
Normal file
505
lib/obp60task/PageNavigation.cpp
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set botton labels
|
||||||
|
commonData->keydata[0].label = "ZOOM -";
|
||||||
|
commonData->keydata[1].label = "ZOOM +";
|
||||||
|
commonData->keydata[4].label = "VALUES";
|
||||||
|
|
||||||
|
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
|
||||||
@@ -3,112 +3,300 @@
|
|||||||
#include "Pagedata.h"
|
#include "Pagedata.h"
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "BoatDataCalibration.h"
|
#include "BoatDataCalibration.h"
|
||||||
|
#include "OBPDataOperations.h"
|
||||||
|
#include "OBPcharts.h"
|
||||||
|
|
||||||
class PageOneValue : public Page
|
class PageOneValue : public Page {
|
||||||
{
|
private:
|
||||||
public:
|
GwLog* logger;
|
||||||
PageOneValue(CommonData &common){
|
|
||||||
commonData = &common;
|
enum PageMode {
|
||||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageOneValue");
|
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
|
||||||
|
calibrationData.calibrateInstance(bValue1, logger); // Check if boat data value is to be calibrated
|
||||||
|
double value1 = bValue1->value; // Value as double in SI unit
|
||||||
|
bool valid1 = bValue1->valid; // Valid information
|
||||||
|
String sValue1 = formatValue(bValue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||||
|
String unit1 = formatValue(bValue1, *commonData).unit; // Unit of value
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int handleKey(int key){
|
public:
|
||||||
// Code for keylock
|
PageOneValue(CommonData& common)
|
||||||
if(key == 11){
|
{
|
||||||
|
commonData = &common;
|
||||||
|
logger = commonData->logger;
|
||||||
|
LOG_DEBUG(GwLog::LOG, "Instantiate PageOneValue");
|
||||||
|
|
||||||
|
width = getdisplay().width(); // Screen width
|
||||||
|
height = getdisplay().height(); // Screen height
|
||||||
|
|
||||||
|
// 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]
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
commonData->keylock = !commonData->keylock;
|
commonData->keylock = !commonData->keylock;
|
||||||
return 0; // Commit the key
|
return 0; // Commit the key
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
int displayPage(PageData &pageData){
|
virtual void displayNew(PageData& pageData)
|
||||||
GwConfigHandler *config = commonData->config;
|
{
|
||||||
GwLog *logger = commonData->logger;
|
#ifdef BOARD_OBP60S3
|
||||||
|
// Clear optical warning
|
||||||
// Old values for hold function
|
if (flashLED == "Limit Violation") {
|
||||||
static String svalue1old = "";
|
|
||||||
static String unit1old = "";
|
|
||||||
|
|
||||||
// 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
|
|
||||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
|
||||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
|
||||||
name1 = name1.substring(0, 6); // String length limit for value name
|
|
||||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
|
||||||
double value1 = bvalue1->value; // Value as double in SI unit
|
|
||||||
bool valid1 = bvalue1->valid; // Valid information
|
|
||||||
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
|
||||||
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
|
|
||||||
|
|
||||||
// Optical warning by limit violation (unused)
|
|
||||||
if(String(flashLED) == "Limit Violation"){
|
|
||||||
setBlinkingLED(false);
|
setBlinkingLED(false);
|
||||||
setFlashLED(false);
|
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
|
||||||
|
|
||||||
|
dataHstryBuf = pageData.hstryBuffers->getBuffer(bValName1);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging boat values
|
setupKeys(); // adjust <mode> key depending on chart supported boat data type
|
||||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
}
|
||||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageOneValue, %s: %f", name1.c_str(), value1);
|
|
||||||
|
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);
|
||||||
|
|
||||||
// Draw page
|
// Draw page
|
||||||
//***********************************************************
|
//***********************************************************
|
||||||
|
|
||||||
/// Set display in partial refresh mode
|
getdisplay().setPartialWindow(0, 0, width, height); // Set partial update
|
||||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
|
||||||
|
|
||||||
// Show name
|
if (pageMode == VALUE || dataHstryBuf == nullptr) {
|
||||||
getdisplay().setTextColor(commonData->fgcolor);
|
// show only data value; ignore other pageMode options if no chart supported boat data history buffer is available
|
||||||
getdisplay().setFont(&Ubuntu_Bold32pt8b);
|
showData(bValue1, FULL);
|
||||||
getdisplay().setCursor(20, 100);
|
|
||||||
getdisplay().print(name1); // Page name
|
|
||||||
|
|
||||||
// Show unit
|
} else if (pageMode == CHART) { // show only data chart
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
if (dataChart) {
|
||||||
getdisplay().setCursor(270, 100);
|
dataChart->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue1);
|
||||||
if(holdvalues == false){
|
}
|
||||||
getdisplay().print(unit1); // Unit
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().print(unit1old);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch font if format for any values
|
} else if (pageMode == BOTH) { // show data value and chart
|
||||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
showData(bValue1, HALF);
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
if (dataChart) {
|
||||||
getdisplay().setCursor(20, 180);
|
dataChart->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, NO_PRNT_NAME, NO_PRNT_VALUE, *bValue1);
|
||||||
}
|
}
|
||||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold32pt8b);
|
|
||||||
getdisplay().setCursor(20, 200);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
|
|
||||||
getdisplay().setCursor(20, 240);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show bus data
|
|
||||||
if(holdvalues == false){
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PAGE_UPDATE;
|
return PAGE_UPDATE;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
static Page* createPage(CommonData &common){
|
static Page* createPage(CommonData& common)
|
||||||
|
{
|
||||||
return new PageOneValue(common);
|
return new PageOneValue(common);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,10 +308,10 @@ static Page* createPage(CommonData &common){
|
|||||||
* this will be number of BoatValue pointers in pageData.values
|
* this will be number of BoatValue pointers in pageData.values
|
||||||
*/
|
*/
|
||||||
PageDescription registerPageOneValue(
|
PageDescription registerPageOneValue(
|
||||||
"OneValue", // Page name
|
"OneValue", // Page name
|
||||||
createPage, // Action
|
createPage, // Action
|
||||||
1, // Number of bus values depends on selection in Web configuration
|
1, // Number of bus values depends on selection in Web configuration
|
||||||
true // Show display header on/off
|
true // Show display header on/off
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -121,18 +121,20 @@ public:
|
|||||||
getdisplay().setCursor(c.x - r + 3 , c.y + h / 2);
|
getdisplay().setCursor(c.x - r + 3 , c.y + h / 2);
|
||||||
getdisplay().print("W");
|
getdisplay().print("W");
|
||||||
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
|
|
||||||
// show satellites in "map"
|
// show satellites in "map"
|
||||||
|
getdisplay().setFont(&IBM8x8px);
|
||||||
for (int i = 0; i < nSat; i++) {
|
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) + M_PI;
|
||||||
float erad = sats[i].Elevation * M_PI / 180.0;
|
float erad = sats[i].Elevation * M_PI / 180.0;
|
||||||
uint16_t x = c.x + sin(arad) * erad * r1;
|
uint16_t x = c.x + sin(arad) * erad * r1;
|
||||||
uint16_t y = c.y + cos(arad) * erad * r1;
|
uint16_t y = c.y + cos(arad) * erad * r1;
|
||||||
getdisplay().fillRect(x-4, y-4, 8, 8, commonData->fgcolor);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal / Noise bars
|
// Signal / Noise bars
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
getdisplay().setCursor(325, 34);
|
getdisplay().setCursor(325, 34);
|
||||||
getdisplay().print("SNR");
|
getdisplay().print("SNR");
|
||||||
// getdisplay().drawRect(270, 20, 125, 257, commonData->fgcolor);
|
// getdisplay().drawRect(270, 20, 125, 257, commonData->fgcolor);
|
||||||
@@ -169,8 +171,10 @@ public:
|
|||||||
getdisplay().print("HDOP:");
|
getdisplay().print("HDOP:");
|
||||||
|
|
||||||
GwApi::BoatValue *bv_hdop = pageData.values[1]; // HDOP
|
GwApi::BoatValue *bv_hdop = pageData.values[1]; // HDOP
|
||||||
String sval_hdop = formatValue(bv_hdop, *commonData).svalue;
|
double hdop = formatValue(bv_hdop, *commonData).value * 4; // 4 is factor for UERE (translation in meter)
|
||||||
sval_hdop = sval_hdop + "m";
|
char sval_hdop[20];
|
||||||
|
dtostrf(hdop, 0, 1, sval_hdop); // Only one prefix
|
||||||
|
strcat(sval_hdop, "m");
|
||||||
getdisplay().setCursor(220, 269);
|
getdisplay().setCursor(220, 269);
|
||||||
getdisplay().print(sval_hdop);
|
getdisplay().print(sval_hdop);
|
||||||
|
|
||||||
|
|||||||
@@ -1,284 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tracker
|
|
||||||
- standalone with SD card backend
|
|
||||||
- standalone with server backend
|
|
||||||
- Regatta Hero integration
|
|
||||||
|
|
||||||
In start phase big timer.
|
|
||||||
Eventually after start other display because timer not needed any
|
|
||||||
more. Race timer smaller on top right corner. Reserved space for
|
|
||||||
message area.
|
|
||||||
|
|
||||||
4 Positions for flags
|
|
||||||
+-----+-----+
|
|
||||||
| 1 | 2 |
|
|
||||||
+-----+-----+
|
|
||||||
| 3 | 4 |
|
|
||||||
+-----+-----+
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Pagedata.h"
|
|
||||||
#include "OBP60Extensions.h"
|
|
||||||
|
|
||||||
// Flags
|
|
||||||
#include "images/alpha.xbm"
|
|
||||||
#include "images/answer.xbm"
|
|
||||||
#include "images/black.xbm"
|
|
||||||
#include "images/blue.xbm"
|
|
||||||
#include "images/charlie.xbm"
|
|
||||||
#include "images/class.xbm"
|
|
||||||
#include "images/finish.xbm"
|
|
||||||
#include "images/hotel.xbm"
|
|
||||||
#include "images/india.xbm"
|
|
||||||
#include "images/november.xbm"
|
|
||||||
#include "images/orange.xbm"
|
|
||||||
#include "images/papa.xbm"
|
|
||||||
#include "images/repeat_one.xbm"
|
|
||||||
#include "images/sierra.xbm"
|
|
||||||
#include "images/start.xbm"
|
|
||||||
#include "images/uniform.xbm"
|
|
||||||
#include "images/xray.xbm"
|
|
||||||
#include "images/yankee.xbm"
|
|
||||||
#include "images/zulu.xbm"
|
|
||||||
|
|
||||||
class PageTracker : public Page
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
char mode = 'N'; // (N)ormal, (C)onfig
|
|
||||||
bool simulation = false;
|
|
||||||
String flashLED;
|
|
||||||
|
|
||||||
String trackerType;
|
|
||||||
String trackerOrganisation;
|
|
||||||
String trackerTeam;
|
|
||||||
String sailClub;
|
|
||||||
String boatName;
|
|
||||||
String boatClass;
|
|
||||||
String boatSailNumber;
|
|
||||||
float boatHandicap;
|
|
||||||
|
|
||||||
void displayModeNormal(PageData &pageData) {
|
|
||||||
|
|
||||||
// TBD Boatvalues: ...
|
|
||||||
|
|
||||||
// Title
|
|
||||||
/* getdisplay().setTextColor(commonData->fgcolor);
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
|
||||||
getdisplay().setCursor(8, 48);
|
|
||||||
getdisplay().print("Tracker"); */
|
|
||||||
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
getdisplay().setCursor(8, 42);
|
|
||||||
if (trackerType == "NONE") {
|
|
||||||
getdisplay().print("Disabled!");
|
|
||||||
} else {
|
|
||||||
getdisplay().print(trackerType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timer
|
|
||||||
getdisplay().setCursor(16, 120);
|
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
|
|
||||||
getdisplay().print("-00:00");
|
|
||||||
|
|
||||||
getdisplay().drawXBitmap(4, 140, class_bits, class_width, class_height, commonData->fgcolor);
|
|
||||||
getdisplay().drawXBitmap(102, 140, start_bits, start_width, start_height, commonData->fgcolor);
|
|
||||||
getdisplay().drawXBitmap(202, 140, finish_bits, finish_width, finish_height, commonData->fgcolor);
|
|
||||||
|
|
||||||
getdisplay().drawXBitmap(4, 210, alpha_bits, alpha_width, alpha_height, commonData->fgcolor);
|
|
||||||
getdisplay().drawXBitmap(102, 210, answer_bits, answer_width, answer_height, commonData->fgcolor);
|
|
||||||
getdisplay().drawXBitmap(202, 210, papa_bits, papa_width, papa_height, commonData->fgcolor);
|
|
||||||
getdisplay().drawXBitmap(302, 210, yankee_bits, yankee_width, yankee_height, commonData->fgcolor);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void displayModeConfig() {
|
|
||||||
|
|
||||||
uint16_t x0 = 8; // left label column
|
|
||||||
uint16_t x1 = 112; // data starts here
|
|
||||||
uint16_t y0 = 48;
|
|
||||||
|
|
||||||
getdisplay().setTextColor(commonData->fgcolor);
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
|
||||||
getdisplay().setCursor(x0, 48);
|
|
||||||
getdisplay().print("Tracker configuration");
|
|
||||||
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
|
|
||||||
// Boat data left column
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
|
||||||
getdisplay().setCursor(x0, 75);
|
|
||||||
getdisplay().print("Boat data");
|
|
||||||
|
|
||||||
y0 = 96;
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
getdisplay().setCursor(x0, y0);
|
|
||||||
getdisplay().print("Boat name");
|
|
||||||
getdisplay().setCursor(x1, y0);
|
|
||||||
getdisplay().print(boatName);
|
|
||||||
|
|
||||||
getdisplay().setCursor(x0, y0 + 16);
|
|
||||||
getdisplay().print("Boat class");
|
|
||||||
getdisplay().setCursor(x1, y0 + 16);
|
|
||||||
getdisplay().print(boatClass);
|
|
||||||
|
|
||||||
getdisplay().setCursor(x0, y0 + 32);
|
|
||||||
getdisplay().print("Handicap");
|
|
||||||
getdisplay().setCursor(x1, y0 + 32);
|
|
||||||
getdisplay().print(boatHandicap, 1);
|
|
||||||
|
|
||||||
getdisplay().setCursor(x0, y0 + 48);
|
|
||||||
getdisplay().print("Sail club");
|
|
||||||
getdisplay().setCursor(x1, y0 + 48);
|
|
||||||
getdisplay().print(sailClub);
|
|
||||||
|
|
||||||
getdisplay().setCursor(x0, y0 + 64);
|
|
||||||
getdisplay().print("Sail number");
|
|
||||||
getdisplay().setCursor(x1, y0 + 64);
|
|
||||||
getdisplay().print(boatSailNumber);
|
|
||||||
|
|
||||||
// Tracker data, right column
|
|
||||||
x0 = 208;
|
|
||||||
x1 = 304;
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
|
||||||
getdisplay().setCursor(x0, 75);
|
|
||||||
getdisplay().print("Tracker info");
|
|
||||||
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
|
|
||||||
getdisplay().setCursor(x0, y0);
|
|
||||||
getdisplay().print("Status");
|
|
||||||
getdisplay().setCursor(x1, y0);
|
|
||||||
if (trackerType == "NONE") {
|
|
||||||
getdisplay().print("Disabled");
|
|
||||||
} else {
|
|
||||||
getdisplay().printf("Type: %s", trackerType);
|
|
||||||
}
|
|
||||||
|
|
||||||
getdisplay().setCursor(x0, y0 + 16);
|
|
||||||
getdisplay().print("Org.");
|
|
||||||
getdisplay().setCursor(x1, y0 + 16);
|
|
||||||
getdisplay().print(trackerOrganisation);
|
|
||||||
|
|
||||||
getdisplay().setCursor(x0, y0 + 32);
|
|
||||||
getdisplay().print("Team");
|
|
||||||
getdisplay().setCursor(x1, y0 + 32);
|
|
||||||
getdisplay().print(trackerTeam);
|
|
||||||
|
|
||||||
|
|
||||||
// Ragatta selection
|
|
||||||
y0 = 180;
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
|
||||||
getdisplay().setCursor(x0, y0);
|
|
||||||
getdisplay().print("Regattas");
|
|
||||||
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
|
|
||||||
// A) Regatta Hero:
|
|
||||||
// Server Hostname, IP, Port
|
|
||||||
// Organisation
|
|
||||||
// Boat name
|
|
||||||
//
|
|
||||||
|
|
||||||
// B) SD-Card: check if card available
|
|
||||||
// log interval: via config in seconds. min=?
|
|
||||||
|
|
||||||
// C) Server: e.g. Raspi in Boat WLAN, own Internet-Server
|
|
||||||
// display connection state to server here
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
PageTracker(CommonData &common)
|
|
||||||
{
|
|
||||||
commonData = &common;
|
|
||||||
common.logger->logDebug(GwLog::LOG, "Instantiate PageTracker");
|
|
||||||
flashLED = common.config->getString(common.config->flashLED);
|
|
||||||
simulation = common.config->getBool(common.config->useSimuData);
|
|
||||||
|
|
||||||
trackerType = common.config->getString(common.config->trackerType);
|
|
||||||
trackerOrganisation = common.config->getString(common.config->trackerOrg);
|
|
||||||
trackerTeam = common.config->getString(common.config->trackerTeam);
|
|
||||||
|
|
||||||
boatName = common.config->getString(common.config->boatName);
|
|
||||||
boatClass = common.config->getString(common.config->boatClass);
|
|
||||||
boatSailNumber = common.config->getString(common.config->boatSailnumber);
|
|
||||||
sailClub = common.config->getString(common.config->sailClub);
|
|
||||||
boatHandicap = common.config->getString(common.config->boatHandicap).toFloat();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupKeys(){
|
|
||||||
Page::setupKeys();
|
|
||||||
commonData->keydata[0].label = "MODE";
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
commonData->keylock = !commonData->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){
|
|
||||||
GwLog *logger = commonData->logger;
|
|
||||||
|
|
||||||
// Logging boat values
|
|
||||||
logger->logDebug(GwLog::LOG, "Drawing at PageTracker; Mode=%c", mode);
|
|
||||||
|
|
||||||
// Set display in partial refresh mode
|
|
||||||
getdisplay().setPartialWindow(0, 0,getdisplay().width(), getdisplay().height());
|
|
||||||
|
|
||||||
if (mode == 'N') {
|
|
||||||
displayModeNormal(pageData);
|
|
||||||
} else if (mode == 'C') {
|
|
||||||
displayModeConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
return PAGE_UPDATE;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
static Page *createPage(CommonData &common){
|
|
||||||
return new PageTracker(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 registerPageTracker(
|
|
||||||
"Tracker", // Page name
|
|
||||||
createPage, // Action
|
|
||||||
0, // Number of bus values depends on selection in Web configuration
|
|
||||||
{"LAT", "LON", "SOG"}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
|
|
||||||
true // Show display header on/off
|
|
||||||
);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -3,176 +3,327 @@
|
|||||||
#include "Pagedata.h"
|
#include "Pagedata.h"
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "BoatDataCalibration.h"
|
#include "BoatDataCalibration.h"
|
||||||
|
#include "OBPDataOperations.h"
|
||||||
|
#include "OBPcharts.h"
|
||||||
|
|
||||||
class PageTwoValues : public Page
|
class PageTwoValues : public Page {
|
||||||
{
|
private:
|
||||||
public:
|
GwLog* logger;
|
||||||
PageTwoValues(CommonData &common){
|
|
||||||
commonData = &common;
|
enum PageMode {
|
||||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageTwoValue");
|
VALUES,
|
||||||
|
VAL1_CHART,
|
||||||
|
VAL2_CHART,
|
||||||
|
CHARTS
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
|
||||||
|
static constexpr int YOFFSET = 130; // y offset for display of 2nd boat value
|
||||||
|
|
||||||
|
int width; // Screen width
|
||||||
|
int height; // Screen height
|
||||||
|
|
||||||
|
bool keylock = false; // Keylock
|
||||||
|
PageMode pageMode = VALUES; // 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;
|
||||||
|
|
||||||
|
// Data buffer pointer (owned by HstryBuffers)
|
||||||
|
static constexpr int NUMVALUES = 2; // two data values in this page
|
||||||
|
RingBuffer<uint16_t>* dataHstryBuf[NUMVALUES] = { nullptr };
|
||||||
|
std::unique_ptr<Chart> dataChart[NUMVALUES]; // Chart object
|
||||||
|
|
||||||
|
// Old values for hold function
|
||||||
|
String sValueOld[NUMVALUES] = { "", "" };
|
||||||
|
String unitOld[NUMVALUES] = { "", "" };
|
||||||
|
|
||||||
|
// display data values in display <mode> [FULL|HALF]
|
||||||
|
void showData(const std::vector<GwApi::BoatValue*>& bValue, DisplayMode mode)
|
||||||
|
{
|
||||||
|
getdisplay().setTextColor(commonData->fgcolor);
|
||||||
|
|
||||||
|
int numValues = bValue.size(); // do we have to handle 1 or 2 values?
|
||||||
|
|
||||||
|
for (int i = 0; i < numValues; i++) {
|
||||||
|
int yOffset = YOFFSET * i;
|
||||||
|
String name = xdrDelete(bValue[i]->getName()); // Value name
|
||||||
|
name = name.substring(0, 6); // String length limit for value name
|
||||||
|
calibrationData.calibrateInstance(bValue[i], logger); // Check if boat data value is to be calibrated
|
||||||
|
double value = bValue[i]->value; // Value as double in SI unit
|
||||||
|
bool valid = bValue[i]->valid; // Valid information
|
||||||
|
String sValue = formatValue(bValue[i], *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||||
|
String unit = formatValue(bValue[i], *commonData).unit; // Unit of value
|
||||||
|
|
||||||
|
// Show name
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||||
|
getdisplay().setCursor(20, 75 + yOffset);
|
||||||
|
getdisplay().print(name); // name
|
||||||
|
|
||||||
|
// Show unit
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||||
|
getdisplay().setCursor(20, 125 + yOffset);
|
||||||
|
|
||||||
|
if (holdValues) {
|
||||||
|
getdisplay().print(unitOld[i]); // name
|
||||||
|
} else {
|
||||||
|
getdisplay().print(unit); // name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch font depending on value format and adjust position
|
||||||
|
if (bValue[i]->getFormat() == "formatLatitude" || bValue[i]->getFormat() == "formatLongitude") {
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||||
|
getdisplay().setCursor(50, 125 + yOffset);
|
||||||
|
} else if (bValue[i]->getFormat() == "formatTime" || bValue[i]->getFormat() == "formatDate") {
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||||
|
getdisplay().setCursor(170, 105 + yOffset);
|
||||||
|
} else { // Default font for other formats
|
||||||
|
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
|
||||||
|
getdisplay().setCursor(180, 125 + yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show bus data
|
||||||
|
if (!holdValues || useSimuData) {
|
||||||
|
getdisplay().print(sValue); // Real value as formated string
|
||||||
|
} else {
|
||||||
|
getdisplay().print(sValueOld[i]); // Old value as formated string
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid == true) {
|
||||||
|
sValueOld[i] = sValue; // Save the old value
|
||||||
|
unitOld[i] = unit; // Save the old unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numValues == 2 && mode == FULL) { // print line only, if we want to show 2 data values
|
||||||
|
getdisplay().fillRect(0, 145, width, 3, commonData->fgcolor); // Horizontal line 3 pix
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int handleKey(int key){
|
public:
|
||||||
// Code for keylock
|
PageTwoValues(CommonData& common)
|
||||||
if(key == 11){
|
{
|
||||||
|
commonData = &common;
|
||||||
|
logger = commonData->logger;
|
||||||
|
LOG_DEBUG(GwLog::LOG, "Instantiate PageTwoValues");
|
||||||
|
|
||||||
|
width = getdisplay().width(); // Screen width
|
||||||
|
height = getdisplay().height(); // Screen height
|
||||||
|
|
||||||
|
// 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]
|
||||||
|
}
|
||||||
|
|
||||||
|
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[0] || dataHstryBuf[1]) { // show "Mode" key only if at least 1 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[0] || dataHstryBuf[1]) { // if at least 1 boat data type supports charts
|
||||||
|
|
||||||
|
// Set page mode: value | value/half chart | full charts
|
||||||
|
if (key == 1) {
|
||||||
|
switch (pageMode) {
|
||||||
|
|
||||||
|
case VALUES:
|
||||||
|
|
||||||
|
if (dataHstryBuf[0]) {
|
||||||
|
pageMode = VAL1_CHART;
|
||||||
|
} else if (dataHstryBuf[1]) {
|
||||||
|
pageMode = VAL2_CHART;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VAL1_CHART:
|
||||||
|
|
||||||
|
if (dataHstryBuf[1]) {
|
||||||
|
pageMode = VAL2_CHART;
|
||||||
|
} else {
|
||||||
|
pageMode = CHARTS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VAL2_CHART:
|
||||||
|
pageMode = CHARTS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHARTS:
|
||||||
|
pageMode = VALUES;
|
||||||
|
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
|
||||||
commonData->keylock = !commonData->keylock;
|
commonData->keylock = !commonData->keylock;
|
||||||
return 0; // Commit the key
|
return 0; // Commit the key
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
int displayPage(PageData &pageData){
|
virtual void displayNew(PageData& pageData)
|
||||||
GwConfigHandler *config = commonData->config;
|
{
|
||||||
GwLog *logger = commonData->logger;
|
#ifdef BOARD_OBP60S3
|
||||||
|
// Clear optical warning
|
||||||
// Old values for hold function
|
if (flashLED == "Limit Violation") {
|
||||||
static String svalue1old = "";
|
|
||||||
static String unit1old = "";
|
|
||||||
static String svalue2old = "";
|
|
||||||
static String unit2old = "";
|
|
||||||
|
|
||||||
// Get config data
|
|
||||||
String lengthformat = config->getString(config->lengthFormat);
|
|
||||||
// bool simulation = config->getBool(config->useSimuData);
|
|
||||||
bool holdvalues = config->getBool(config->holdvalues);
|
|
||||||
String flashLED = config->getString(config->flashLED);
|
|
||||||
String backlightMode = config->getString(config->backlight);
|
|
||||||
|
|
||||||
// Get boat values #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
|
|
||||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
|
||||||
double value1 = bvalue1->value; // Value as double in SI unit
|
|
||||||
bool valid1 = bvalue1->valid; // Valid information
|
|
||||||
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
|
||||||
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
|
|
||||||
|
|
||||||
// Get boat values #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
|
|
||||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
|
||||||
double value2 = bvalue2->value; // Value as double in SI unit
|
|
||||||
bool valid2 = bvalue2->valid; // Valid information
|
|
||||||
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
|
||||||
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
|
|
||||||
|
|
||||||
// Optical warning by limit violation (unused)
|
|
||||||
if(String(flashLED) == "Limit Violation"){
|
|
||||||
setBlinkingLED(false);
|
setBlinkingLED(false);
|
||||||
setFlashLED(false);
|
setFlashLED(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// buffer initialization will fail, if page is default page, because <displayNew> is not executed at system start for default page
|
||||||
|
for (int i = 0; i < NUMVALUES; i++) {
|
||||||
|
if (!dataChart[i]) { // Create chart objects if they don't exist
|
||||||
|
|
||||||
|
GwApi::BoatValue* bValue = pageData.values[i]; // Page boat data element
|
||||||
|
String bValName = bValue->getName(); // Value name
|
||||||
|
String bValFormat = bValue->getFormat(); // Value format
|
||||||
|
|
||||||
|
dataHstryBuf[i] = pageData.hstryBuffers->getBuffer(bValName);
|
||||||
|
|
||||||
|
if (dataHstryBuf[i]) {
|
||||||
|
dataChart[i].reset(new Chart(*dataHstryBuf[i], Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: Created chart object%d for %s", i, bValName.c_str());
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: No chart object available for %s", bValName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging boat values
|
setupKeys(); // adjust <mode> key depending on chart supported boat data type
|
||||||
if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement?
|
}
|
||||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageTwoValues, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2);
|
|
||||||
|
int displayPage(PageData& pageData)
|
||||||
|
{
|
||||||
|
LOG_DEBUG(GwLog::LOG, "Display PageTwoValues");
|
||||||
|
|
||||||
|
// Get boat values for page
|
||||||
|
std::vector<GwApi::BoatValue*> bValue;
|
||||||
|
bValue.push_back(pageData.values[0]); // Page boat data element 1
|
||||||
|
bValue.push_back(pageData.values[1]); // Page boat data element 2
|
||||||
|
|
||||||
|
// Optical warning by limit violation (unused)
|
||||||
|
if (String(flashLED) == "Limit Violation") {
|
||||||
|
setBlinkingLED(false);
|
||||||
|
setFlashLED(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bValue[0] == NULL && bValue[1] == NULL)
|
||||||
|
return PAGE_OK; // no data, no page to display
|
||||||
|
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: printing #1: %s, %.3f, #2: %s, %.3f",
|
||||||
|
bValue[0]->getName().c_str(), bValue[0]->value, bValue[1]->getName().c_str(), bValue[1]->value);
|
||||||
|
|
||||||
// Draw page
|
// Draw page
|
||||||
//***********************************************************
|
//***********************************************************
|
||||||
|
|
||||||
// Set display in partial refresh mode
|
getdisplay().setPartialWindow(0, 0, width, height); // Set partial update
|
||||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
|
||||||
|
|
||||||
// ############### Value 1 ################
|
if (pageMode == VALUES || (dataHstryBuf[0] == nullptr && dataHstryBuf[1] == nullptr)) {
|
||||||
|
// show only data value; ignore other pageMode options if no chart supported boat data history buffer is available
|
||||||
|
showData(bValue, FULL);
|
||||||
|
|
||||||
// Show name
|
} else if (pageMode == VAL1_CHART) { // show data value 1 and chart
|
||||||
getdisplay().setTextColor(commonData->fgcolor);
|
showData({bValue[0]}, HALF);
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
if (dataChart[0]) {
|
||||||
getdisplay().setCursor(20, 80);
|
dataChart[0]->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, NO_PRNT_NAME, NO_PRNT_VALUE, *bValue[0]);
|
||||||
getdisplay().print(name1); // Page name
|
}
|
||||||
|
|
||||||
// Show unit
|
} else if (pageMode == VAL2_CHART) { // show data value 2 and chart
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
showData({bValue[1]}, HALF);
|
||||||
getdisplay().setCursor(20, 130);
|
if (dataChart[1]) {
|
||||||
if(holdvalues == false){
|
dataChart[1]->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, NO_PRNT_NAME, NO_PRNT_VALUE, *bValue[1]);
|
||||||
getdisplay().print(unit1); // Unit
|
}
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().print(unit1old);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch font if format for any values
|
} else if (pageMode == CHARTS) { // show both data charts
|
||||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
if (dataChart[0]) {
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
if (dataChart[1]) {
|
||||||
getdisplay().setCursor(50, 130);
|
dataChart[0]->showChrt(HORIZONTAL, HALF_SIZE_TOP, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[0]);
|
||||||
}
|
} else {
|
||||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
dataChart[0]->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[0]);
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
}
|
||||||
getdisplay().setCursor(170, 105);
|
}
|
||||||
}
|
if (dataChart[1]) {
|
||||||
else{
|
if (dataChart[0]) {
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
|
dataChart[1]->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[1]);
|
||||||
getdisplay().setCursor(180, 130);
|
} else {
|
||||||
}
|
dataChart[1]->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[1]);
|
||||||
|
}
|
||||||
// Show bus data
|
}
|
||||||
if(holdvalues == false){
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// ############### Horizontal Line ################
|
|
||||||
|
|
||||||
// Horizontal line 3 pix
|
|
||||||
getdisplay().fillRect(0, 145, 400, 3, commonData->fgcolor);
|
|
||||||
|
|
||||||
// ############### Value 2 ################
|
|
||||||
|
|
||||||
// Show name
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
|
||||||
getdisplay().setCursor(20, 190);
|
|
||||||
getdisplay().print(name2); // Page name
|
|
||||||
|
|
||||||
// Show unit
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
|
||||||
getdisplay().setCursor(20, 240);
|
|
||||||
if(holdvalues == false){
|
|
||||||
getdisplay().print(unit2); // Unit
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().print(unit2old);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch font if format for any values
|
|
||||||
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
|
||||||
getdisplay().setCursor(50, 240);
|
|
||||||
}
|
|
||||||
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
|
||||||
getdisplay().setCursor(170, 215);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
|
|
||||||
getdisplay().setCursor(180, 240);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show bus data
|
|
||||||
if(holdvalues == false){
|
|
||||||
getdisplay().print(svalue2); // Real value as formated string
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().print(svalue2old); // Old value as formated string
|
|
||||||
}
|
|
||||||
if(valid2 == true){
|
|
||||||
svalue2old = svalue2; // Save the old value
|
|
||||||
unit2old = unit2; // Save the old unit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PAGE_UPDATE;
|
return PAGE_UPDATE;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
static Page *createPage(CommonData &common){
|
static Page* createPage(CommonData& common)
|
||||||
|
{
|
||||||
return new PageTwoValues(common);
|
return new PageTwoValues(common);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* with the code below we make this page known to the PageTask
|
* 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 give it a type (name) that can be selected in the config
|
||||||
@@ -181,10 +332,10 @@ static Page *createPage(CommonData &common){
|
|||||||
* this will be number of BoatValue pointers in pageData.values
|
* this will be number of BoatValue pointers in pageData.values
|
||||||
*/
|
*/
|
||||||
PageDescription registerPageTwoValues(
|
PageDescription registerPageTwoValues(
|
||||||
"TwoValues", // Page name
|
"TwoValues", // Page name
|
||||||
createPage, // Action
|
createPage, // Action
|
||||||
2, // Number of bus values depends on selection in Web configuration
|
2, // Number of bus values depends on selection in Web configuration
|
||||||
true // Show display header on/off
|
true // Show display header on/off
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -247,8 +247,8 @@ public:
|
|||||||
if(key == 1){ // Mode switch
|
if(key == 1){ // Mode switch
|
||||||
if(mode == 'N'){
|
if(mode == 'N'){
|
||||||
mode = 'L';
|
mode = 'L';
|
||||||
} else if (mode == 'L') {
|
// } else if (mode == 'L') {
|
||||||
mode = 'X';
|
// mode = 'X';
|
||||||
} else {
|
} else {
|
||||||
mode = 'N';
|
mode = 'N';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,97 +2,76 @@
|
|||||||
|
|
||||||
#include "Pagedata.h"
|
#include "Pagedata.h"
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "OBPRingBuffer.h"
|
|
||||||
#include "OBPDataOperations.h"
|
#include "OBPDataOperations.h"
|
||||||
#include "BoatDataCalibration.h"
|
#include "OBPcharts.h"
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
static const double radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees
|
|
||||||
|
|
||||||
// Get maximum difference of last <amount> of TWD ringbuffer values to center chart; returns "0" if data is not valid
|
|
||||||
int getCntr(const RingBuffer<int16_t>& windDirHstry, size_t amount)
|
|
||||||
{
|
|
||||||
const int MAX_VAL = windDirHstry.getMaxVal();
|
|
||||||
size_t count = windDirHstry.getCurrentSize();
|
|
||||||
|
|
||||||
if (windDirHstry.isEmpty() || amount <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (amount > count)
|
|
||||||
amount = count;
|
|
||||||
|
|
||||||
uint16_t midWndDir, minWndDir, maxWndDir = 0;
|
|
||||||
int wndCenter = 0;
|
|
||||||
|
|
||||||
midWndDir = windDirHstry.getMid(amount);
|
|
||||||
if (midWndDir != MAX_VAL) {
|
|
||||||
midWndDir = midWndDir / 1000.0 * radToDeg;
|
|
||||||
wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value
|
|
||||||
minWndDir = windDirHstry.getMin(amount) / 1000.0 * radToDeg;
|
|
||||||
maxWndDir = windDirHstry.getMax(amount) / 1000.0 * radToDeg;
|
|
||||||
if ((maxWndDir - minWndDir) > 180 && !(minWndDir > maxWndDir)) { // if wind range is > 180 and no 0° crossover, adjust wndCenter to smaller wind range end
|
|
||||||
wndCenter = WindUtils::to360(wndCenter + 180);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return wndCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get maximum difference of last <amount> of TWD ringbuffer values to center chart
|
|
||||||
int getRng(const RingBuffer<int16_t>& windDirHstry, int center, size_t amount)
|
|
||||||
{
|
|
||||||
int minVal = windDirHstry.getMinVal();
|
|
||||||
const int MAX_VAL = windDirHstry.getMaxVal();
|
|
||||||
size_t count = windDirHstry.getCurrentSize();
|
|
||||||
|
|
||||||
if (windDirHstry.isEmpty() || amount <= 0) {
|
|
||||||
return MAX_VAL;
|
|
||||||
}
|
|
||||||
if (amount > count)
|
|
||||||
amount = count;
|
|
||||||
|
|
||||||
int value = 0;
|
|
||||||
int rng = 0;
|
|
||||||
int maxRng = minVal;
|
|
||||||
// Start from the newest value (last) and go backwards x times
|
|
||||||
for (size_t i = 0; i < amount; i++) {
|
|
||||||
value = windDirHstry.get(count - 1 - i);
|
|
||||||
|
|
||||||
if (value == MAX_VAL) {
|
|
||||||
continue; // ignore invalid values
|
|
||||||
}
|
|
||||||
|
|
||||||
value = value / 1000.0 * radToDeg;
|
|
||||||
rng = abs(((value - center + 540) % 360) - 180);
|
|
||||||
if (rng > maxRng)
|
|
||||||
maxRng = rng;
|
|
||||||
}
|
|
||||||
if (maxRng > 180) {
|
|
||||||
maxRng = 180;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (maxRng != minVal ? maxRng : MAX_VAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ****************************************************************
|
// ****************************************************************
|
||||||
class PageWindPlot : public Page {
|
class PageWindPlot : public Page {
|
||||||
|
|
||||||
|
private:
|
||||||
|
GwLog* logger;
|
||||||
|
|
||||||
|
enum ChartMode {
|
||||||
|
DIRECTION,
|
||||||
|
SPEED,
|
||||||
|
BOTH
|
||||||
|
};
|
||||||
|
|
||||||
|
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 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
|
bool keylock = false; // Keylock
|
||||||
char chrtMode = 'D'; // Chart mode: 'D' for TWD, 'S' for TWS, 'B' for both
|
ChartMode chrtMode = DIRECTION;
|
||||||
bool showTruW = true; // Show true wind or apparant wind in chart area
|
bool showTruW = true; // Show true wind or apparent wind in chart area
|
||||||
bool oldShowTruW = false; // remember recent user selection of wind data type
|
bool oldShowTruW = false; // remember recent user selection of wind data type
|
||||||
|
|
||||||
int dataIntv = 1; // Update interval for wind history chart:
|
int8_t dataIntv = 1; // Update interval for wind history chart:
|
||||||
// (1)|(2)|(3)|(4) seconds for approx. 4, 8, 12, 16 min. history chart
|
// (1)|(2)|(3)|(4)|(8) x 240 seconds for 4, 8, 12, 16, 32 min. history chart
|
||||||
bool useSimuData;
|
bool useSimuData;
|
||||||
|
// bool holdValues;
|
||||||
String flashLED;
|
String flashLED;
|
||||||
String backlightMode;
|
String backlightMode;
|
||||||
|
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
String wndSrc; // Wind source true/apparent wind - preselection for OBP40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Data buffers pointers (owned by HstryBuffers)
|
||||||
|
RingBuffer<uint16_t>* twdHstry = nullptr;
|
||||||
|
RingBuffer<uint16_t>* twsHstry = nullptr;
|
||||||
|
RingBuffer<uint16_t>* awdHstry = nullptr;
|
||||||
|
RingBuffer<uint16_t>* awsHstry = nullptr;
|
||||||
|
|
||||||
|
// Chart objects
|
||||||
|
std::unique_ptr<Chart> twdChart, awdChart; // Chart object for wind direction
|
||||||
|
std::unique_ptr<Chart> twsChart, awsChart; // Chart object for wind speed
|
||||||
|
|
||||||
|
// Active charts and values
|
||||||
|
Chart* wdChart = nullptr;
|
||||||
|
Chart* wsChart = nullptr;
|
||||||
|
GwApi::BoatValue* wdBVal = nullptr;
|
||||||
|
GwApi::BoatValue* wsBVal = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PageWindPlot(CommonData& common)
|
PageWindPlot(CommonData& common)
|
||||||
{
|
{
|
||||||
commonData = &common;
|
commonData = &common;
|
||||||
common.logger->logDebug(GwLog::LOG, "Instantiate PageWindPlot");
|
logger = commonData->logger;
|
||||||
|
LOG_DEBUG(GwLog::LOG, "Instantiate PageWindPlot");
|
||||||
|
|
||||||
|
width = getdisplay().width(); // Screen width
|
||||||
|
height = getdisplay().height(); // Screen height
|
||||||
|
|
||||||
// Get config data
|
// Get config data
|
||||||
useSimuData = common.config->getBool(common.config->useSimuData);
|
useSimuData = common.config->getBool(common.config->useSimuData);
|
||||||
@@ -100,31 +79,32 @@ public:
|
|||||||
flashLED = common.config->getString(common.config->flashLED);
|
flashLED = common.config->getString(common.config->flashLED);
|
||||||
backlightMode = common.config->getString(common.config->backlight);
|
backlightMode = common.config->getString(common.config->backlight);
|
||||||
|
|
||||||
|
oldShowTruW = !showTruW; // makes wind source being initialized at initial page call
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupKeys()
|
virtual void setupKeys()
|
||||||
{
|
{
|
||||||
Page::setupKeys();
|
Page::setupKeys();
|
||||||
// commonData->keydata[0].label = "MODE";
|
commonData->keydata[0].label = "MODE";
|
||||||
#if defined BOARD_OBP60S3
|
#if defined BOARD_OBP60S3
|
||||||
commonData->keydata[1].label = "SRC";
|
commonData->keydata[1].label = "SRC";
|
||||||
commonData->keydata[4].label = "INTV";
|
commonData->keydata[4].label = "ZOOM";
|
||||||
#elif defined BOARD_OBP40S3
|
#elif defined BOARD_OBP40S3
|
||||||
commonData->keydata[1].label = "INTV";
|
commonData->keydata[1].label = "ZOOM";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key functions
|
// Key functions
|
||||||
virtual int handleKey(int key)
|
virtual int handleKey(int key)
|
||||||
{
|
{
|
||||||
// Set chart mode TWD | TWS -> to be implemented
|
// Set chart mode
|
||||||
if (key == 1) {
|
if (key == 1) {
|
||||||
if (chrtMode == 'D') {
|
if (chrtMode == DIRECTION) {
|
||||||
chrtMode = 'S';
|
chrtMode = SPEED;
|
||||||
} else if (chrtMode == 'S') {
|
} else if (chrtMode == SPEED) {
|
||||||
chrtMode = 'B';
|
chrtMode = BOTH;
|
||||||
} else {
|
} else {
|
||||||
chrtMode = 'D';
|
chrtMode = DIRECTION;
|
||||||
}
|
}
|
||||||
return 0; // Commit the key
|
return 0; // Commit the key
|
||||||
}
|
}
|
||||||
@@ -147,6 +127,8 @@ public:
|
|||||||
dataIntv = 3;
|
dataIntv = 3;
|
||||||
} else if (dataIntv == 3) {
|
} else if (dataIntv == 3) {
|
||||||
dataIntv = 4;
|
dataIntv = 4;
|
||||||
|
} else if (dataIntv == 4) {
|
||||||
|
dataIntv = 8;
|
||||||
} else {
|
} else {
|
||||||
dataIntv = 1;
|
dataIntv = 1;
|
||||||
}
|
}
|
||||||
@@ -161,349 +143,109 @@ public:
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void displayNew(PageData &pageData){
|
virtual void displayNew(PageData& pageData)
|
||||||
|
{
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
|
// Clear optical warning
|
||||||
|
if (flashLED == "Limit Violation") {
|
||||||
|
setBlinkingLED(false);
|
||||||
|
setFlashLED(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef BOARD_OBP40S3
|
#ifdef BOARD_OBP40S3
|
||||||
String wndSrc; // Wind source true/apparant wind - preselection for OBP40
|
// we can only initialize user defined wind source here, because "pageData" is not available at object instantiation
|
||||||
|
|
||||||
wndSrc = commonData->config->getString("page" + String(pageData.pageNumber) + "wndsrc");
|
wndSrc = commonData->config->getString("page" + String(pageData.pageNumber) + "wndsrc");
|
||||||
if (wndSrc =="True wind") {
|
if (wndSrc == "True wind") {
|
||||||
showTruW = true;
|
showTruW = true;
|
||||||
} else {
|
} else {
|
||||||
showTruW = false; // Wind source is apparant wind
|
showTruW = false; // Wind source is apparent wind
|
||||||
}
|
}
|
||||||
commonData->logger->logDebug(GwLog::LOG,"New PageWindPlot: wind source=%s", wndSrc);
|
oldShowTruW = !showTruW; // Force chart update in displayPage
|
||||||
#endif
|
#endif
|
||||||
oldShowTruW = !showTruW; // makes wind source being initialized at initial page call
|
|
||||||
|
if (!twdChart) { // Create true wind charts if they don't exist
|
||||||
|
twdHstry = pageData.hstryBuffers->getBuffer("TWD");
|
||||||
|
twsHstry = pageData.hstryBuffers->getBuffer("TWS");
|
||||||
|
|
||||||
|
if (twdHstry) {
|
||||||
|
twdChart.reset(new Chart(*twdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
|
||||||
|
}
|
||||||
|
if (twsHstry) {
|
||||||
|
twsChart.reset(new Chart(*twsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!awdChart) { // Create apparent wind charts if they don't exist
|
||||||
|
awdHstry = pageData.hstryBuffers->getBuffer("AWD");
|
||||||
|
awsHstry = pageData.hstryBuffers->getBuffer("AWS");
|
||||||
|
|
||||||
|
if (awdHstry) {
|
||||||
|
awdChart.reset(new Chart(*awdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
|
||||||
|
}
|
||||||
|
if (awsHstry) {
|
||||||
|
awsChart.reset(new Chart(*awsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
|
||||||
|
}
|
||||||
|
if (twdHstry && twsHstry && awdHstry && awsHstry) {
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Created wind charts");
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Some/all chart objects for wind data missing");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int displayPage(PageData& pageData)
|
int displayPage(PageData& pageData)
|
||||||
{
|
{
|
||||||
GwConfigHandler* config = commonData->config;
|
|
||||||
GwLog* logger = commonData->logger;
|
|
||||||
|
|
||||||
static RingBuffer<int16_t>* wdHstry; // Wind direction data buffer
|
|
||||||
static RingBuffer<uint16_t>* wsHstry; // Wind speed data buffer
|
|
||||||
static String wdName, wdFormat; // Wind direction name and format
|
|
||||||
static String wsName, wsFormat; // Wind speed name and format
|
|
||||||
static int16_t wdMAX_VAL; // Max. value of wd history buffer, indicating invalid values
|
|
||||||
float wsValue; // Wind speed value in chart area
|
|
||||||
String wsUnit; // Wind speed unit in chart area
|
|
||||||
static GwApi::BoatValue* wsBVal = new GwApi::BoatValue("TWS"); // temp BoatValue for wind speed unit identification; required by OBP60Formater
|
|
||||||
|
|
||||||
// current boat data values; TWD/AWD only for validation test
|
|
||||||
const int numBoatData = 2;
|
|
||||||
GwApi::BoatValue* bvalue;
|
|
||||||
bool BDataValid[numBoatData];
|
|
||||||
|
|
||||||
static bool isInitialized = false; // Flag to indicate that page is initialized
|
|
||||||
static bool wndDataValid = false; // Flag to indicate if wind data is valid
|
|
||||||
static int numNoData; // Counter for multiple invalid data values in a row
|
|
||||||
|
|
||||||
static int width; // Screen width
|
|
||||||
static int height; // Screen height
|
|
||||||
static int xCenter; // Center of screen in x direction
|
|
||||||
static const int yOffset = 48; // Offset for y coordinates of chart area
|
|
||||||
static int cHeight; // height of chart area
|
|
||||||
static int bufSize; // History buffer size: 960 values for appox. 16 min. history chart
|
|
||||||
static int intvBufSize; // Buffer size used for currently selected time interval
|
|
||||||
int count; // current size of buffer
|
|
||||||
static int numWndVals; // number of wind values available for current interval selection
|
|
||||||
static 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
|
|
||||||
static size_t lastIdx; // Last index of TWD history buffer
|
|
||||||
static size_t lastAddedIdx = 0; // Last index of TWD history buffer when new data was added
|
|
||||||
static int oldDataIntv; // remember recent user selection of data interval
|
|
||||||
|
|
||||||
static int wndCenter; // chart wind center value position
|
|
||||||
static int wndLeft; // chart wind left value position
|
|
||||||
static int wndRight; // chart wind right value position
|
|
||||||
static int chrtRng; // Range of wind values from mid wind value to min/max wind value in degrees
|
|
||||||
int diffRng; // Difference between mid and current wind value
|
|
||||||
static const int dfltRng = 60; // Default range for chart
|
|
||||||
int midWndDir; // New value for wndCenter after chart start / shift
|
|
||||||
|
|
||||||
int x, y; // x and y coordinates for drawing
|
|
||||||
static int prevX, prevY; // Last x and y coordinates for drawing
|
|
||||||
static float chrtScl; // Scale for wind values in pixels per degree
|
|
||||||
int chrtVal; // Current wind value
|
|
||||||
static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line
|
|
||||||
|
|
||||||
LOG_DEBUG(GwLog::LOG, "Display PageWindPlot");
|
LOG_DEBUG(GwLog::LOG, "Display PageWindPlot");
|
||||||
ulong timer = millis();
|
ulong pageTime = millis();
|
||||||
|
|
||||||
if (!isInitialized) {
|
|
||||||
width = getdisplay().width();
|
|
||||||
height = getdisplay().height();
|
|
||||||
xCenter = width / 2;
|
|
||||||
cHeight = height - yOffset - 22;
|
|
||||||
numNoData = 0;
|
|
||||||
bufStart = 0;
|
|
||||||
oldDataIntv = 0;
|
|
||||||
wsValue = 0;
|
|
||||||
numAddedBufVals, currIdx, lastIdx = 0;
|
|
||||||
wndCenter = INT_MAX;
|
|
||||||
midWndDir = 0;
|
|
||||||
diffRng = dfltRng;
|
|
||||||
chrtRng = dfltRng;
|
|
||||||
|
|
||||||
isInitialized = true; // Set flag to indicate that page is now initialized
|
|
||||||
}
|
|
||||||
|
|
||||||
// read boat data values; TWD only for validation test, TWS for display of current value
|
|
||||||
for (int i = 0; i < numBoatData; i++) {
|
|
||||||
bvalue = pageData.values[i];
|
|
||||||
BDataValid[i] = bvalue->valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optical warning by limit violation (unused)
|
|
||||||
if (String(flashLED) == "Limit Violation") {
|
|
||||||
setBlinkingLED(false);
|
|
||||||
setFlashLED(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showTruW != oldShowTruW) {
|
if (showTruW != oldShowTruW) {
|
||||||
|
|
||||||
|
// Switch active charts based on showTruW
|
||||||
if (showTruW) {
|
if (showTruW) {
|
||||||
wdHstry = pageData.boatHstry->hstryBufList.twdHstry;
|
wdChart = twdChart.get();
|
||||||
wsHstry = pageData.boatHstry->hstryBufList.twsHstry;
|
wsChart = twsChart.get();
|
||||||
|
wdBVal = pageData.values[0];
|
||||||
|
wsBVal = pageData.values[1];
|
||||||
} else {
|
} else {
|
||||||
wdHstry = pageData.boatHstry->hstryBufList.awdHstry;
|
wdChart = awdChart.get();
|
||||||
wsHstry = pageData.boatHstry->hstryBufList.awsHstry;
|
wsChart = awsChart.get();
|
||||||
|
wdBVal = pageData.values[2];
|
||||||
|
wsBVal = pageData.values[3];
|
||||||
}
|
}
|
||||||
wdHstry->getMetaData(wdName, wdFormat);
|
|
||||||
wsHstry->getMetaData(wsName, wsFormat);
|
|
||||||
wdMAX_VAL = wdHstry->getMaxVal();
|
|
||||||
bufSize = wdHstry->getCapacity();
|
|
||||||
wsBVal->setFormat(wsHstry->getFormat());
|
|
||||||
lastAddedIdx = wdHstry->getLastIdx();
|
|
||||||
|
|
||||||
oldShowTruW = showTruW;
|
oldShowTruW = showTruW;
|
||||||
}
|
}
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: draw with data %s: %.2f, %s: %.2f", wdBVal->getName().c_str(), wdBVal->value, wsBVal->getName().c_str(), wsBVal->value);
|
||||||
// Identify buffer size and buffer start position for chart
|
|
||||||
count = wdHstry->getCurrentSize();
|
|
||||||
currIdx = wdHstry->getLastIdx();
|
|
||||||
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
|
|
||||||
if (dataIntv != oldDataIntv || count == 1) {
|
|
||||||
// new data interval selected by user
|
|
||||||
intvBufSize = cHeight * dataIntv;
|
|
||||||
numWndVals = min(count, (cHeight - 60) * dataIntv);
|
|
||||||
bufStart = max(0, count - numWndVals);
|
|
||||||
lastAddedIdx = currIdx;
|
|
||||||
oldDataIntv = dataIntv;
|
|
||||||
} else {
|
|
||||||
numWndVals = numWndVals + numAddedBufVals;
|
|
||||||
lastAddedIdx = currIdx;
|
|
||||||
if (count == bufSize) {
|
|
||||||
bufStart = max(0, bufStart - numAddedBufVals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Dataset: count: %d, xWD: %.1f, xWS: %.2f, xWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, wind source: %s",
|
|
||||||
count, wdHstry->getLast() / 1000.0 * radToDeg, wsHstry->getLast() / 1000.0 * 1.94384, BDataValid[0], intvBufSize, numWndVals, bufStart, numAddedBufVals, wdHstry->getLastIdx(),
|
|
||||||
showTruW ? "True" : "App");
|
|
||||||
|
|
||||||
// Set wndCenter from 1st real buffer value
|
|
||||||
if (wndCenter == INT_MAX || (wndCenter == 0 && count == 1)) {
|
|
||||||
wndCenter = getCntr(*wdHstry, numWndVals);
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, xWD: %.1f, wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", count, wdHstry->getLast() / 1000.0 * radToDeg,
|
|
||||||
wndCenter, diffRng, chrtRng, wdHstry->getMin(numWndVals) / 1000.0 * radToDeg, wdHstry->getMax(numWndVals) / 1000.0 * radToDeg);
|
|
||||||
} else {
|
|
||||||
// check and adjust range between left, center, and right chart limit
|
|
||||||
diffRng = getRng(*wdHstry, wndCenter, numWndVals);
|
|
||||||
diffRng = (diffRng == wdMAX_VAL ? 0 : diffRng);
|
|
||||||
if (diffRng > chrtRng) {
|
|
||||||
chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 degree value
|
|
||||||
} else if (diffRng + 10 < chrtRng) { // Reduce chart range for higher resolution if possible
|
|
||||||
chrtRng = max(dfltRng, int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10);
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range adjust: wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", wndCenter, diffRng, chrtRng,
|
|
||||||
wdHstry->getMin(numWndVals) / 1000.0 * radToDeg, wdHstry->getMax(numWndVals) / 1000.0 * radToDeg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chrtScl = float(width) / float(chrtRng) / 2.0; // Chart scale: pixels per degree
|
|
||||||
wndLeft = wndCenter - chrtRng;
|
|
||||||
if (wndLeft < 0)
|
|
||||||
wndLeft += 360;
|
|
||||||
wndRight = (chrtRng < 180 ? wndCenter + chrtRng : wndCenter + chrtRng - 1);
|
|
||||||
if (wndRight >= 360)
|
|
||||||
wndRight -= 360;
|
|
||||||
|
|
||||||
// Draw page
|
// Draw page
|
||||||
//***********************************************************************
|
//***********************************************************
|
||||||
|
|
||||||
// Set display in partial refresh mode
|
// Set display in partial refresh mode
|
||||||
getdisplay().setPartialWindow(0, 0, width, height); // Set partial update
|
getdisplay().setPartialWindow(0, 0, width, height); // Set partial update
|
||||||
getdisplay().setTextColor(commonData->fgcolor);
|
getdisplay().setTextColor(commonData->fgcolor);
|
||||||
|
|
||||||
// chart lines
|
if (chrtMode == DIRECTION) {
|
||||||
getdisplay().fillRect(0, yOffset, width, 2, commonData->fgcolor);
|
if (wdChart) {
|
||||||
getdisplay().fillRect(xCenter, yOffset, 1, cHeight, commonData->fgcolor);
|
wdChart->showChrt(VERTICAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *wdBVal);
|
||||||
|
|
||||||
// chart labels
|
|
||||||
char sWndLbl[4]; // char buffer for Wind angle label
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
|
||||||
getdisplay().setCursor(xCenter - 88, yOffset - 3);
|
|
||||||
getdisplay().print(wdName); // Wind data name
|
|
||||||
snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter);
|
|
||||||
drawTextCenter(xCenter, yOffset - 11, sWndLbl);
|
|
||||||
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
|
|
||||||
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
|
|
||||||
getdisplay().setCursor(1, yOffset - 3);
|
|
||||||
snprintf(sWndLbl, 4, "%03d", (wndLeft < 0) ? (wndLeft + 360) : wndLeft);
|
|
||||||
getdisplay().print(sWndLbl); // Wind left value
|
|
||||||
getdisplay().drawCircle(46, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
|
|
||||||
getdisplay().drawCircle(46, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
|
|
||||||
getdisplay().setCursor(width - 50, yOffset - 3);
|
|
||||||
snprintf(sWndLbl, 4, "%03d", (wndRight < 0) ? (wndRight + 360) : wndRight);
|
|
||||||
getdisplay().print(sWndLbl); // Wind right value
|
|
||||||
getdisplay().drawCircle(width - 5, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
|
|
||||||
getdisplay().drawCircle(width - 5, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
|
|
||||||
|
|
||||||
if (wdHstry->getMax() == wdMAX_VAL) {
|
|
||||||
// only <MAX_VAL> values in buffer -> no valid wind data available
|
|
||||||
wndDataValid = false;
|
|
||||||
} else if (!BDataValid[0] && !useSimuData) {
|
|
||||||
// currently no valid xWD data available and no simulation mode
|
|
||||||
numNoData++;
|
|
||||||
wndDataValid = true;
|
|
||||||
if (numNoData > 3) {
|
|
||||||
// If more than 4 invalid values in a row, send message
|
|
||||||
wndDataValid = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
numNoData = 0; // reset data error counter
|
|
||||||
wndDataValid = true; // At least some wind data available
|
|
||||||
}
|
|
||||||
// Draw wind values in chart
|
|
||||||
//***********************************************************************
|
|
||||||
if (wndDataValid) {
|
|
||||||
for (int i = 0; i < (numWndVals / dataIntv); i++) {
|
|
||||||
chrtVal = static_cast<int>(wdHstry->get(bufStart + (i * dataIntv))); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer
|
|
||||||
if (chrtVal == wdMAX_VAL) {
|
|
||||||
chrtPrevVal = wdMAX_VAL;
|
|
||||||
} else {
|
|
||||||
chrtVal = static_cast<int>((chrtVal / 1000.0 * radToDeg) + 0.5); // Convert to degrees and round
|
|
||||||
x = ((chrtVal - wndLeft + 360) % 360) * chrtScl;
|
|
||||||
y = yOffset + cHeight - i; // Position in chart area
|
|
||||||
|
|
||||||
if (i >= (numWndVals / dataIntv) - 1) // log chart data of 1 line (adjust for test purposes)
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %d, bufStart: %d, count: %d, linesToShow: %d", i, chrtVal, bufStart, count, (numWndVals / dataIntv));
|
|
||||||
|
|
||||||
if ((i == 0) || (chrtPrevVal == wdMAX_VAL)) {
|
|
||||||
// just a dot for 1st chart point or after some invalid values
|
|
||||||
prevX = x;
|
|
||||||
prevY = y;
|
|
||||||
} else {
|
|
||||||
// cross borders check; shift values to [-180..0..180]; when crossing borders, range is 2x 180 degrees
|
|
||||||
int wndLeftDlt = -180 - ((wndLeft >= 180) ? (wndLeft - 360) : wndLeft);
|
|
||||||
int chrtVal180 = ((chrtVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180;
|
|
||||||
int chrtPrevVal180 = ((chrtPrevVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180;
|
|
||||||
if (((chrtPrevVal180 >= -180) && (chrtPrevVal180 < -90) && (chrtVal180 > 90)) || ((chrtPrevVal180 <= 179) && (chrtPrevVal180 > 90) && chrtVal180 <= -90)) {
|
|
||||||
// If current value crosses chart borders compared to previous value, split line
|
|
||||||
int xSplit = (((chrtPrevVal180 > 0 ? wndRight : wndLeft) - wndLeft + 360) % 360) * chrtScl;
|
|
||||||
getdisplay().drawLine(prevX, prevY, xSplit, y, commonData->fgcolor);
|
|
||||||
getdisplay().drawLine(prevX, prevY - 1, ((xSplit != prevX) ? xSplit : xSplit - 1), ((xSplit != prevX) ? y - 1 : y), commonData->fgcolor);
|
|
||||||
prevX = (((chrtVal180 > 0 ? wndRight : wndLeft) - wndLeft + 360) % 360) * chrtScl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw line with 2 pixels width + make sure vertical line are drawn correctly
|
|
||||||
getdisplay().drawLine(prevX, prevY, x, y, commonData->fgcolor);
|
|
||||||
getdisplay().drawLine(prevX, prevY - 1, ((x != prevX) ? x : x - 1), ((x != prevX) ? y - 1 : y), commonData->fgcolor);
|
|
||||||
chrtPrevVal = chrtVal;
|
|
||||||
prevX = x;
|
|
||||||
prevY = y;
|
|
||||||
}
|
|
||||||
// Reaching chart area top end
|
|
||||||
if (i >= (cHeight - 1)) {
|
|
||||||
oldDataIntv = 0; // force reset of buffer start and number of values to show in next display loop
|
|
||||||
|
|
||||||
int minWndDir = wdHstry->getMin(numWndVals) / 1000.0 * radToDeg;
|
|
||||||
int maxWndDir = wdHstry->getMax(numWndVals) / 1000.0 * radToDeg;
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter);
|
|
||||||
// if (((minWndDir - wndCenter >= 0) && (minWndDir - wndCenter < 180)) || ((maxWndDir - wndCenter <= 0) && (maxWndDir - wndCenter >=180))) {
|
|
||||||
if ((wndRight > wndCenter && (minWndDir >= wndCenter && minWndDir <= wndRight)) || (wndRight <= wndCenter && (minWndDir >= wndCenter || minWndDir <= wndRight)) || (wndLeft < wndCenter && (maxWndDir <= wndCenter && maxWndDir >= wndLeft)) || (wndLeft >= wndCenter && (maxWndDir <= wndCenter || maxWndDir >= wndLeft))) {
|
|
||||||
// Check if all wind value are left or right of center value -> optimize chart center
|
|
||||||
wndCenter = getCntr(*wdHstry, numWndVals);
|
|
||||||
}
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print wind speed value
|
} else if (chrtMode == SPEED) {
|
||||||
int currentZone;
|
if (wsChart) {
|
||||||
static int lastZone = 0;
|
wsChart->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *wsBVal);
|
||||||
static bool flipTws = false;
|
|
||||||
int xPosTws;
|
|
||||||
static const int yPosTws = yOffset + 40;
|
|
||||||
|
|
||||||
xPosTws = flipTws ? 20 : width - 145;
|
|
||||||
currentZone = (y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146) ? 1 : 0; // Define current zone for TWS value
|
|
||||||
if (currentZone != lastZone) {
|
|
||||||
// Only flip when x moves to a different zone
|
|
||||||
if ((y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146)) {
|
|
||||||
flipTws = !flipTws;
|
|
||||||
xPosTws = flipTws ? 20 : width - 145;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lastZone = currentZone;
|
|
||||||
|
|
||||||
wsValue = wsHstry->getLast();
|
} else if (chrtMode == BOTH) {
|
||||||
wsBVal->value = wsValue / 1000.0; // temp variable to retreive data unit from OBP60Formater
|
if (wdChart) {
|
||||||
wsBVal->valid = (static_cast<uint16_t>(wsValue) != wsHstry->getMinVal());
|
wdChart->showChrt(VERTICAL, HALF_SIZE_LEFT, dataIntv, PRNT_NAME, PRNT_VALUE, *wdBVal);
|
||||||
String swsValue = formatValue(wsBVal, *commonData).svalue; // value (string)
|
}
|
||||||
wsUnit = formatValue(wsBVal, *commonData).unit; // Unit of value
|
if (wsChart) {
|
||||||
getdisplay().fillRect(xPosTws - 4, yPosTws - 38, 142, 44, commonData->bgcolor); // Clear area for TWS value
|
wsChart->showChrt(VERTICAL, HALF_SIZE_RIGHT, dataIntv, PRNT_NAME, PRNT_VALUE, *wsBVal);
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
}
|
||||||
getdisplay().setCursor(xPosTws, yPosTws);
|
|
||||||
getdisplay().print(swsValue); // Value
|
|
||||||
/* if (!wsBVal->valid) {
|
|
||||||
getdisplay().print("--.-");
|
|
||||||
} else {
|
|
||||||
wsValue = wsValue / 1000.0 * 1.94384; // Wind speed value in knots
|
|
||||||
if (wsValue < 10.0) {
|
|
||||||
getdisplay().printf("!%3.1f", wsValue); // Value, round to 1 decimal
|
|
||||||
} else {
|
|
||||||
getdisplay().printf("%4.1f", wsValue); // Value, round to 1 decimal
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
|
||||||
getdisplay().setCursor(xPosTws + 82, yPosTws - 14);
|
|
||||||
getdisplay().print(wsName); // Name
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
getdisplay().setCursor(xPosTws + 82, yPosTws + 1);
|
|
||||||
getdisplay().print(wsUnit); // Unit
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// No valid data available
|
|
||||||
LOG_DEBUG(GwLog::LOG, "PageWindPlot: No valid data available");
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
|
||||||
getdisplay().fillRect(xCenter - 33, height / 2 - 20, 66, 24, commonData->bgcolor); // Clear area for message
|
|
||||||
drawTextCenter(xCenter, height / 2 - 10, "No data");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// chart Y axis labels; print at last to overwrite potential chart lines in label area
|
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: page time %ldms", millis() - pageTime);
|
||||||
int yPos;
|
|
||||||
int chrtLbl;
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
|
||||||
for (int i = 1; i <= 3; i++) {
|
|
||||||
yPos = yOffset + (i * 60);
|
|
||||||
getdisplay().fillRect(0, yPos, width, 1, commonData->fgcolor);
|
|
||||||
getdisplay().fillRect(0, yPos - 8, 24, 16, commonData->bgcolor); // Clear small area to remove potential chart lines
|
|
||||||
getdisplay().setCursor(1, yPos + 4);
|
|
||||||
if (count >= intvBufSize) {
|
|
||||||
// Calculate minute value for label
|
|
||||||
chrtLbl = ((i - 1 + (prevY < yOffset + 30)) * dataIntv) * -1; // change label if last data point is more than 30 lines (= seconds) from chart line
|
|
||||||
} else {
|
|
||||||
int j = 3 - i;
|
|
||||||
chrtLbl = (int((((numWndVals / dataIntv) - 50) * dataIntv / 60) + 1) - (j * dataIntv)) * -1; // 50 lines left below last chart line
|
|
||||||
}
|
|
||||||
getdisplay().printf("%3d", chrtLbl); // Wind value label
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot time: %ld", millis() - timer);
|
|
||||||
return PAGE_UPDATE;
|
return PAGE_UPDATE;
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static Page* createPage(CommonData& common)
|
static Page* createPage(CommonData& common)
|
||||||
@@ -520,7 +262,7 @@ PageDescription registerPageWindPlot(
|
|||||||
"WindPlot", // Page name
|
"WindPlot", // Page name
|
||||||
createPage, // Action
|
createPage, // Action
|
||||||
0, // Number of bus values depends on selection in Web configuration
|
0, // Number of bus values depends on selection in Web configuration
|
||||||
{ "TWD", "AWD" }, // Bus values we need in the page
|
{ "TWD", "TWS", "AWD", "AWS" }, // Bus values we need in the page
|
||||||
true // Show display header on/off
|
true // Show display header on/off
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ class PageWindRoseFlex : public Page
|
|||||||
{
|
{
|
||||||
int16_t lp = 80; // Pointer length
|
int16_t lp = 80; // Pointer length
|
||||||
char source = 'A'; // data source (A)pparent | (T)rue
|
char source = 'A'; // data source (A)pparent | (T)rue
|
||||||
String ssource="App."; // String for Data Source
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PageWindRoseFlex(CommonData &common){
|
PageWindRoseFlex(CommonData &common){
|
||||||
@@ -26,10 +25,8 @@ public:
|
|||||||
// Code for set source
|
// Code for set source
|
||||||
if(source == 'A'){
|
if(source == 'A'){
|
||||||
source = 'T';
|
source = 'T';
|
||||||
ssource = "True"; // String to display
|
|
||||||
} else {
|
} else {
|
||||||
source = 'A';
|
source = 'A';
|
||||||
ssource = "App."; // String to display
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return key; // Commit the key
|
return key; // Commit the key
|
||||||
@@ -58,6 +55,11 @@ public:
|
|||||||
static String unit5old = "";
|
static String unit5old = "";
|
||||||
static String svalue6old = "";
|
static String svalue6old = "";
|
||||||
static String unit6old = "";
|
static String unit6old = "";
|
||||||
|
static GFXfont name3font;
|
||||||
|
static GFXfont name4font;
|
||||||
|
static GFXfont name5font;
|
||||||
|
static GFXfont name6font;
|
||||||
|
|
||||||
|
|
||||||
// Get config data
|
// Get config data
|
||||||
String lengthformat = config->getString(config->lengthFormat);
|
String lengthformat = config->getString(config->lengthFormat);
|
||||||
@@ -114,6 +116,12 @@ public:
|
|||||||
GwApi::BoatValue *bvalue3 = pageData.values[0];
|
GwApi::BoatValue *bvalue3 = pageData.values[0];
|
||||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||||
name3 = name3.substring(0, 6); // String length limit for value name
|
name3 = name3.substring(0, 6); // String length limit for value name
|
||||||
|
if (name3.length()>3){
|
||||||
|
name3font=Ubuntu_Bold8pt8b;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
name3font=Ubuntu_Bold12pt8b;
|
||||||
|
}
|
||||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||||
double value3 = bvalue3->value; // Value as double in SI unit
|
double value3 = bvalue3->value; // Value as double in SI unit
|
||||||
bool valid3 = bvalue3->valid; // Valid information
|
bool valid3 = bvalue3->valid; // Valid information
|
||||||
@@ -128,6 +136,12 @@ public:
|
|||||||
GwApi::BoatValue *bvalue4 = pageData.values[1];
|
GwApi::BoatValue *bvalue4 = pageData.values[1];
|
||||||
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
||||||
name4 = name4.substring(0, 6); // String length limit for value name
|
name4 = name4.substring(0, 6); // String length limit for value name
|
||||||
|
if (name4.length()>3){
|
||||||
|
name4font=Ubuntu_Bold8pt8b;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
name4font=Ubuntu_Bold12pt8b;
|
||||||
|
}
|
||||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||||
double value4 = bvalue4->value; // Value as double in SI unit
|
double value4 = bvalue4->value; // Value as double in SI unit
|
||||||
bool valid4 = bvalue4->valid; // Valid information
|
bool valid4 = bvalue4->valid; // Valid information
|
||||||
@@ -142,6 +156,12 @@ public:
|
|||||||
GwApi::BoatValue *bvalue5 = pageData.values[2];
|
GwApi::BoatValue *bvalue5 = pageData.values[2];
|
||||||
String name5 = xdrDelete(bvalue5->getName()); // Value name
|
String name5 = xdrDelete(bvalue5->getName()); // Value name
|
||||||
name5 = name5.substring(0, 6); // String length limit for value name
|
name5 = name5.substring(0, 6); // String length limit for value name
|
||||||
|
if (name5.length()>3){
|
||||||
|
name5font=Ubuntu_Bold8pt8b;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
name5font=Ubuntu_Bold12pt8b;
|
||||||
|
}
|
||||||
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
|
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
|
||||||
double value5 = bvalue5->value; // Value as double in SI unit
|
double value5 = bvalue5->value; // Value as double in SI unit
|
||||||
bool valid5 = bvalue5->valid; // Valid information
|
bool valid5 = bvalue5->valid; // Valid information
|
||||||
@@ -152,10 +172,16 @@ public:
|
|||||||
unit5old = unit5; // Save old unit
|
unit5old = unit5; // Save old unit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get boat value for center
|
// Get boat value for center (name is not displayed)
|
||||||
GwApi::BoatValue *bvalue6 = pageData.values[3];
|
GwApi::BoatValue *bvalue6 = pageData.values[3];
|
||||||
String name6 = xdrDelete(bvalue6->getName()); // Value name
|
String name6 = xdrDelete(bvalue6->getName()); // Value name
|
||||||
name6 = name6.substring(0, 6); // String length limit for value name
|
name6 = name6.substring(0, 6); // String length limit for value name
|
||||||
|
if (name6.length()>3){
|
||||||
|
name6font=Ubuntu_Bold8pt8b;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
name6font=Ubuntu_Bold8pt8b;
|
||||||
|
}
|
||||||
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
|
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
|
||||||
double value6 = bvalue6->value; // Value as double in SI unit
|
double value6 = bvalue6->value; // Value as double in SI unit
|
||||||
bool valid6 = bvalue6->valid; // Valid information
|
bool valid6 = bvalue6->valid; // Valid information
|
||||||
@@ -209,7 +235,7 @@ public:
|
|||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||||
getdisplay().setCursor(10, 270);
|
getdisplay().setCursor(10, 270);
|
||||||
getdisplay().print(svalue3); // Value
|
getdisplay().print(svalue3); // Value
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
getdisplay().setFont(&name3font);
|
||||||
getdisplay().setCursor(10, 220);
|
getdisplay().setCursor(10, 220);
|
||||||
getdisplay().print(name3); // Name
|
getdisplay().print(name3); // Name
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
@@ -224,18 +250,13 @@ public:
|
|||||||
|
|
||||||
// Show value 4 (=second user-configured parameter) at top right
|
// Show value 4 (=second user-configured parameter) at top right
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||||
getdisplay().setCursor(295, 65);
|
getdisplay().setCursor(295, 65);
|
||||||
if(valid3 == true){
|
getdisplay().print(svalue4); // Value
|
||||||
getdisplay().print(svalue4); // Value
|
getdisplay().setFont(&name4font);
|
||||||
}
|
getdisplay().setCursor(325, 95);
|
||||||
else{
|
|
||||||
getdisplay().print("---"); // Value
|
|
||||||
}
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
|
||||||
getdisplay().setCursor(335, 95);
|
|
||||||
getdisplay().print(name4); // Name
|
getdisplay().print(name4); // Name
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
getdisplay().setCursor(335, 115);
|
getdisplay().setCursor(325, 115);
|
||||||
getdisplay().print(" ");
|
getdisplay().print(" ");
|
||||||
if(holdvalues == false){
|
if(holdvalues == false){
|
||||||
getdisplay().print(unit4); // Unit
|
getdisplay().print(unit4); // Unit
|
||||||
@@ -251,11 +272,11 @@ public:
|
|||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||||
getdisplay().setCursor(295, 270);
|
getdisplay().setCursor(295, 270);
|
||||||
getdisplay().print(svalue5); // Value
|
getdisplay().print(svalue5); // Value
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
getdisplay().setFont(&name5font);
|
||||||
getdisplay().setCursor(335, 220);
|
getdisplay().setCursor(325, 220);
|
||||||
getdisplay().print(name5); // Name
|
getdisplay().print(name5); // Name
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
getdisplay().setCursor(335, 190);
|
getdisplay().setCursor(325, 190);
|
||||||
getdisplay().print(" ");
|
getdisplay().print(" ");
|
||||||
if(holdvalues == false){
|
if(holdvalues == false){
|
||||||
getdisplay().print(unit5); // Unit
|
getdisplay().print(unit5); // Unit
|
||||||
@@ -357,12 +378,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Center circle
|
// Center circle
|
||||||
getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
|
getdisplay().fillCircle(200, 150, startwidth + 8, commonData->bgcolor);
|
||||||
getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
|
getdisplay().fillCircle(200, 150, startwidth + 6, commonData->fgcolor);
|
||||||
|
getdisplay().fillCircle(200, 150, startwidth + 4, commonData->bgcolor);
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||||
|
if (source=='A'){
|
||||||
|
getdisplay().setCursor(193, 155);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getdisplay().setCursor(195, 156);
|
||||||
|
}
|
||||||
|
getdisplay().print({source});
|
||||||
|
|
||||||
|
|
||||||
//*******************************************************************************************
|
//*******************************************************************************************
|
||||||
|
|
||||||
// Show value6 (=fourth user-configured parameter) and ssource, so that they do not collide with the wind pointer
|
// Show value6 (=fourth user-configured parameter)
|
||||||
if ( cos(value1) > 0){
|
if ( cos(value1) > 0){
|
||||||
//pointer points upwards
|
//pointer points upwards
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||||
@@ -377,13 +408,6 @@ if ( cos(value1) > 0){
|
|||||||
else{
|
else{
|
||||||
getdisplay().print(unit6old); // Unit
|
getdisplay().print(unit6old); // Unit
|
||||||
}
|
}
|
||||||
if (sin(value1)>0){
|
|
||||||
getdisplay().setCursor(160, 130);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().setCursor(220, 130);
|
|
||||||
}
|
|
||||||
getdisplay().print(ssource); // true or app.
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// pointer points downwards
|
// pointer points downwards
|
||||||
@@ -399,13 +423,6 @@ else{
|
|||||||
else{
|
else{
|
||||||
getdisplay().print(unit6old); // Unit
|
getdisplay().print(unit6old); // Unit
|
||||||
}
|
}
|
||||||
if (sin(value1)>0){
|
|
||||||
getdisplay().setCursor(160, 200);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
getdisplay().setCursor(220, 200);
|
|
||||||
}
|
|
||||||
getdisplay().print(ssource); //true or app.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PAGE_UPDATE;
|
return PAGE_UPDATE;
|
||||||
|
|||||||
@@ -4,19 +4,20 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "LedSpiTask.h"
|
#include "LedSpiTask.h"
|
||||||
#include "OBPDataOperations.h"
|
|
||||||
|
|
||||||
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
|
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
|
||||||
|
|
||||||
typedef std::vector<GwApi::BoatValue *> ValueList;
|
typedef std::vector<GwApi::BoatValue *> ValueList;
|
||||||
|
|
||||||
|
class HstryBuffers;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
GwApi *api;
|
GwApi *api;
|
||||||
String pageName;
|
String pageName;
|
||||||
uint8_t pageNumber; // page number in sequence of visible pages
|
uint8_t pageNumber; // page number in sequence of visible pages
|
||||||
//the values will always contain the user defined values first
|
//the values will always contain the user defined values first
|
||||||
ValueList values;
|
ValueList values;
|
||||||
HstryBuf* boatHstry;
|
HstryBuffers* hstryBuffers; // list of all boat history buffers
|
||||||
} PageData;
|
} PageData;
|
||||||
|
|
||||||
// Sensor data structure (only for extended sensors, not for NMEA bus sensors)
|
// Sensor data structure (only for extended sensors, not for NMEA bus sensors)
|
||||||
@@ -195,10 +196,16 @@ String formatLongitude(double lon);
|
|||||||
|
|
||||||
// Structure for formatted boat values
|
// Structure for formatted boat values
|
||||||
typedef struct{
|
typedef struct{
|
||||||
double value;
|
double value; // SI value of boat data value
|
||||||
String svalue;
|
double cvalue; // value converted to target unit
|
||||||
String unit;
|
String svalue; // value converted to target unit and formatted
|
||||||
|
String unit; // target value unit
|
||||||
} FormattedData;
|
} FormattedData;
|
||||||
|
|
||||||
// Formatter for boat values
|
// Formatter for boat values
|
||||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata);
|
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata);
|
||||||
|
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool ignoreSimuDataSetting);
|
||||||
|
|
||||||
|
// Helper method for conversion of any data value from SI to user defined format (defined in OBP60Formatter)
|
||||||
|
double convertValue(const double &value, const String &format, CommonData &commondata);
|
||||||
|
double convertValue(const double &value, const String &name, const String &format, CommonData &commondata);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
202
lib/obp60task/fonts/IBM8x8px.h
Normal file
202
lib/obp60task/fonts/IBM8x8px.h
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
const uint8_t IBM8x8pxBitmaps[] PROGMEM = {
|
||||||
|
0x00, /* 0x20 space */
|
||||||
|
0x6F, 0xF6, 0x60, 0x60, /* 0x21 exclam */
|
||||||
|
0xDE, 0xF6, /* 0x22 quotedbl */
|
||||||
|
0x6C, 0xDB, 0xFB, 0x6F, 0xED, 0x9B, 0x00, /* 0x23 numbersign */
|
||||||
|
0x31, 0xFC, 0x1E, 0x0F, 0xE3, 0x00, /* 0x24 dollar */
|
||||||
|
0xC7, 0x98, 0x61, 0x86, 0x78, 0xC0, /* 0x25 percent */
|
||||||
|
0x38, 0xD8, 0xE3, 0xBD, 0xD9, 0x9D, 0x80, /* 0x26 ampersand */
|
||||||
|
0x6F, 0x00, /* 0x27 quotesingle */
|
||||||
|
0x36, 0xCC, 0xC6, 0x30, /* 0x28 parenleft */
|
||||||
|
0xC6, 0x33, 0x36, 0xC0, /* 0x29 parenright */
|
||||||
|
0x66, 0x3C, 0xFF, 0x3C, 0x66, /* 0x2A asterisk */
|
||||||
|
0x30, 0xCF, 0xCC, 0x30, /* 0x2B plus */
|
||||||
|
0x6F, 0x00, /* 0x2C comma */
|
||||||
|
0xFC, /* 0x2D hyphen */
|
||||||
|
0xF0, /* 0x2E period */
|
||||||
|
0x06, 0x18, 0x61, 0x86, 0x18, 0x20, 0x00, /* 0x2F slash */
|
||||||
|
0x7D, 0x8F, 0x3E, 0xFF, 0x7C, 0xDF, 0x00, /* 0x30 zero */
|
||||||
|
0x31, 0xC3, 0x0C, 0x30, 0xCF, 0xC0, /* 0x31 one */
|
||||||
|
0x7B, 0x30, 0xCE, 0x63, 0x1F, 0xC0, /* 0x32 two */
|
||||||
|
0x7B, 0x30, 0xCE, 0x0F, 0x37, 0x80, /* 0x33 three */
|
||||||
|
0x1C, 0x79, 0xB6, 0x6F, 0xE1, 0x87, 0x80, /* 0x34 four */
|
||||||
|
0xFF, 0x0F, 0x83, 0x0F, 0x37, 0x80, /* 0x35 five */
|
||||||
|
0x39, 0x8C, 0x3E, 0xCF, 0x37, 0x80, /* 0x36 six */
|
||||||
|
0xFF, 0x30, 0xC6, 0x30, 0xC3, 0x00, /* 0x37 seven */
|
||||||
|
0x7B, 0x3C, 0xDE, 0xCF, 0x37, 0x80, /* 0x38 eight */
|
||||||
|
0x7B, 0x3C, 0xDF, 0x0C, 0x67, 0x00, /* 0x39 nine */
|
||||||
|
0xF0, 0xF0, /* 0x3A colon */
|
||||||
|
0x6C, 0x37, 0x80, /* 0x3B semicolon */
|
||||||
|
0x19, 0x99, 0x86, 0x18, 0x60, /* 0x3C less */
|
||||||
|
0xFC, 0x00, 0x3F, /* 0x3D equal */
|
||||||
|
0xC3, 0x0C, 0x33, 0x33, 0x00, /* 0x3E greater */
|
||||||
|
0x7B, 0x30, 0xC6, 0x30, 0x03, 0x00, /* 0x3F question */
|
||||||
|
0x7D, 0x8F, 0x7E, 0xFD, 0xF8, 0x1E, 0x00, /* 0x40 at */
|
||||||
|
0x31, 0xEC, 0xF3, 0xFF, 0x3C, 0xC0, /* 0x41 A */
|
||||||
|
0xFC, 0xCD, 0x9B, 0xE6, 0x6C, 0xFF, 0x00, /* 0x42 B */
|
||||||
|
0x3C, 0xCF, 0x06, 0x0C, 0x0C, 0xCF, 0x00, /* 0x43 C */
|
||||||
|
0xF8, 0xD9, 0x9B, 0x36, 0x6D, 0xBE, 0x00, /* 0x44 D */
|
||||||
|
0xFE, 0xC5, 0xA3, 0xC6, 0x8C, 0x7F, 0x80, /* 0x45 E */
|
||||||
|
0xFE, 0xC5, 0xA3, 0xC6, 0x8C, 0x3C, 0x00, /* 0x46 F */
|
||||||
|
0x3C, 0xCF, 0x06, 0x0C, 0xEC, 0xCF, 0x80, /* 0x47 G */
|
||||||
|
0xCF, 0x3C, 0xFF, 0xCF, 0x3C, 0xC0, /* 0x48 H */
|
||||||
|
0xF6, 0x66, 0x66, 0xF0, /* 0x49 I */
|
||||||
|
0x1E, 0x18, 0x30, 0x6C, 0xD9, 0x9E, 0x00, /* 0x4A J */
|
||||||
|
0xE6, 0xCD, 0xB3, 0xC6, 0xCC, 0xF9, 0x80, /* 0x4B K */
|
||||||
|
0xF0, 0xC1, 0x83, 0x06, 0x2C, 0xFF, 0x80, /* 0x4C L */
|
||||||
|
0xC7, 0xDF, 0xFF, 0xFD, 0x78, 0xF1, 0x80, /* 0x4D M */
|
||||||
|
0xC7, 0xCF, 0xDE, 0xFC, 0xF8, 0xF1, 0x80, /* 0x4E N */
|
||||||
|
0x38, 0xDB, 0x1E, 0x3C, 0x6D, 0x8E, 0x00, /* 0x4F O */
|
||||||
|
0xFC, 0xCD, 0x9B, 0xE6, 0x0C, 0x3C, 0x00, /* 0x50 P */
|
||||||
|
0x7B, 0x3C, 0xF3, 0xDD, 0xE1, 0xC0, /* 0x51 Q */
|
||||||
|
0xFC, 0xCD, 0x9B, 0xE6, 0xCC, 0xF9, 0x80, /* 0x52 R */
|
||||||
|
0x7B, 0x3E, 0x1C, 0x1F, 0x37, 0x80, /* 0x53 S */
|
||||||
|
0xFE, 0xD3, 0x0C, 0x30, 0xC7, 0x80, /* 0x54 T */
|
||||||
|
0xCF, 0x3C, 0xF3, 0xCF, 0x3F, 0xC0, /* 0x55 U */
|
||||||
|
0xCF, 0x3C, 0xF3, 0xCD, 0xE3, 0x00, /* 0x56 V */
|
||||||
|
0xC7, 0x8F, 0x1E, 0xBF, 0xFD, 0xF1, 0x80, /* 0x57 W */
|
||||||
|
0xC7, 0x8D, 0xB1, 0xC3, 0x8D, 0xB1, 0x80, /* 0x58 X */
|
||||||
|
0xCF, 0x3C, 0xDE, 0x30, 0xC7, 0x80, /* 0x59 Y */
|
||||||
|
0xFF, 0x8E, 0x30, 0xC3, 0x2C, 0xFF, 0x80, /* 0x5A Z */
|
||||||
|
0xFC, 0xCC, 0xCC, 0xF0, /* 0x5B bracketleft */
|
||||||
|
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, /* 0x5C backslash */
|
||||||
|
0xF3, 0x33, 0x33, 0xF0, /* 0x5D bracketright */
|
||||||
|
0x10, 0x71, 0xB6, 0x30, /* 0x5E asciicircum */
|
||||||
|
0xFF, /* 0x5F underscore */
|
||||||
|
0xD9, 0x80, /* 0x60 grave */
|
||||||
|
0x78, 0x19, 0xF6, 0x67, 0x60, /* 0x61 a */
|
||||||
|
0xE0, 0xC1, 0x83, 0xE6, 0x6C, 0xF7, 0x00, /* 0x62 b */
|
||||||
|
0x7B, 0x3C, 0x33, 0x78, /* 0x63 c */
|
||||||
|
0x1C, 0x18, 0x33, 0xEC, 0xD9, 0x9D, 0x80, /* 0x64 d */
|
||||||
|
0x7B, 0x3F, 0xF0, 0x78, /* 0x65 e */
|
||||||
|
0x39, 0xB6, 0x3C, 0x61, 0x8F, 0x00, /* 0x66 f */
|
||||||
|
0x77, 0x9B, 0x33, 0xE0, 0xDF, 0x00, /* 0x67 g */
|
||||||
|
0xE0, 0xC1, 0xB3, 0xB6, 0x6C, 0xF9, 0x80, /* 0x68 h */
|
||||||
|
0x60, 0xE6, 0x66, 0xF0, /* 0x69 i */
|
||||||
|
0x0C, 0x00, 0xC3, 0x0F, 0x3C, 0xDE, /* 0x6A j */
|
||||||
|
0xE0, 0xC1, 0x9B, 0x67, 0x8D, 0xB9, 0x80, /* 0x6B k */
|
||||||
|
0xE6, 0x66, 0x66, 0xF0, /* 0x6C l */
|
||||||
|
0xCD, 0xFF, 0xFE, 0xBC, 0x60, /* 0x6D m */
|
||||||
|
0xFB, 0x3C, 0xF3, 0xCC, /* 0x6E n */
|
||||||
|
0x7B, 0x3C, 0xF3, 0x78, /* 0x6F o */
|
||||||
|
0xDC, 0xCD, 0x9B, 0xE6, 0x1E, 0x00, /* 0x70 p */
|
||||||
|
0x77, 0x9B, 0x33, 0xE0, 0xC3, 0xC0, /* 0x71 q */
|
||||||
|
0xDC, 0xED, 0x9B, 0x0F, 0x00, /* 0x72 r */
|
||||||
|
0x7F, 0x07, 0x83, 0xF8, /* 0x73 s */
|
||||||
|
0x23, 0x3E, 0xC6, 0x34, 0xC0, /* 0x74 t */
|
||||||
|
0xCD, 0x9B, 0x36, 0x67, 0x60, /* 0x75 u */
|
||||||
|
0xCF, 0x3C, 0xDE, 0x30, /* 0x76 v */
|
||||||
|
0xC7, 0xAF, 0xFF, 0xF6, 0xC0, /* 0x77 w */
|
||||||
|
0xC6, 0xD8, 0xE3, 0x6C, 0x60, /* 0x78 x */
|
||||||
|
0xCF, 0x3C, 0xDF, 0x0F, 0xE0, /* 0x79 y */
|
||||||
|
0xFE, 0x63, 0x19, 0xFC, /* 0x7A z */
|
||||||
|
0x1C, 0xC3, 0x38, 0x30, 0xC1, 0xC0, /* 0x7B braceleft */
|
||||||
|
0xFC, 0xFC, /* 0x7C bar */
|
||||||
|
0xE0, 0xC3, 0x07, 0x30, 0xCE, 0x00, /* 0x7D braceright */
|
||||||
|
0x77, 0xB8, /* 0x7E asciitilde */
|
||||||
|
0x10, 0x71, 0xB6, 0x3C, 0x7F, 0xC0 /* 0x7F uni007F */
|
||||||
|
};
|
||||||
|
|
||||||
|
const GFXglyph IBM8x8pxGlyphs[] PROGMEM = {
|
||||||
|
{ 0, 1, 1, 2, 0, -1 }, /* 0x20 space */
|
||||||
|
{ 1, 4, 7, 5, 0, -7 }, /* 0x21 exclam */
|
||||||
|
{ 5, 5, 3, 6, 0, -7 }, /* 0x22 quotedbl */
|
||||||
|
{ 7, 7, 7, 8, 0, -7 }, /* 0x23 numbersign */
|
||||||
|
{ 14, 6, 7, 7, 0, -7 }, /* 0x24 dollar */
|
||||||
|
{ 20, 7, 6, 8, 0, -6 }, /* 0x25 percent */
|
||||||
|
{ 26, 7, 7, 8, 0, -7 }, /* 0x26 ampersand */
|
||||||
|
{ 33, 3, 3, 4, 0, -7 }, /* 0x27 quotesingle */
|
||||||
|
{ 35, 4, 7, 5, 0, -7 }, /* 0x28 parenleft */
|
||||||
|
{ 39, 4, 7, 5, 0, -7 }, /* 0x29 parenright */
|
||||||
|
{ 43, 8, 5, 9, 0, -6 }, /* 0x2A asterisk */
|
||||||
|
{ 48, 6, 5, 7, 0, -6 }, /* 0x2B plus */
|
||||||
|
{ 52, 3, 3, 4, 0, -2 }, /* 0x2C comma */
|
||||||
|
{ 54, 6, 1, 7, 0, -4 }, /* 0x2D hyphen */
|
||||||
|
{ 55, 2, 2, 3, 0, -2 }, /* 0x2E period */
|
||||||
|
{ 56, 7, 7, 8, 0, -7 }, /* 0x2F slash */
|
||||||
|
{ 63, 7, 7, 8, 0, -7 }, /* 0x30 zero */
|
||||||
|
{ 70, 6, 7, 7, 0, -7 }, /* 0x31 one */
|
||||||
|
{ 76, 6, 7, 7, 0, -7 }, /* 0x32 two */
|
||||||
|
{ 82, 6, 7, 7, 0, -7 }, /* 0x33 three */
|
||||||
|
{ 88, 7, 7, 8, 0, -7 }, /* 0x34 four */
|
||||||
|
{ 95, 6, 7, 7, 0, -7 }, /* 0x35 five */
|
||||||
|
{ 101, 6, 7, 7, 0, -7 }, /* 0x36 six */
|
||||||
|
{ 107, 6, 7, 7, 0, -7 }, /* 0x37 seven */
|
||||||
|
{ 113, 6, 7, 7, 0, -7 }, /* 0x38 eight */
|
||||||
|
{ 119, 6, 7, 7, 0, -7 }, /* 0x39 nine */
|
||||||
|
{ 125, 2, 6, 3, 0, -6 }, /* 0x3A colon */
|
||||||
|
{ 127, 3, 6, 4, 0, -6 }, /* 0x3B semicolon */
|
||||||
|
{ 130, 5, 7, 6, 0, -7 }, /* 0x3C less */
|
||||||
|
{ 135, 6, 4, 7, 0, -5 }, /* 0x3D equal */
|
||||||
|
{ 138, 5, 7, 6, 0, -7 }, /* 0x3E greater */
|
||||||
|
{ 143, 6, 7, 7, 0, -7 }, /* 0x3F question */
|
||||||
|
{ 149, 7, 7, 8, 0, -7 }, /* 0x40 at */
|
||||||
|
{ 156, 6, 7, 7, 0, -7 }, /* 0x41 A */
|
||||||
|
{ 162, 7, 7, 8, 0, -7 }, /* 0x42 B */
|
||||||
|
{ 169, 7, 7, 8, 0, -7 }, /* 0x43 C */
|
||||||
|
{ 176, 7, 7, 8, 0, -7 }, /* 0x44 D */
|
||||||
|
{ 183, 7, 7, 8, 0, -7 }, /* 0x45 E */
|
||||||
|
{ 190, 7, 7, 8, 0, -7 }, /* 0x46 F */
|
||||||
|
{ 197, 7, 7, 8, 0, -7 }, /* 0x47 G */
|
||||||
|
{ 204, 6, 7, 7, 0, -7 }, /* 0x48 H */
|
||||||
|
{ 210, 4, 7, 5, 0, -7 }, /* 0x49 I */
|
||||||
|
{ 214, 7, 7, 8, 0, -7 }, /* 0x4A J */
|
||||||
|
{ 221, 7, 7, 8, 0, -7 }, /* 0x4B K */
|
||||||
|
{ 228, 7, 7, 8, 0, -7 }, /* 0x4C L */
|
||||||
|
{ 235, 7, 7, 8, 0, -7 }, /* 0x4D M */
|
||||||
|
{ 242, 7, 7, 8, 0, -7 }, /* 0x4E N */
|
||||||
|
{ 249, 7, 7, 8, 0, -7 }, /* 0x4F O */
|
||||||
|
{ 256, 7, 7, 8, 0, -7 }, /* 0x50 P */
|
||||||
|
{ 263, 6, 7, 7, 0, -7 }, /* 0x51 Q */
|
||||||
|
{ 269, 7, 7, 8, 0, -7 }, /* 0x52 R */
|
||||||
|
{ 276, 6, 7, 7, 0, -7 }, /* 0x53 S */
|
||||||
|
{ 282, 6, 7, 7, 0, -7 }, /* 0x54 T */
|
||||||
|
{ 288, 6, 7, 7, 0, -7 }, /* 0x55 U */
|
||||||
|
{ 294, 6, 7, 7, 0, -7 }, /* 0x56 V */
|
||||||
|
{ 300, 7, 7, 8, 0, -7 }, /* 0x57 W */
|
||||||
|
{ 307, 7, 7, 8, 0, -7 }, /* 0x58 X */
|
||||||
|
{ 314, 6, 7, 7, 0, -7 }, /* 0x59 Y */
|
||||||
|
{ 320, 7, 7, 8, 0, -7 }, /* 0x5A Z */
|
||||||
|
{ 327, 4, 7, 5, 0, -7 }, /* 0x5B bracketleft */
|
||||||
|
{ 331, 7, 7, 8, 0, -7 }, /* 0x5C backslash */
|
||||||
|
{ 338, 4, 7, 5, 0, -7 }, /* 0x5D bracketright */
|
||||||
|
{ 342, 7, 4, 8, 0, -7 }, /* 0x5E asciicircum */
|
||||||
|
{ 346, 8, 1, 9, 0, 0 }, /* 0x5F underscore */
|
||||||
|
{ 347, 3, 3, 4, 0, -7 }, /* 0x60 grave */
|
||||||
|
{ 349, 7, 5, 8, 0, -5 }, /* 0x61 a */
|
||||||
|
{ 354, 7, 7, 8, 0, -7 }, /* 0x62 b */
|
||||||
|
{ 361, 6, 5, 7, 0, -5 }, /* 0x63 c */
|
||||||
|
{ 365, 7, 7, 8, 0, -7 }, /* 0x64 d */
|
||||||
|
{ 372, 6, 5, 7, 0, -5 }, /* 0x65 e */
|
||||||
|
{ 376, 6, 7, 7, 0, -7 }, /* 0x66 f */
|
||||||
|
{ 382, 7, 6, 8, 0, -5 }, /* 0x67 g */
|
||||||
|
{ 388, 7, 7, 8, 0, -7 }, /* 0x68 h */
|
||||||
|
{ 395, 4, 7, 5, 0, -7 }, /* 0x69 i */
|
||||||
|
{ 399, 6, 8, 7, 0, -7 }, /* 0x6A j */
|
||||||
|
{ 405, 7, 7, 8, 0, -7 }, /* 0x6B k */
|
||||||
|
{ 412, 4, 7, 5, 0, -7 }, /* 0x6C l */
|
||||||
|
{ 416, 7, 5, 8, 0, -5 }, /* 0x6D m */
|
||||||
|
{ 421, 6, 5, 7, 0, -5 }, /* 0x6E n */
|
||||||
|
{ 425, 6, 5, 7, 0, -5 }, /* 0x6F o */
|
||||||
|
{ 429, 7, 6, 8, 0, -5 }, /* 0x70 p */
|
||||||
|
{ 435, 7, 6, 8, 0, -5 }, /* 0x71 q */
|
||||||
|
{ 441, 7, 5, 8, 0, -5 }, /* 0x72 r */
|
||||||
|
{ 446, 6, 5, 7, 0, -5 }, /* 0x73 s */
|
||||||
|
{ 450, 5, 7, 6, 0, -7 }, /* 0x74 t */
|
||||||
|
{ 455, 7, 5, 8, 0, -5 }, /* 0x75 u */
|
||||||
|
{ 460, 6, 5, 7, 0, -5 }, /* 0x76 v */
|
||||||
|
{ 464, 7, 5, 8, 0, -5 }, /* 0x77 w */
|
||||||
|
{ 469, 7, 5, 8, 0, -5 }, /* 0x78 x */
|
||||||
|
{ 474, 6, 6, 7, 0, -5 }, /* 0x79 y */
|
||||||
|
{ 479, 6, 5, 7, 0, -5 }, /* 0x7A z */
|
||||||
|
{ 483, 6, 7, 7, 0, -7 }, /* 0x7B braceleft */
|
||||||
|
{ 489, 2, 7, 3, 0, -7 }, /* 0x7C bar */
|
||||||
|
{ 491, 6, 7, 7, 0, -7 }, /* 0x7D braceright */
|
||||||
|
{ 497, 7, 2, 8, 0, -7 }, /* 0x7E asciitilde */
|
||||||
|
{ 499, 7, 6, 8, 0, -6 } /* 0x7F uni007F */
|
||||||
|
};
|
||||||
|
|
||||||
|
const GFXfont IBM8x8px PROGMEM = {
|
||||||
|
(uint8_t *)IBM8x8pxBitmaps,
|
||||||
|
(GFXglyph *)IBM8x8pxGlyphs,
|
||||||
|
0x20, 0x7F, 8 };
|
||||||
@@ -20,7 +20,7 @@ import getopt
|
|||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
|
|
||||||
__version__ = "0.2"
|
__version__ = "0.3"
|
||||||
|
|
||||||
def detect_pages(filename):
|
def detect_pages(filename):
|
||||||
# returns a dictionary with page name and the number of gui fields
|
# returns a dictionary with page name and the number of gui fields
|
||||||
@@ -87,6 +87,11 @@ def create_json(device, no_of_pages, pagedata):
|
|||||||
output = []
|
output = []
|
||||||
|
|
||||||
for page_no in range(1, no_of_pages + 1):
|
for page_no in range(1, no_of_pages + 1):
|
||||||
|
|
||||||
|
category = f"{device.upper()} Page {page_no}"
|
||||||
|
capabilities = {device.lower(): "true"}
|
||||||
|
visiblepages = [str(vp) for vp in range(page_no, no_of_pages + 1)]
|
||||||
|
|
||||||
page_data = {
|
page_data = {
|
||||||
"name": f"page{page_no}type",
|
"name": f"page{page_no}type",
|
||||||
"label": "Type",
|
"label": "Type",
|
||||||
@@ -94,9 +99,11 @@ def create_json(device, no_of_pages, pagedata):
|
|||||||
"default": get_default_page(page_no),
|
"default": get_default_page(page_no),
|
||||||
"description": f"Type of page for page {page_no}",
|
"description": f"Type of page for page {page_no}",
|
||||||
"list": pages,
|
"list": pages,
|
||||||
"category": f"{device.upper()} Page {page_no}",
|
"category": category,
|
||||||
"capabilities": {device.lower(): "true"},
|
"capabilities": {device.lower(): "true"},
|
||||||
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
|
"condition": {
|
||||||
|
"visiblePages": visiblepages
|
||||||
|
},
|
||||||
#"fields": [],
|
#"fields": [],
|
||||||
}
|
}
|
||||||
output.append(page_data)
|
output.append(page_data)
|
||||||
@@ -108,39 +115,59 @@ def create_json(device, no_of_pages, pagedata):
|
|||||||
"type": "boatData",
|
"type": "boatData",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "The display for field {}".format(number_to_text(field_no)),
|
"description": "The display for field {}".format(number_to_text(field_no)),
|
||||||
"category": f"{device.upper()} Page {page_no}",
|
"category": category,
|
||||||
"capabilities": {device.lower(): "true"},
|
"capabilities": capabilities,
|
||||||
"condition": [
|
"condition": {
|
||||||
{f"page{page_no}type": page}
|
f"page{page_no}type": [ p for p in pages if pagedata[p] >= field_no ]
|
||||||
for page in pages
|
,"visiblePages": visiblepages
|
||||||
if pagedata[page] >= field_no
|
}
|
||||||
],
|
|
||||||
}
|
}
|
||||||
output.append(field_data)
|
output.append(field_data)
|
||||||
|
|
||||||
fluid_data ={
|
fluid_data = {
|
||||||
"name": f"page{page_no}fluid",
|
"name": f"page{page_no}fluid",
|
||||||
"label": "Fluid type",
|
"label": "Fluid type",
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"list": [
|
"list": [
|
||||||
{"l":"Fuel (0)","v":"0"},
|
{"l":"Fuel (0)","v":"0"},
|
||||||
{"l":"Water (1)","v":"1"},
|
{"l":"Water (1)","v":"1"},
|
||||||
{"l":"Gray Water (2)","v":"2"},
|
{"l":"Gray Water (2)","v":"2"},
|
||||||
{"l":"Live Well (3)","v":"3"},
|
{"l":"Live Well (3)","v":"3"},
|
||||||
{"l":"Oil (4)","v":"4"},
|
{"l":"Oil (4)","v":"4"},
|
||||||
{"l":"Black Water (5)","v":"5"},
|
{"l":"Black Water (5)","v":"5"},
|
||||||
{"l":"Fuel Gasoline (6)","v":"6"}
|
{"l":"Fuel Gasoline (6)","v":"6"}
|
||||||
],
|
],
|
||||||
"description": "Fluid type in tank",
|
"description": "Fluid type in tank",
|
||||||
"category": f"{device.upper()} Page {page_no}",
|
"category": category,
|
||||||
"capabilities": {
|
"capabilities": capabilities,
|
||||||
device.lower(): "true"
|
"condition": {
|
||||||
},
|
f"page{page_no}type": "Fluid",
|
||||||
"condition":[{f"page{page_no}type":"Fluid"}]
|
"visiblePages": visiblepages
|
||||||
}
|
}
|
||||||
|
}
|
||||||
output.append(fluid_data)
|
output.append(fluid_data)
|
||||||
|
|
||||||
|
if device.upper() == 'OBP40':
|
||||||
|
windsource = {
|
||||||
|
"name": f"page{page_no}wndsrc",
|
||||||
|
"label": "Wind source",
|
||||||
|
"type": "list",
|
||||||
|
"default": "True wind",
|
||||||
|
"description": f"Wind source for page {page_no}: [true|apparent]",
|
||||||
|
"list": [
|
||||||
|
"True wind",
|
||||||
|
"Apparent wind"
|
||||||
|
],
|
||||||
|
"category": category,
|
||||||
|
"capabilities": capabilities,
|
||||||
|
"condition": {
|
||||||
|
f"page{page_no}type": "WindPlot",
|
||||||
|
"visiblePages": visiblepages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.append(windsource)
|
||||||
|
|
||||||
return json.dumps(output, indent=4)
|
return json.dumps(output, indent=4)
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define alpha_width 96
|
|
||||||
#define alpha_height 64
|
|
||||||
static unsigned char alpha_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xee, 0xee, 0x06,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x01,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xee, 0x6e, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xee, 0x06, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0x01, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0x6e, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0x06, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0x01, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x6e, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x1b, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x06, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x06, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x1b, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x6e, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0x01, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0x06, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0x6e, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0x01, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xee, 0x06, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xee, 0x6e, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x01,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xee, 0xee, 0x06,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xee, 0xee, 0x6e,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define answer_width 96
|
|
||||||
#define answer_height 64
|
|
||||||
static unsigned char answer_bits[] PROGMEM = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xf7, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xab, 0xfa, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0xc5, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xab, 0xaa, 0x0a, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0xff, 0xff, 0x01, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0xfe, 0x1f, 0x00, 0x00,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xfe, 0x0f, 0x00,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0xf0, 0xff, 0x07,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xfa, 0x7f,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xfd,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x50, 0x55, 0xfd,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xa0, 0xfa, 0x7f,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0xf0, 0xff, 0x07,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0x02, 0x00, 0xfe, 0x0f, 0x00,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0x55, 0x01, 0xfe, 0x1f, 0x00, 0x00,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xaa, 0xaa, 0xff, 0xff, 0x01, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x40, 0x55, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0xab, 0xaa, 0x0a, 0x00, 0x80, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xab, 0xaa, 0x0a, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0xc5, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xab, 0xfa, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xf7, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
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,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define black_width 96
|
|
||||||
#define black_height 64
|
|
||||||
static unsigned char black_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0xc0, 0x1f, 0xff, 0x1f, 0xfc, 0x0f, 0x78, 0x7c, 0xf8, 0xff,
|
|
||||||
0xff, 0x3f, 0x00, 0x1f, 0xff, 0x1f, 0xfc, 0x07, 0x70, 0x3c, 0xfc, 0xff,
|
|
||||||
0xff, 0x3f, 0x00, 0x1e, 0xff, 0x1f, 0xfc, 0x03, 0x70, 0x1c, 0xfe, 0xff,
|
|
||||||
0xff, 0x3f, 0x3e, 0x1e, 0xff, 0x8f, 0xf8, 0xe1, 0x7b, 0x0c, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x3e, 0x1e, 0xff, 0x8f, 0xf8, 0xf0, 0x7f, 0x84, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x00, 0x1f, 0xff, 0x87, 0xf0, 0xf8, 0x7f, 0xc0, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x00, 0x1f, 0xff, 0xc7, 0xf1, 0xf8, 0x7f, 0xe0, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x00, 0x1e, 0xff, 0xc7, 0xf1, 0xf8, 0x7f, 0xc0, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x3e, 0x1c, 0xff, 0xc3, 0xe1, 0xf8, 0x7f, 0x84, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x7e, 0x1c, 0xff, 0x03, 0xe0, 0xf8, 0x7f, 0x8c, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x7e, 0x1c, 0xff, 0x01, 0xe0, 0xf0, 0x7f, 0x1c, 0xff, 0xff,
|
|
||||||
0xff, 0x3f, 0x3e, 0x1c, 0xff, 0x01, 0xc0, 0xe1, 0x7b, 0x1c, 0xfe, 0xff,
|
|
||||||
0xff, 0x3f, 0x00, 0x1e, 0x80, 0xf1, 0xc7, 0x01, 0x70, 0x3c, 0xfc, 0xff,
|
|
||||||
0xff, 0x3f, 0x00, 0x1e, 0x80, 0xf0, 0x87, 0x03, 0x70, 0x7c, 0xf8, 0xff,
|
|
||||||
0xff, 0x3f, 0x80, 0x1f, 0x80, 0xf8, 0x8f, 0x0f, 0x78, 0xfc, 0xf0, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define blue_width 96
|
|
||||||
#define blue_height 64
|
|
||||||
static unsigned char blue_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x15, 0x40, 0x05, 0x55, 0x50, 0x51, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x0e, 0x80, 0x8e, 0xee, 0xe8, 0xe0, 0x00, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x15, 0x00, 0x05, 0x55, 0x50, 0x51, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x1b, 0x1b, 0x8b, 0xbb, 0xb8, 0xb1, 0xb8, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x15, 0x15, 0x05, 0x55, 0x50, 0x51, 0x50, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x0e, 0x80, 0x8e, 0xee, 0xe8, 0xe0, 0xe8, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x15, 0x00, 0x05, 0x55, 0x50, 0x51, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x1b, 0x00, 0x8b, 0xbb, 0xb8, 0xb1, 0x00, 0xba, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x15, 0x15, 0x04, 0x55, 0x50, 0x51, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x0e, 0x2e, 0x8e, 0xee, 0xe8, 0xe0, 0xe8, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x15, 0x15, 0x04, 0x55, 0x50, 0x51, 0x50, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x1b, 0x1b, 0x8a, 0xbb, 0xb0, 0xb0, 0xb8, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x15, 0x00, 0x05, 0x40, 0x01, 0x50, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x0e, 0x00, 0x0e, 0xc0, 0x02, 0xec, 0x00, 0xec, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x15, 0x40, 0x05, 0x40, 0x05, 0x54, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define charlie_width 96
|
|
||||||
#define charlie_height 64
|
|
||||||
static unsigned char charlie_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define class_width 96
|
|
||||||
#define class_height 64
|
|
||||||
static unsigned char class_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xf8, 0xc3, 0x01, 0xc0, 0x07, 0xe0, 0x07, 0xfc, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xfc, 0xc7, 0x01, 0xc0, 0x07, 0xf8, 0x0f, 0xff, 0x01, 0xc0,
|
|
||||||
0x03, 0x00, 0xfe, 0xc7, 0x01, 0xc0, 0x07, 0xfc, 0x87, 0xff, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x0f, 0xc2, 0x01, 0xe0, 0x0e, 0x1c, 0x84, 0x83, 0x00, 0xc0,
|
|
||||||
0x03, 0x80, 0x07, 0xc0, 0x01, 0xe0, 0x0e, 0x1c, 0x80, 0x03, 0x00, 0xc0,
|
|
||||||
0x03, 0x80, 0x03, 0xc0, 0x01, 0xf0, 0x1e, 0x3c, 0x80, 0x07, 0x00, 0xc0,
|
|
||||||
0x03, 0x80, 0x03, 0xc0, 0x01, 0x70, 0x1c, 0xf8, 0x01, 0x3f, 0x00, 0xc0,
|
|
||||||
0x03, 0x80, 0x03, 0xc0, 0x01, 0x70, 0x1c, 0xf0, 0x07, 0xfe, 0x00, 0xc0,
|
|
||||||
0x03, 0x80, 0x03, 0xc0, 0x01, 0x78, 0x3c, 0xc0, 0x0f, 0xf8, 0x01, 0xc0,
|
|
||||||
0x03, 0x80, 0x03, 0xc0, 0x01, 0xf8, 0x3f, 0x00, 0x1e, 0xc0, 0x03, 0xc0,
|
|
||||||
0x03, 0x80, 0x07, 0xc0, 0x01, 0xfc, 0x3f, 0x00, 0x1c, 0x80, 0x03, 0xc0,
|
|
||||||
0x03, 0x00, 0x0f, 0xc2, 0x01, 0xfc, 0x7f, 0x08, 0x1c, 0x81, 0x03, 0xc0,
|
|
||||||
0x03, 0x00, 0xff, 0xc7, 0xff, 0x1c, 0x70, 0xfc, 0x9f, 0xff, 0x03, 0xc0,
|
|
||||||
0x03, 0x00, 0xfe, 0xc7, 0xff, 0x1e, 0xf0, 0xfc, 0x8f, 0xff, 0x01, 0xc0,
|
|
||||||
0x03, 0x00, 0xf8, 0xc3, 0xff, 0x0e, 0xe0, 0xf0, 0x03, 0x7e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define finish_width 96
|
|
||||||
#define finish_height 64
|
|
||||||
static unsigned char finish_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0x6e, 0x00, 0x8e, 0xc6, 0x8e, 0x8e, 0x0e, 0xe8, 0xe8, 0xe0, 0xee,
|
|
||||||
0x57, 0x55, 0x00, 0x04, 0x05, 0x05, 0x05, 0x05, 0x50, 0x50, 0x51, 0xd5,
|
|
||||||
0xbb, 0x3b, 0x00, 0x8a, 0x03, 0x8b, 0x8b, 0x03, 0xb8, 0xb8, 0xb1, 0xfb,
|
|
||||||
0x57, 0x55, 0x54, 0x05, 0x05, 0x05, 0x05, 0x41, 0x51, 0x50, 0x51, 0xd5,
|
|
||||||
0xef, 0x6e, 0xec, 0x8e, 0x06, 0x8e, 0x8e, 0xe2, 0xee, 0xe8, 0xe0, 0xee,
|
|
||||||
0x57, 0x55, 0x54, 0x05, 0x05, 0x04, 0x05, 0x41, 0x55, 0x50, 0x51, 0xd5,
|
|
||||||
0xbb, 0x3b, 0x00, 0x8b, 0x03, 0x88, 0x8b, 0x03, 0xba, 0x00, 0xb0, 0xfb,
|
|
||||||
0x57, 0x55, 0x00, 0x05, 0x45, 0x00, 0x05, 0x05, 0x50, 0x00, 0x50, 0xd5,
|
|
||||||
0xef, 0x6e, 0x00, 0x8e, 0xc6, 0x80, 0x8e, 0x2e, 0xe0, 0x00, 0xe0, 0xee,
|
|
||||||
0x57, 0x55, 0x54, 0x05, 0x45, 0x01, 0x05, 0x55, 0x41, 0x50, 0x51, 0xd5,
|
|
||||||
0xbb, 0x3b, 0xb8, 0x8b, 0x83, 0x83, 0x8b, 0xbb, 0xa3, 0xb8, 0xb1, 0xfb,
|
|
||||||
0x57, 0x55, 0x54, 0x05, 0x45, 0x01, 0x05, 0x55, 0x41, 0x50, 0x51, 0xd5,
|
|
||||||
0xef, 0x6e, 0xec, 0x8e, 0xc6, 0x86, 0x8e, 0x02, 0xe0, 0xe8, 0xe0, 0xee,
|
|
||||||
0x57, 0x55, 0x54, 0x05, 0x45, 0x05, 0x05, 0x01, 0x50, 0x50, 0x51, 0xd5,
|
|
||||||
0xbb, 0x3b, 0xb8, 0x8b, 0x83, 0x8b, 0x8b, 0x0b, 0xb8, 0xb8, 0xb1, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define flag_hotel_width 96
|
|
||||||
#define flag_hotel_height 64
|
|
||||||
static unsigned char flag_hotel_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define india_width 96
|
|
||||||
#define india_height 64
|
|
||||||
static unsigned char india_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0xf2, 0x2f, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0xff, 0xff, 0x89, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0xf2, 0xff, 0xff, 0x2f, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0xf8, 0xff, 0xff, 0x9f, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0xfe, 0xff, 0xff, 0x7f, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0xff, 0xff, 0xff, 0xff, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0xff, 0xff, 0xff, 0xff, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0xff, 0xff, 0xff, 0xff, 0x89, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0xa2, 0xff, 0xff, 0xff, 0xff, 0x23, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0xff, 0xff, 0xff, 0xff, 0x89, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0xa2, 0xff, 0xff, 0xff, 0xff, 0x23, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0xff, 0xff, 0xff, 0xff, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0xfe, 0xff, 0xff, 0x7f, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0xfc, 0xff, 0xff, 0xbf, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0xfa, 0xff, 0xff, 0x3f, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0xc8, 0xff, 0xff, 0x8b, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0xfe, 0x7f, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define november_width 96
|
|
||||||
#define november_height 64
|
|
||||||
static unsigned char november_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0xdf, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x77, 0x77, 0xf7,
|
|
||||||
0x03, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xea,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define orange_width 96
|
|
||||||
#define orange_height 64
|
|
||||||
static unsigned char orange_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaf, 0xfa, 0xaf, 0xea, 0xaf, 0xba, 0xfa, 0xaa, 0xbf, 0xfa, 0xef,
|
|
||||||
0xe3, 0x3f, 0xf0, 0x3f, 0xc0, 0x07, 0x78, 0x70, 0xc0, 0x7f, 0xf8, 0xcf,
|
|
||||||
0xfb, 0xff, 0xfa, 0xff, 0xea, 0xaf, 0xfa, 0xfa, 0xea, 0xff, 0xfa, 0xef,
|
|
||||||
0x7b, 0xf0, 0x70, 0xf0, 0xe0, 0x0e, 0xf8, 0x70, 0xf0, 0x20, 0x38, 0xc0,
|
|
||||||
0xbb, 0xea, 0xfb, 0xea, 0xea, 0xae, 0xfa, 0xfb, 0xfa, 0xaa, 0xba, 0xea,
|
|
||||||
0x1f, 0xc0, 0x71, 0xe0, 0xf0, 0x1e, 0xf8, 0x73, 0x38, 0x00, 0x38, 0xc0,
|
|
||||||
0xbf, 0xea, 0xfb, 0xfa, 0xfa, 0xbe, 0xba, 0xfb, 0xba, 0xaa, 0xfa, 0xef,
|
|
||||||
0x1f, 0xc0, 0xf1, 0x7f, 0x70, 0x1c, 0x38, 0x77, 0x38, 0x70, 0xf8, 0xcf,
|
|
||||||
0xbf, 0xea, 0xfb, 0xbf, 0xfa, 0xbe, 0xba, 0xff, 0xba, 0xfa, 0xfa, 0xef,
|
|
||||||
0x1f, 0xc0, 0xf1, 0x0f, 0xf8, 0x3f, 0x38, 0x7e, 0x38, 0x70, 0x38, 0xc0,
|
|
||||||
0xbf, 0xea, 0xfb, 0xbe, 0xfe, 0xbf, 0xba, 0xfe, 0xfa, 0xfa, 0xba, 0xea,
|
|
||||||
0x7b, 0xf0, 0x70, 0x38, 0xfc, 0x7f, 0x38, 0x7c, 0xf0, 0x70, 0x38, 0xc0,
|
|
||||||
0xfb, 0xff, 0xfa, 0xfa, 0xbe, 0xfa, 0xba, 0xfa, 0xfa, 0xff, 0xfa, 0xff,
|
|
||||||
0xe3, 0x3f, 0x70, 0xf0, 0x1e, 0xf0, 0x38, 0x70, 0xe0, 0x7f, 0xf8, 0xdf,
|
|
||||||
0xab, 0xbf, 0xfa, 0xea, 0xaf, 0xea, 0xba, 0xfa, 0xaa, 0xbf, 0xfa, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define papa_width 96
|
|
||||||
#define papa_height 64
|
|
||||||
static unsigned char papa_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define repeat_one_width 96
|
|
||||||
#define repeat_one_height 64
|
|
||||||
static unsigned char repeat_one_bits[] PROGMEM = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xfb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xef, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0xd5, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xbb, 0xbb, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0xd5, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xef, 0xee, 0xee, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x55, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x43, 0x55, 0x55, 0x55, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x0b, 0xef, 0xee, 0xee, 0xae, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x70, 0x55, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x23, 0xc2, 0xbb, 0xbb, 0xbb, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x54, 0x55, 0x55, 0xd5, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x8b, 0x88, 0xe0, 0xee, 0xee, 0xee, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x55, 0x55, 0x55, 0xd5, 0x03, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x23, 0x22, 0x22, 0xb8, 0xbb, 0xbb, 0xbb, 0x1f, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0xf5, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x8b, 0x88, 0x88, 0x08, 0xee, 0xee, 0xee, 0xee, 0x07, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, 0x3d, 0x00, 0x00, 0x00,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x82, 0xbb, 0xbb, 0xbb, 0xfb, 0x01, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x0f, 0x00, 0x00,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0xe0, 0xee, 0xee, 0xee, 0x7e, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xd5, 0x03, 0x00,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xb0, 0xbb, 0xbb, 0xbb, 0x1f, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xf5, 0x00,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xee, 0xee, 0xee, 0xee, 0x07,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, 0x1d,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xbb, 0xbb, 0xbb, 0x7b,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, 0x1d,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xee, 0xee, 0xee, 0xee, 0x07,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0xf5, 0x00,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xb0, 0xbb, 0xbb, 0xbb, 0x1f, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0xd5, 0x03, 0x00,
|
|
||||||
0x8b, 0x88, 0x88, 0x88, 0x88, 0xc0, 0xee, 0xee, 0xee, 0x7e, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x0f, 0x00, 0x00,
|
|
||||||
0x23, 0x22, 0x22, 0x22, 0x02, 0xbb, 0xbb, 0xbb, 0xfb, 0x03, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x3d, 0x00, 0x00, 0x00,
|
|
||||||
0x8b, 0x88, 0x88, 0x08, 0xee, 0xee, 0xee, 0xee, 0x07, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0xf5, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x23, 0x22, 0x22, 0xb0, 0xbb, 0xbb, 0xbb, 0x1f, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x55, 0x55, 0x55, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x8b, 0x88, 0xe0, 0xee, 0xee, 0xee, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x54, 0x55, 0x55, 0xd5, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x23, 0xc2, 0xbb, 0xbb, 0xbb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x58, 0x55, 0x55, 0x55, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x0b, 0xef, 0xee, 0xee, 0xee, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x43, 0x55, 0x55, 0x55, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x55, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xef, 0xee, 0xee, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0xd5, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xbb, 0xbb, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x55, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xef, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x57, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xfb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
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,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define sierra_width 96
|
|
||||||
#define sierra_height 64
|
|
||||||
static unsigned char sierra_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xe8, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x0e, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x1b, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define start_width 96
|
|
||||||
#define start_height 64
|
|
||||||
static unsigned char start_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xfe, 0xfe, 0xff, 0xfa, 0xaa, 0xff, 0xfa, 0xff, 0xab, 0xea,
|
|
||||||
0x03, 0x00, 0xff, 0xfd, 0x7f, 0xf8, 0x00, 0xff, 0xf3, 0xff, 0x01, 0xc0,
|
|
||||||
0xab, 0xaa, 0xff, 0xfe, 0xff, 0xfa, 0xaa, 0xff, 0xff, 0xff, 0xab, 0xea,
|
|
||||||
0x03, 0x80, 0x83, 0x80, 0x03, 0xdc, 0x01, 0x07, 0x0f, 0x0e, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xab, 0xaa, 0xab, 0xfe, 0xab, 0xaf, 0xae, 0xae, 0xaa, 0xea,
|
|
||||||
0x03, 0x80, 0x07, 0x80, 0x03, 0xde, 0x03, 0x07, 0x0e, 0x0e, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xbf, 0xaa, 0xab, 0xae, 0xab, 0xaf, 0xaf, 0xae, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0xfe, 0x80, 0x03, 0x8e, 0x03, 0xff, 0x07, 0x0e, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xfa, 0xab, 0xab, 0xaf, 0xaf, 0xff, 0xab, 0xae, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0xc0, 0x83, 0x03, 0xff, 0x07, 0xff, 0x00, 0x0e, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xab, 0xab, 0xff, 0xaf, 0xef, 0xab, 0xae, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x81, 0x83, 0x83, 0xff, 0x0f, 0x87, 0x03, 0x0e, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xff, 0xab, 0xab, 0xab, 0xae, 0xaf, 0xaf, 0xae, 0xaa, 0xea,
|
|
||||||
0x03, 0x80, 0xff, 0x81, 0xc3, 0x03, 0x1e, 0x07, 0x0f, 0x0e, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xfe, 0xaa, 0xeb, 0xab, 0xbe, 0xaf, 0xbe, 0xae, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define uniform_width 96
|
|
||||||
#define uniform_height 64
|
|
||||||
static unsigned char uniform_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define xray_width 96
|
|
||||||
#define xray_height 64
|
|
||||||
static unsigned char xray_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define yankee_width 96
|
|
||||||
#define yankee_height 64
|
|
||||||
static unsigned char yankee_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x03, 0x60, 0x55, 0xd5, 0x00, 0x00, 0x55, 0x55, 0x05, 0x00, 0x58, 0xd5,
|
|
||||||
0xab, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xae, 0xea,
|
|
||||||
0x03, 0x54, 0x55, 0x15, 0x00, 0x60, 0x55, 0xd5, 0x00, 0x00, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xae, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x83, 0x55, 0x55, 0x03, 0x00, 0x54, 0x55, 0x15, 0x00, 0x60, 0x55, 0xd5,
|
|
||||||
0xeb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xba, 0xaa, 0xea,
|
|
||||||
0x53, 0x55, 0x55, 0x00, 0x80, 0x55, 0x55, 0x03, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xba, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xee,
|
|
||||||
0x57, 0x55, 0x0d, 0x00, 0x50, 0x55, 0x55, 0x00, 0x80, 0x55, 0x55, 0xc3,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xea, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x01, 0x00, 0x56, 0x55, 0x0d, 0x00, 0x50, 0x55, 0x55, 0xc0,
|
|
||||||
0xab, 0xea, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xea,
|
|
||||||
0x57, 0x35, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x56, 0x55, 0x0d, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x05, 0x00, 0x58, 0x55, 0x35, 0x00, 0x40, 0x55, 0x55, 0x01, 0xc0,
|
|
||||||
0xab, 0xab, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xea,
|
|
||||||
0xd7, 0x00, 0x00, 0x55, 0x55, 0x05, 0x00, 0x58, 0x55, 0x35, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x17, 0x00, 0x60, 0x55, 0xd5, 0x00, 0x00, 0x55, 0x55, 0x05, 0x00, 0xd8,
|
|
||||||
0xaf, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xee,
|
|
||||||
0x03, 0x00, 0x54, 0x55, 0x15, 0x00, 0x60, 0x55, 0xd5, 0x00, 0x00, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x80, 0x55, 0x55, 0x03, 0x00, 0x54, 0x55, 0x15, 0x00, 0x60, 0xd5,
|
|
||||||
0xab, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xba, 0xea,
|
|
||||||
0x03, 0x50, 0x55, 0x55, 0x00, 0x80, 0x55, 0x55, 0x03, 0x00, 0x54, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xba, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x56, 0x55, 0x0d, 0x00, 0x50, 0x55, 0x55, 0x00, 0x80, 0x55, 0xd5,
|
|
||||||
0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xea, 0xaa, 0xea,
|
|
||||||
0x43, 0x55, 0x55, 0x01, 0x00, 0x56, 0x55, 0x0d, 0x00, 0x50, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xea, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfa,
|
|
||||||
0x5b, 0x55, 0x35, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x56, 0x55, 0xcd,
|
|
||||||
0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xab, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x05, 0x00, 0x58, 0x55, 0x35, 0x00, 0x40, 0x55, 0x55, 0xc1,
|
|
||||||
0xab, 0xaa, 0xab, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xea,
|
|
||||||
0x57, 0xd5, 0x00, 0x00, 0x55, 0x55, 0x05, 0x00, 0x58, 0x55, 0x35, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xae, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x15, 0x00, 0x60, 0x55, 0xd5, 0x00, 0x00, 0x55, 0x55, 0x05, 0xc0,
|
|
||||||
0xab, 0xae, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xea,
|
|
||||||
0x57, 0x03, 0x00, 0x54, 0x55, 0x15, 0x00, 0x60, 0x55, 0xd5, 0x00, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x00, 0x80, 0x55, 0x55, 0x03, 0x00, 0x54, 0x55, 0x15, 0x00, 0xe0,
|
|
||||||
0xbb, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xfa,
|
|
||||||
0x0f, 0x00, 0x50, 0x55, 0x55, 0x00, 0x80, 0x55, 0x55, 0x03, 0x00, 0xd4,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x00, 0x56, 0x55, 0x0d, 0x00, 0x50, 0x55, 0x55, 0x00, 0x80, 0xd5,
|
|
||||||
0xab, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xea, 0xea,
|
|
||||||
0x03, 0x40, 0x55, 0x55, 0x01, 0x00, 0x56, 0x55, 0x0d, 0x00, 0x50, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x03, 0x58, 0x55, 0x35, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x56, 0xd5,
|
|
||||||
0xab, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xab, 0xea,
|
|
||||||
0x03, 0x55, 0x55, 0x05, 0x00, 0x58, 0x55, 0x35, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xab, 0xaa, 0xaa, 0xab, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0x63, 0x55, 0xd5, 0x00, 0x00, 0x55, 0x55, 0x05, 0x00, 0x58, 0x55, 0xf5,
|
|
||||||
0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xae, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x15, 0x00, 0x60, 0x55, 0xd5, 0x00, 0x00, 0x55, 0x55, 0xc5,
|
|
||||||
0xab, 0xaa, 0xae, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xeb,
|
|
||||||
0x57, 0x55, 0x03, 0x00, 0x54, 0x55, 0x15, 0x00, 0x60, 0x55, 0xd5, 0xc0,
|
|
||||||
0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xba, 0xaa, 0xaa, 0xea,
|
|
||||||
0x57, 0x55, 0x00, 0x80, 0x55, 0x55, 0x03, 0x00, 0x54, 0x55, 0x15, 0xc0,
|
|
||||||
0xab, 0xba, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xea,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#define zulu_width 96
|
|
||||||
#define zulu_height 64
|
|
||||||
static unsigned char zulu_bits[] PROGMEM = {
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0,
|
|
||||||
0x3f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xfa,
|
|
||||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4,
|
|
||||||
0xff, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xee,
|
|
||||||
0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xd5,
|
|
||||||
0xff, 0x2f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xfb,
|
|
||||||
0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xd5,
|
|
||||||
0xff, 0x3f, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xec, 0xee,
|
|
||||||
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0x8f, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xf0, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xba, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0x83, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0x3f, 0x22, 0x22, 0x22, 0x22, 0xb8, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0x88, 0x88, 0x88, 0x88, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0x2f, 0x22, 0x22, 0xa2, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xbf, 0x88, 0x88, 0xec, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x23, 0xa2, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x54, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xbe, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x57, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xea, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xab, 0xea, 0xbb, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x55, 0xd5, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xee, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0x7f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xaf, 0xaa, 0xaa, 0xba, 0xbb, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0x57, 0x55, 0x55, 0x75, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xab, 0xaa, 0xaa, 0xaa, 0xee, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xbf, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0xff, 0x5f, 0x55, 0x55, 0x55, 0x55, 0x5d, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0xff, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0x7f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xbf, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xee, 0xee, 0xee,
|
|
||||||
0xff, 0xff, 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xbb, 0xfb,
|
|
||||||
0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x55, 0xd5,
|
|
||||||
0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xee, 0xee,
|
|
||||||
0xff, 0x7f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xff, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xfb,
|
|
||||||
0xff, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x75, 0xd5,
|
|
||||||
0xff, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xee,
|
|
||||||
0xff, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5,
|
|
||||||
0xbf, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfe,
|
|
||||||
0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xdd,
|
|
||||||
0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
@@ -27,7 +27,6 @@
|
|||||||
#include "images/unknown.xbm" // unknown page indicator
|
#include "images/unknown.xbm" // unknown page indicator
|
||||||
#include "OBP60QRWiFi.h" // Functions lib for WiFi QR code
|
#include "OBP60QRWiFi.h" // Functions lib for WiFi QR code
|
||||||
#include "OBPSensorTask.h" // Functions lib for sensor data
|
#include "OBPSensorTask.h" // Functions lib for sensor data
|
||||||
#include "OBPTrackerTask.h" // Functions lib for tracker data
|
|
||||||
|
|
||||||
// Global vars
|
// Global vars
|
||||||
bool initComplete = false; // Initialization complete
|
bool initComplete = false; // Initialization complete
|
||||||
@@ -261,8 +260,10 @@ void registerAllPages(PageList &list){
|
|||||||
list.add(®isterPageFluid);
|
list.add(®isterPageFluid);
|
||||||
extern PageDescription registerPageSkyView;
|
extern PageDescription registerPageSkyView;
|
||||||
list.add(®isterPageSkyView);
|
list.add(®isterPageSkyView);
|
||||||
extern PageDescription registerPageTracker;
|
extern PageDescription registerPageNavigation;
|
||||||
list.add(®isterPageTracker);
|
list.add(®isterPageNavigation);
|
||||||
|
extern PageDescription registerPageDigitalOut;
|
||||||
|
list.add(®isterPageDigitalOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undervoltage detection for shutdown display
|
// Undervoltage detection for shutdown display
|
||||||
@@ -368,7 +369,6 @@ void OBP60Task(GwApi *api){
|
|||||||
bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
|
bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
|
||||||
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
|
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
|
||||||
uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
|
uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
|
||||||
bool tracker_enabled = api->getConfig()->getConfigItem(api->getConfig()->trackerType,true)->asString() != "NONE";
|
|
||||||
#ifdef BOARD_OBP40S3
|
#ifdef BOARD_OBP40S3
|
||||||
bool syspage_enabled = config->getBool(config->systemPage);
|
bool syspage_enabled = config->getBool(config->systemPage);
|
||||||
#endif
|
#endif
|
||||||
@@ -432,11 +432,11 @@ void OBP60Task(GwApi *api){
|
|||||||
#endif
|
#endif
|
||||||
LOG_DEBUG(GwLog::LOG,"...done");
|
LOG_DEBUG(GwLog::LOG,"...done");
|
||||||
|
|
||||||
int lastPage=pageNumber;
|
int lastPage=-1; // initialize with an impiossible value, so we can detect wether we are during startup and no page has been displayed yet
|
||||||
|
|
||||||
BoatValueList boatValues; //all the boat values for the api query
|
BoatValueList boatValues; //all the boat values for the api query
|
||||||
HstryBuf hstryBufList(960); // Create ring buffers for history storage of some boat data
|
HstryBuffers hstryBufList(1920, &boatValues, logger); // Create empty list of boat data history buffers
|
||||||
WindUtils trueWind(&boatValues); // Create helper object for true wind calculation
|
WindUtils trueWind(&boatValues, logger); // Create helper object for true wind calculation
|
||||||
//commonData.distanceformat=config->getString(xxx);
|
//commonData.distanceformat=config->getString(xxx);
|
||||||
//add all necessary data to common data
|
//add all necessary data to common data
|
||||||
|
|
||||||
@@ -479,21 +479,27 @@ void OBP60Task(GwApi *api){
|
|||||||
LOG_DEBUG(GwLog::DEBUG,"added fixed value %s to page %d",value->getName().c_str(),i);
|
LOG_DEBUG(GwLog::DEBUG,"added fixed value %s to page %d",value->getName().c_str(),i);
|
||||||
pages[i].parameters.values.push_back(value);
|
pages[i].parameters.values.push_back(value);
|
||||||
}
|
}
|
||||||
// Add boat history data to page parameters
|
|
||||||
pages[i].parameters.boatHstry = &hstryBufList;
|
// Read the specified boat data type of relevant pages and create a history buffer for each type
|
||||||
|
if (pages[i].parameters.pageName == "OneValue" || pages[i].parameters.pageName == "TwoValues" || pages[i].parameters.pageName == "WindPlot") {
|
||||||
|
for (auto pVal : pages[i].parameters.values) {
|
||||||
|
hstryBufList.addBuffer(pVal->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add list of history buffers to page parameters
|
||||||
|
pages[i].parameters.hstryBuffers = &hstryBufList;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add out of band system page (always available)
|
// add out of band system page (always available)
|
||||||
Page *syspage = allPages.pages[0]->creator(commonData);
|
Page *syspage = allPages.pages[0]->creator(commonData);
|
||||||
|
|
||||||
// Read all calibration data settings from config
|
|
||||||
calibrationData.readConfig(config, logger);
|
|
||||||
|
|
||||||
// Check user settings for true wind calculation
|
// Check user settings for true wind calculation
|
||||||
bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false);
|
bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false);
|
||||||
bool useSimuData = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
bool useSimuData = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
||||||
|
|
||||||
// Initialize history buffer for certain boat data
|
// Read all calibration data settings from config
|
||||||
hstryBufList.init(&boatValues, logger);
|
calibrationData.readConfig(config, logger);
|
||||||
|
|
||||||
// Display screenshot handler for HTTP request
|
// Display screenshot handler for HTTP request
|
||||||
// http://192.168.15.1/api/user/OBP60Task/screenshot
|
// http://192.168.15.1/api/user/OBP60Task/screenshot
|
||||||
@@ -515,16 +521,6 @@ void OBP60Task(GwApi *api){
|
|||||||
SharedData *shared=new SharedData(api);
|
SharedData *shared=new SharedData(api);
|
||||||
createSensorTask(shared);
|
createSensorTask(shared);
|
||||||
|
|
||||||
// Tracker task
|
|
||||||
if (tracker_enabled) {
|
|
||||||
TrackerData trackerData;
|
|
||||||
trackerData.api = api;
|
|
||||||
trackerData.logger = logger;
|
|
||||||
createTrackerTask(&trackerData);
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG(GwLog::LOG, "Tracker not enabled. No task created.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Task Loop
|
// Task Loop
|
||||||
//####################################################################################
|
//####################################################################################
|
||||||
|
|
||||||
@@ -724,8 +720,8 @@ void OBP60Task(GwApi *api){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Full display update afer a new selected page and 4s wait time
|
// Full display update afer a new selected page and 8s wait time
|
||||||
if(millis() > starttime4 + 4000 && delayedDisplayUpdate == true){
|
if(millis() > starttime4 + 8000 && delayedDisplayUpdate == true){
|
||||||
starttime1 = millis();
|
starttime1 = millis();
|
||||||
starttime2 = millis();
|
starttime2 = millis();
|
||||||
getdisplay().setFullWindow(); // Set full update
|
getdisplay().setFullWindow(); // Set full update
|
||||||
@@ -818,10 +814,10 @@ void OBP60Task(GwApi *api){
|
|||||||
api->getStatus(commonData.status);
|
api->getStatus(commonData.status);
|
||||||
|
|
||||||
if (calcTrueWnds) {
|
if (calcTrueWnds) {
|
||||||
trueWind.addTrueWind(api, &boatValues, logger);
|
trueWind.addWinds();
|
||||||
}
|
}
|
||||||
// Handle history buffers for TWD, TWS for wind plot page and other usage
|
// Handle history buffers for certain boat data for windplot page and other usage
|
||||||
hstryBufList.handleHstryBuf(useSimuData);
|
hstryBufList.handleHstryBufs(useSimuData, commonData);
|
||||||
|
|
||||||
// Clear display
|
// Clear display
|
||||||
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
|
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
|
||||||
@@ -858,8 +854,10 @@ void OBP60Task(GwApi *api){
|
|||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (lastPage != pageNumber){
|
if (lastPage != pageNumber){
|
||||||
pages[lastPage].page->leavePage(pages[lastPage].parameters); // call page cleanup code
|
if (lastPage != -1){ // skip cleanup if we are during startup, and no page has been displayed yet.
|
||||||
if (hasFRAM) fram.write(FRAM_PAGE_NO, pageNumber); // remember new page for device restart
|
pages[lastPage].page->leavePage(pages[lastPage].parameters); // call page cleanup code
|
||||||
|
if (hasFRAM) fram.write(FRAM_PAGE_NO, pageNumber); // remember new page for device restart
|
||||||
|
}
|
||||||
currentPage->setupKeys();
|
currentPage->setupKeys();
|
||||||
currentPage->displayNew(pages[pageNumber].parameters);
|
currentPage->displayNew(pages[pageNumber].parameters);
|
||||||
lastPage = pageNumber;
|
lastPage = pageNumber;
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ lib_deps =
|
|||||||
Wire
|
Wire
|
||||||
SPI
|
SPI
|
||||||
ESP32time
|
ESP32time
|
||||||
|
HTTPClient
|
||||||
|
WiFiClientSecure
|
||||||
esphome/AsyncTCP-esphome@2.0.1
|
esphome/AsyncTCP-esphome@2.0.1
|
||||||
robtillaart/PCF8574@0.3.9
|
robtillaart/PCF8574@0.3.9
|
||||||
adafruit/Adafruit Unified Sensor @ 1.1.13
|
adafruit/Adafruit Unified Sensor @ 1.1.13
|
||||||
@@ -74,7 +76,8 @@ lib_deps =
|
|||||||
SPI
|
SPI
|
||||||
SD
|
SD
|
||||||
ESP32time
|
ESP32time
|
||||||
PubSubClient
|
HTTPClient
|
||||||
|
WiFiClientSecure
|
||||||
esphome/AsyncTCP-esphome@2.0.1
|
esphome/AsyncTCP-esphome@2.0.1
|
||||||
robtillaart/PCF8574@0.3.9
|
robtillaart/PCF8574@0.3.9
|
||||||
adafruit/Adafruit Unified Sensor @ 1.1.13
|
adafruit/Adafruit Unified Sensor @ 1.1.13
|
||||||
@@ -100,8 +103,8 @@ build_flags=
|
|||||||
-D HARDWARE_V10 #OBP40 hardware revision V1.0 SKU:DIE07300S V1.1 (CrowPanel 4.2)
|
-D HARDWARE_V10 #OBP40 hardware revision V1.0 SKU:DIE07300S V1.1 (CrowPanel 4.2)
|
||||||
-D DISPLAY_GDEY042T81 #new E-Ink display from Good Display (Waveshare), R10 2.2 ohm - good (contast lost by shunshine)
|
-D DISPLAY_GDEY042T81 #new E-Ink display from Good Display (Waveshare), R10 2.2 ohm - good (contast lost by shunshine)
|
||||||
#-D DISPLAY_ZJY400300-042CAAMFGN #alternativ E-Ink display from ZZE Technology, R10 2.2 ohm - very good
|
#-D DISPLAY_ZJY400300-042CAAMFGN #alternativ E-Ink display from ZZE Technology, R10 2.2 ohm - very good
|
||||||
#-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh
|
-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh
|
||||||
#-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors
|
-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter
|
upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter
|
||||||
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
|
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
|
||||||
|
|||||||
840
lib/obp60task/puff.c
Normal file
840
lib/obp60task/puff.c
Normal file
@@ -0,0 +1,840 @@
|
|||||||
|
/*
|
||||||
|
* puff.c
|
||||||
|
* Copyright (C) 2002-2013 Mark Adler
|
||||||
|
* For conditions of distribution and use, see copyright notice in puff.h
|
||||||
|
* version 2.3, 21 Jan 2013
|
||||||
|
*
|
||||||
|
* puff.c is a simple inflate written to be an unambiguous way to specify the
|
||||||
|
* deflate format. It is not written for speed but rather simplicity. As a
|
||||||
|
* side benefit, this code might actually be useful when small code is more
|
||||||
|
* important than speed, such as bootstrap applications. For typical deflate
|
||||||
|
* data, zlib's inflate() is about four times as fast as puff(). zlib's
|
||||||
|
* inflate compiles to around 20K on my machine, whereas puff.c compiles to
|
||||||
|
* around 4K on my machine (a PowerPC using GNU cc). If the faster decode()
|
||||||
|
* function here is used, then puff() is only twice as slow as zlib's
|
||||||
|
* inflate().
|
||||||
|
*
|
||||||
|
* All dynamically allocated memory comes from the stack. The stack required
|
||||||
|
* is less than 2K bytes. This code is compatible with 16-bit int's and
|
||||||
|
* assumes that long's are at least 32 bits. puff.c uses the short data type,
|
||||||
|
* assumed to be 16 bits, for arrays in order to conserve memory. The code
|
||||||
|
* works whether integers are stored big endian or little endian.
|
||||||
|
*
|
||||||
|
* In the comments below are "Format notes" that describe the inflate process
|
||||||
|
* and document some of the less obvious aspects of the format. This source
|
||||||
|
* code is meant to supplement RFC 1951, which formally describes the deflate
|
||||||
|
* format:
|
||||||
|
*
|
||||||
|
* http://www.zlib.org/rfc-deflate.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change history:
|
||||||
|
*
|
||||||
|
* 1.0 10 Feb 2002 - First version
|
||||||
|
* 1.1 17 Feb 2002 - Clarifications of some comments and notes
|
||||||
|
* - Update puff() dest and source pointers on negative
|
||||||
|
* errors to facilitate debugging deflators
|
||||||
|
* - Remove longest from struct huffman -- not needed
|
||||||
|
* - Simplify offs[] index in construct()
|
||||||
|
* - Add input size and checking, using longjmp() to
|
||||||
|
* maintain easy readability
|
||||||
|
* - Use short data type for large arrays
|
||||||
|
* - Use pointers instead of long to specify source and
|
||||||
|
* destination sizes to avoid arbitrary 4 GB limits
|
||||||
|
* 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!),
|
||||||
|
* but leave simple version for readability
|
||||||
|
* - Make sure invalid distances detected if pointers
|
||||||
|
* are 16 bits
|
||||||
|
* - Fix fixed codes table error
|
||||||
|
* - Provide a scanning mode for determining size of
|
||||||
|
* uncompressed data
|
||||||
|
* 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly]
|
||||||
|
* - Add a puff.h file for the interface
|
||||||
|
* - Add braces in puff() for else do [Gailly]
|
||||||
|
* - Use indexes instead of pointers for readability
|
||||||
|
* 1.4 31 Mar 2002 - Simplify construct() code set check
|
||||||
|
* - Fix some comments
|
||||||
|
* - Add FIXLCODES #define
|
||||||
|
* 1.5 6 Apr 2002 - Minor comment fixes
|
||||||
|
* 1.6 7 Aug 2002 - Minor format changes
|
||||||
|
* 1.7 3 Mar 2003 - Added test code for distribution
|
||||||
|
* - Added zlib-like license
|
||||||
|
* 1.8 9 Jan 2004 - Added some comments on no distance codes case
|
||||||
|
* 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland]
|
||||||
|
* - Catch missing end-of-block symbol error
|
||||||
|
* 2.0 25 Jul 2008 - Add #define to permit distance too far back
|
||||||
|
* - Add option in TEST code for puff to write the data
|
||||||
|
* - Add option in TEST code to skip input bytes
|
||||||
|
* - Allow TEST code to read from piped stdin
|
||||||
|
* 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers
|
||||||
|
* - Avoid unsigned comparisons for even happier compilers
|
||||||
|
* 2.2 25 Apr 2010 - Fix bug in variable initializations [Oberhumer]
|
||||||
|
* - Add const where appropriate [Oberhumer]
|
||||||
|
* - Split if's and ?'s for coverage testing
|
||||||
|
* - Break out test code to separate file
|
||||||
|
* - Move NIL to puff.h
|
||||||
|
* - Allow incomplete code only if single code length is 1
|
||||||
|
* - Add full code coverage test to Makefile
|
||||||
|
* 2.3 21 Jan 2013 - Check for invalid code length codes in dynamic blocks
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
|
||||||
|
#include "puff.h" /* prototype for puff() */
|
||||||
|
|
||||||
|
#define local static /* for local function definitions */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximums for allocations and loops. It is not useful to change these --
|
||||||
|
* they are fixed by the deflate format.
|
||||||
|
*/
|
||||||
|
#define MAXBITS 15 /* maximum bits in a code */
|
||||||
|
#define MAXLCODES 286 /* maximum number of literal/length codes */
|
||||||
|
#define MAXDCODES 30 /* maximum number of distance codes */
|
||||||
|
#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
|
||||||
|
#define FIXLCODES 288 /* number of fixed literal/length codes */
|
||||||
|
|
||||||
|
/* input and output state */
|
||||||
|
struct state {
|
||||||
|
/* output state */
|
||||||
|
unsigned char *out; /* output buffer */
|
||||||
|
unsigned long outlen; /* available space at out */
|
||||||
|
unsigned long outcnt; /* bytes written to out so far */
|
||||||
|
|
||||||
|
/* input state */
|
||||||
|
const unsigned char *in; /* input buffer */
|
||||||
|
unsigned long inlen; /* available input at in */
|
||||||
|
unsigned long incnt; /* bytes read so far */
|
||||||
|
int bitbuf; /* bit buffer */
|
||||||
|
int bitcnt; /* number of bits in bit buffer */
|
||||||
|
|
||||||
|
/* input limit error return state for bits() and decode() */
|
||||||
|
jmp_buf env;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return need bits from the input stream. This always leaves less than
|
||||||
|
* eight bits in the buffer. bits() works properly for need == 0.
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - Bits are stored in bytes from the least significant bit to the most
|
||||||
|
* significant bit. Therefore bits are dropped from the bottom of the bit
|
||||||
|
* buffer, using shift right, and new bytes are appended to the top of the
|
||||||
|
* bit buffer, using shift left.
|
||||||
|
*/
|
||||||
|
local int bits(struct state *s, int need)
|
||||||
|
{
|
||||||
|
long val; /* bit accumulator (can use up to 20 bits) */
|
||||||
|
|
||||||
|
/* load at least need bits into val */
|
||||||
|
val = s->bitbuf;
|
||||||
|
while (s->bitcnt < need) {
|
||||||
|
if (s->incnt == s->inlen)
|
||||||
|
longjmp(s->env, 1); /* out of input */
|
||||||
|
val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
|
||||||
|
s->bitcnt += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* drop need bits and update buffer, always zero to seven bits left */
|
||||||
|
s->bitbuf = (int)(val >> need);
|
||||||
|
s->bitcnt -= need;
|
||||||
|
|
||||||
|
/* return need bits, zeroing the bits above that */
|
||||||
|
return (int)(val & ((1L << need) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a stored block.
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - After the two-bit stored block type (00), the stored block length and
|
||||||
|
* stored bytes are byte-aligned for fast copying. Therefore any leftover
|
||||||
|
* bits in the byte that has the last bit of the type, as many as seven, are
|
||||||
|
* discarded. The value of the discarded bits are not defined and should not
|
||||||
|
* be checked against any expectation.
|
||||||
|
*
|
||||||
|
* - The second inverted copy of the stored block length does not have to be
|
||||||
|
* checked, but it's probably a good idea to do so anyway.
|
||||||
|
*
|
||||||
|
* - A stored block can have zero length. This is sometimes used to byte-align
|
||||||
|
* subsets of the compressed data for random access or partial recovery.
|
||||||
|
*/
|
||||||
|
local int stored(struct state *s)
|
||||||
|
{
|
||||||
|
unsigned len; /* length of stored block */
|
||||||
|
|
||||||
|
/* discard leftover bits from current byte (assumes s->bitcnt < 8) */
|
||||||
|
s->bitbuf = 0;
|
||||||
|
s->bitcnt = 0;
|
||||||
|
|
||||||
|
/* get length and check against its one's complement */
|
||||||
|
if (s->incnt + 4 > s->inlen)
|
||||||
|
return 2; /* not enough input */
|
||||||
|
len = s->in[s->incnt++];
|
||||||
|
len |= s->in[s->incnt++] << 8;
|
||||||
|
if (s->in[s->incnt++] != (~len & 0xff) ||
|
||||||
|
s->in[s->incnt++] != ((~len >> 8) & 0xff))
|
||||||
|
return -2; /* didn't match complement! */
|
||||||
|
|
||||||
|
/* copy len bytes from in to out */
|
||||||
|
if (s->incnt + len > s->inlen)
|
||||||
|
return 2; /* not enough input */
|
||||||
|
if (s->out != NIL) {
|
||||||
|
if (s->outcnt + len > s->outlen)
|
||||||
|
return 1; /* not enough output space */
|
||||||
|
while (len--)
|
||||||
|
s->out[s->outcnt++] = s->in[s->incnt++];
|
||||||
|
}
|
||||||
|
else { /* just scanning */
|
||||||
|
s->outcnt += len;
|
||||||
|
s->incnt += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* done with a valid stored block */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
|
||||||
|
* each length, which for a canonical code are stepped through in order.
|
||||||
|
* symbol[] are the symbol values in canonical order, where the number of
|
||||||
|
* entries is the sum of the counts in count[]. The decoding process can be
|
||||||
|
* seen in the function decode() below.
|
||||||
|
*/
|
||||||
|
struct huffman {
|
||||||
|
short *count; /* number of symbols of each length */
|
||||||
|
short *symbol; /* canonically ordered symbols */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode a code from the stream s using huffman table h. Return the symbol or
|
||||||
|
* a negative value if there is an error. If all of the lengths are zero, i.e.
|
||||||
|
* an empty code, or if the code is incomplete and an invalid code is received,
|
||||||
|
* then -10 is returned after reading MAXBITS bits.
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - The codes as stored in the compressed data are bit-reversed relative to
|
||||||
|
* a simple integer ordering of codes of the same lengths. Hence below the
|
||||||
|
* bits are pulled from the compressed data one at a time and used to
|
||||||
|
* build the code value reversed from what is in the stream in order to
|
||||||
|
* permit simple integer comparisons for decoding. A table-based decoding
|
||||||
|
* scheme (as used in zlib) does not need to do this reversal.
|
||||||
|
*
|
||||||
|
* - The first code for the shortest length is all zeros. Subsequent codes of
|
||||||
|
* the same length are simply integer increments of the previous code. When
|
||||||
|
* moving up a length, a zero bit is appended to the code. For a complete
|
||||||
|
* code, the last code of the longest length will be all ones.
|
||||||
|
*
|
||||||
|
* - Incomplete codes are handled by this decoder, since they are permitted
|
||||||
|
* in the deflate format. See the format notes for fixed() and dynamic().
|
||||||
|
*/
|
||||||
|
#ifdef SLOW
|
||||||
|
local int decode(struct state *s, const struct huffman *h)
|
||||||
|
{
|
||||||
|
int len; /* current number of bits in code */
|
||||||
|
int code; /* len bits being decoded */
|
||||||
|
int first; /* first code of length len */
|
||||||
|
int count; /* number of codes of length len */
|
||||||
|
int index; /* index of first code of length len in symbol table */
|
||||||
|
|
||||||
|
code = first = index = 0;
|
||||||
|
for (len = 1; len <= MAXBITS; len++) {
|
||||||
|
code |= bits(s, 1); /* get next bit */
|
||||||
|
count = h->count[len];
|
||||||
|
if (code - count < first) /* if length len, return symbol */
|
||||||
|
return h->symbol[index + (code - first)];
|
||||||
|
index += count; /* else update for next length */
|
||||||
|
first += count;
|
||||||
|
first <<= 1;
|
||||||
|
code <<= 1;
|
||||||
|
}
|
||||||
|
return -10; /* ran out of codes */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A faster version of decode() for real applications of this code. It's not
|
||||||
|
* as readable, but it makes puff() twice as fast. And it only makes the code
|
||||||
|
* a few percent larger.
|
||||||
|
*/
|
||||||
|
#else /* !SLOW */
|
||||||
|
local int decode(struct state *s, const struct huffman *h)
|
||||||
|
{
|
||||||
|
int len; /* current number of bits in code */
|
||||||
|
int code; /* len bits being decoded */
|
||||||
|
int first; /* first code of length len */
|
||||||
|
int count; /* number of codes of length len */
|
||||||
|
int index; /* index of first code of length len in symbol table */
|
||||||
|
int bitbuf; /* bits from stream */
|
||||||
|
int left; /* bits left in next or left to process */
|
||||||
|
short *next; /* next number of codes */
|
||||||
|
|
||||||
|
bitbuf = s->bitbuf;
|
||||||
|
left = s->bitcnt;
|
||||||
|
code = first = index = 0;
|
||||||
|
len = 1;
|
||||||
|
next = h->count + 1;
|
||||||
|
while (1) {
|
||||||
|
while (left--) {
|
||||||
|
code |= bitbuf & 1;
|
||||||
|
bitbuf >>= 1;
|
||||||
|
count = *next++;
|
||||||
|
if (code - count < first) { /* if length len, return symbol */
|
||||||
|
s->bitbuf = bitbuf;
|
||||||
|
s->bitcnt = (s->bitcnt - len) & 7;
|
||||||
|
return h->symbol[index + (code - first)];
|
||||||
|
}
|
||||||
|
index += count; /* else update for next length */
|
||||||
|
first += count;
|
||||||
|
first <<= 1;
|
||||||
|
code <<= 1;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
left = (MAXBITS+1) - len;
|
||||||
|
if (left == 0)
|
||||||
|
break;
|
||||||
|
if (s->incnt == s->inlen)
|
||||||
|
longjmp(s->env, 1); /* out of input */
|
||||||
|
bitbuf = s->in[s->incnt++];
|
||||||
|
if (left > 8)
|
||||||
|
left = 8;
|
||||||
|
}
|
||||||
|
return -10; /* ran out of codes */
|
||||||
|
}
|
||||||
|
#endif /* SLOW */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given the list of code lengths length[0..n-1] representing a canonical
|
||||||
|
* Huffman code for n symbols, construct the tables required to decode those
|
||||||
|
* codes. Those tables are the number of codes of each length, and the symbols
|
||||||
|
* sorted by length, retaining their original order within each length. The
|
||||||
|
* return value is zero for a complete code set, negative for an over-
|
||||||
|
* subscribed code set, and positive for an incomplete code set. The tables
|
||||||
|
* can be used if the return value is zero or positive, but they cannot be used
|
||||||
|
* if the return value is negative. If the return value is zero, it is not
|
||||||
|
* possible for decode() using that table to return an error--any stream of
|
||||||
|
* enough bits will resolve to a symbol. If the return value is positive, then
|
||||||
|
* it is possible for decode() using that table to return an error for received
|
||||||
|
* codes past the end of the incomplete lengths.
|
||||||
|
*
|
||||||
|
* Not used by decode(), but used for error checking, h->count[0] is the number
|
||||||
|
* of the n symbols not in the code. So n - h->count[0] is the number of
|
||||||
|
* codes. This is useful for checking for incomplete codes that have more than
|
||||||
|
* one symbol, which is an error in a dynamic block.
|
||||||
|
*
|
||||||
|
* Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS
|
||||||
|
* This is assured by the construction of the length arrays in dynamic() and
|
||||||
|
* fixed() and is not verified by construct().
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - Permitted and expected examples of incomplete codes are one of the fixed
|
||||||
|
* codes and any code with a single symbol which in deflate is coded as one
|
||||||
|
* bit instead of zero bits. See the format notes for fixed() and dynamic().
|
||||||
|
*
|
||||||
|
* - Within a given code length, the symbols are kept in ascending order for
|
||||||
|
* the code bits definition.
|
||||||
|
*/
|
||||||
|
local int construct(struct huffman *h, const short *length, int n)
|
||||||
|
{
|
||||||
|
int symbol; /* current symbol when stepping through length[] */
|
||||||
|
int len; /* current length when stepping through h->count[] */
|
||||||
|
int left; /* number of possible codes left of current length */
|
||||||
|
short offs[MAXBITS+1]; /* offsets in symbol table for each length */
|
||||||
|
|
||||||
|
/* count number of codes of each length */
|
||||||
|
for (len = 0; len <= MAXBITS; len++)
|
||||||
|
h->count[len] = 0;
|
||||||
|
for (symbol = 0; symbol < n; symbol++)
|
||||||
|
(h->count[length[symbol]])++; /* assumes lengths are within bounds */
|
||||||
|
if (h->count[0] == n) /* no codes! */
|
||||||
|
return 0; /* complete, but decode() will fail */
|
||||||
|
|
||||||
|
/* check for an over-subscribed or incomplete set of lengths */
|
||||||
|
left = 1; /* one possible code of zero length */
|
||||||
|
for (len = 1; len <= MAXBITS; len++) {
|
||||||
|
left <<= 1; /* one more bit, double codes left */
|
||||||
|
left -= h->count[len]; /* deduct count from possible codes */
|
||||||
|
if (left < 0)
|
||||||
|
return left; /* over-subscribed--return negative */
|
||||||
|
} /* left > 0 means incomplete */
|
||||||
|
|
||||||
|
/* generate offsets into symbol table for each length for sorting */
|
||||||
|
offs[1] = 0;
|
||||||
|
for (len = 1; len < MAXBITS; len++)
|
||||||
|
offs[len + 1] = offs[len] + h->count[len];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* put symbols in table sorted by length, by symbol order within each
|
||||||
|
* length
|
||||||
|
*/
|
||||||
|
for (symbol = 0; symbol < n; symbol++)
|
||||||
|
if (length[symbol] != 0)
|
||||||
|
h->symbol[offs[length[symbol]]++] = symbol;
|
||||||
|
|
||||||
|
/* return zero for complete set, positive for incomplete set */
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode literal/length and distance codes until an end-of-block code.
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - Compressed data that is after the block type if fixed or after the code
|
||||||
|
* description if dynamic is a combination of literals and length/distance
|
||||||
|
* pairs terminated by and end-of-block code. Literals are simply Huffman
|
||||||
|
* coded bytes. A length/distance pair is a coded length followed by a
|
||||||
|
* coded distance to represent a string that occurs earlier in the
|
||||||
|
* uncompressed data that occurs again at the current location.
|
||||||
|
*
|
||||||
|
* - Literals, lengths, and the end-of-block code are combined into a single
|
||||||
|
* code of up to 286 symbols. They are 256 literals (0..255), 29 length
|
||||||
|
* symbols (257..285), and the end-of-block symbol (256).
|
||||||
|
*
|
||||||
|
* - There are 256 possible lengths (3..258), and so 29 symbols are not enough
|
||||||
|
* to represent all of those. Lengths 3..10 and 258 are in fact represented
|
||||||
|
* by just a length symbol. Lengths 11..257 are represented as a symbol and
|
||||||
|
* some number of extra bits that are added as an integer to the base length
|
||||||
|
* of the length symbol. The number of extra bits is determined by the base
|
||||||
|
* length symbol. These are in the static arrays below, lens[] for the base
|
||||||
|
* lengths and lext[] for the corresponding number of extra bits.
|
||||||
|
*
|
||||||
|
* - The reason that 258 gets its own symbol is that the longest length is used
|
||||||
|
* often in highly redundant files. Note that 258 can also be coded as the
|
||||||
|
* base value 227 plus the maximum extra value of 31. While a good deflate
|
||||||
|
* should never do this, it is not an error, and should be decoded properly.
|
||||||
|
*
|
||||||
|
* - If a length is decoded, including its extra bits if any, then it is
|
||||||
|
* followed a distance code. There are up to 30 distance symbols. Again
|
||||||
|
* there are many more possible distances (1..32768), so extra bits are added
|
||||||
|
* to a base value represented by the symbol. The distances 1..4 get their
|
||||||
|
* own symbol, but the rest require extra bits. The base distances and
|
||||||
|
* corresponding number of extra bits are below in the static arrays dist[]
|
||||||
|
* and dext[].
|
||||||
|
*
|
||||||
|
* - Literal bytes are simply written to the output. A length/distance pair is
|
||||||
|
* an instruction to copy previously uncompressed bytes to the output. The
|
||||||
|
* copy is from distance bytes back in the output stream, copying for length
|
||||||
|
* bytes.
|
||||||
|
*
|
||||||
|
* - Distances pointing before the beginning of the output data are not
|
||||||
|
* permitted.
|
||||||
|
*
|
||||||
|
* - Overlapped copies, where the length is greater than the distance, are
|
||||||
|
* allowed and common. For example, a distance of one and a length of 258
|
||||||
|
* simply copies the last byte 258 times. A distance of four and a length of
|
||||||
|
* twelve copies the last four bytes three times. A simple forward copy
|
||||||
|
* ignoring whether the length is greater than the distance or not implements
|
||||||
|
* this correctly. You should not use memcpy() since its behavior is not
|
||||||
|
* defined for overlapped arrays. You should not use memmove() or bcopy()
|
||||||
|
* since though their behavior -is- defined for overlapping arrays, it is
|
||||||
|
* defined to do the wrong thing in this case.
|
||||||
|
*/
|
||||||
|
local int codes(struct state *s,
|
||||||
|
const struct huffman *lencode,
|
||||||
|
const struct huffman *distcode)
|
||||||
|
{
|
||||||
|
int symbol; /* decoded symbol */
|
||||||
|
int len; /* length for copy */
|
||||||
|
unsigned dist; /* distance for copy */
|
||||||
|
static const short lens[29] = { /* Size base for length codes 257..285 */
|
||||||
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||||
|
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
|
||||||
|
static const short lext[29] = { /* Extra bits for length codes 257..285 */
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||||
|
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
|
||||||
|
static const short dists[30] = { /* Offset base for distance codes 0..29 */
|
||||||
|
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||||
|
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||||
|
8193, 12289, 16385, 24577};
|
||||||
|
static const short dext[30] = { /* Extra bits for distance codes 0..29 */
|
||||||
|
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||||
|
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||||
|
12, 12, 13, 13};
|
||||||
|
|
||||||
|
/* decode literals and length/distance pairs */
|
||||||
|
do {
|
||||||
|
symbol = decode(s, lencode);
|
||||||
|
if (symbol < 0)
|
||||||
|
return symbol; /* invalid symbol */
|
||||||
|
if (symbol < 256) { /* literal: symbol is the byte */
|
||||||
|
/* write out the literal */
|
||||||
|
if (s->out != NIL) {
|
||||||
|
if (s->outcnt == s->outlen)
|
||||||
|
return 1;
|
||||||
|
s->out[s->outcnt] = symbol;
|
||||||
|
}
|
||||||
|
s->outcnt++;
|
||||||
|
}
|
||||||
|
else if (symbol > 256) { /* length */
|
||||||
|
/* get and compute length */
|
||||||
|
symbol -= 257;
|
||||||
|
if (symbol >= 29)
|
||||||
|
return -10; /* invalid fixed code */
|
||||||
|
len = lens[symbol] + bits(s, lext[symbol]);
|
||||||
|
|
||||||
|
/* get and check distance */
|
||||||
|
symbol = decode(s, distcode);
|
||||||
|
if (symbol < 0)
|
||||||
|
return symbol; /* invalid symbol */
|
||||||
|
dist = dists[symbol] + bits(s, dext[symbol]);
|
||||||
|
#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||||||
|
if (dist > s->outcnt)
|
||||||
|
return -11; /* distance too far back */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* copy length bytes from distance bytes back */
|
||||||
|
if (s->out != NIL) {
|
||||||
|
if (s->outcnt + len > s->outlen)
|
||||||
|
return 1;
|
||||||
|
while (len--) {
|
||||||
|
s->out[s->outcnt] =
|
||||||
|
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||||||
|
dist > s->outcnt ?
|
||||||
|
0 :
|
||||||
|
#endif
|
||||||
|
s->out[s->outcnt - dist];
|
||||||
|
s->outcnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s->outcnt += len;
|
||||||
|
}
|
||||||
|
} while (symbol != 256); /* end of block symbol */
|
||||||
|
|
||||||
|
/* done with a valid fixed or dynamic block */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a fixed codes block.
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - This block type can be useful for compressing small amounts of data for
|
||||||
|
* which the size of the code descriptions in a dynamic block exceeds the
|
||||||
|
* benefit of custom codes for that block. For fixed codes, no bits are
|
||||||
|
* spent on code descriptions. Instead the code lengths for literal/length
|
||||||
|
* codes and distance codes are fixed. The specific lengths for each symbol
|
||||||
|
* can be seen in the "for" loops below.
|
||||||
|
*
|
||||||
|
* - The literal/length code is complete, but has two symbols that are invalid
|
||||||
|
* and should result in an error if received. This cannot be implemented
|
||||||
|
* simply as an incomplete code since those two symbols are in the "middle"
|
||||||
|
* of the code. They are eight bits long and the longest literal/length\
|
||||||
|
* code is nine bits. Therefore the code must be constructed with those
|
||||||
|
* symbols, and the invalid symbols must be detected after decoding.
|
||||||
|
*
|
||||||
|
* - The fixed distance codes also have two invalid symbols that should result
|
||||||
|
* in an error if received. Since all of the distance codes are the same
|
||||||
|
* length, this can be implemented as an incomplete code. Then the invalid
|
||||||
|
* codes are detected while decoding.
|
||||||
|
*/
|
||||||
|
local int fixed(struct state *s)
|
||||||
|
{
|
||||||
|
static int virgin = 1;
|
||||||
|
static short lencnt[MAXBITS+1], lensym[FIXLCODES];
|
||||||
|
static short distcnt[MAXBITS+1], distsym[MAXDCODES];
|
||||||
|
static struct huffman lencode, distcode;
|
||||||
|
|
||||||
|
/* build fixed huffman tables if first call (may not be thread safe) */
|
||||||
|
if (virgin) {
|
||||||
|
int symbol;
|
||||||
|
short lengths[FIXLCODES];
|
||||||
|
|
||||||
|
/* construct lencode and distcode */
|
||||||
|
lencode.count = lencnt;
|
||||||
|
lencode.symbol = lensym;
|
||||||
|
distcode.count = distcnt;
|
||||||
|
distcode.symbol = distsym;
|
||||||
|
|
||||||
|
/* literal/length table */
|
||||||
|
for (symbol = 0; symbol < 144; symbol++)
|
||||||
|
lengths[symbol] = 8;
|
||||||
|
for (; symbol < 256; symbol++)
|
||||||
|
lengths[symbol] = 9;
|
||||||
|
for (; symbol < 280; symbol++)
|
||||||
|
lengths[symbol] = 7;
|
||||||
|
for (; symbol < FIXLCODES; symbol++)
|
||||||
|
lengths[symbol] = 8;
|
||||||
|
construct(&lencode, lengths, FIXLCODES);
|
||||||
|
|
||||||
|
/* distance table */
|
||||||
|
for (symbol = 0; symbol < MAXDCODES; symbol++)
|
||||||
|
lengths[symbol] = 5;
|
||||||
|
construct(&distcode, lengths, MAXDCODES);
|
||||||
|
|
||||||
|
/* do this just once */
|
||||||
|
virgin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode data until end-of-block code */
|
||||||
|
return codes(s, &lencode, &distcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a dynamic codes block.
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - A dynamic block starts with a description of the literal/length and
|
||||||
|
* distance codes for that block. New dynamic blocks allow the compressor to
|
||||||
|
* rapidly adapt to changing data with new codes optimized for that data.
|
||||||
|
*
|
||||||
|
* - The codes used by the deflate format are "canonical", which means that
|
||||||
|
* the actual bits of the codes are generated in an unambiguous way simply
|
||||||
|
* from the number of bits in each code. Therefore the code descriptions
|
||||||
|
* are simply a list of code lengths for each symbol.
|
||||||
|
*
|
||||||
|
* - The code lengths are stored in order for the symbols, so lengths are
|
||||||
|
* provided for each of the literal/length symbols, and for each of the
|
||||||
|
* distance symbols.
|
||||||
|
*
|
||||||
|
* - If a symbol is not used in the block, this is represented by a zero as the
|
||||||
|
* code length. This does not mean a zero-length code, but rather that no
|
||||||
|
* code should be created for this symbol. There is no way in the deflate
|
||||||
|
* format to represent a zero-length code.
|
||||||
|
*
|
||||||
|
* - The maximum number of bits in a code is 15, so the possible lengths for
|
||||||
|
* any code are 1..15.
|
||||||
|
*
|
||||||
|
* - The fact that a length of zero is not permitted for a code has an
|
||||||
|
* interesting consequence. Normally if only one symbol is used for a given
|
||||||
|
* code, then in fact that code could be represented with zero bits. However
|
||||||
|
* in deflate, that code has to be at least one bit. So for example, if
|
||||||
|
* only a single distance base symbol appears in a block, then it will be
|
||||||
|
* represented by a single code of length one, in particular one 0 bit. This
|
||||||
|
* is an incomplete code, since if a 1 bit is received, it has no meaning,
|
||||||
|
* and should result in an error. So incomplete distance codes of one symbol
|
||||||
|
* should be permitted, and the receipt of invalid codes should be handled.
|
||||||
|
*
|
||||||
|
* - It is also possible to have a single literal/length code, but that code
|
||||||
|
* must be the end-of-block code, since every dynamic block has one. This
|
||||||
|
* is not the most efficient way to create an empty block (an empty fixed
|
||||||
|
* block is fewer bits), but it is allowed by the format. So incomplete
|
||||||
|
* literal/length codes of one symbol should also be permitted.
|
||||||
|
*
|
||||||
|
* - If there are only literal codes and no lengths, then there are no distance
|
||||||
|
* codes. This is represented by one distance code with zero bits.
|
||||||
|
*
|
||||||
|
* - The list of up to 286 length/literal lengths and up to 30 distance lengths
|
||||||
|
* are themselves compressed using Huffman codes and run-length encoding. In
|
||||||
|
* the list of code lengths, a 0 symbol means no code, a 1..15 symbol means
|
||||||
|
* that length, and the symbols 16, 17, and 18 are run-length instructions.
|
||||||
|
* Each of 16, 17, and 18 are followed by extra bits to define the length of
|
||||||
|
* the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10
|
||||||
|
* zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols
|
||||||
|
* are common, hence the special coding for zero lengths.
|
||||||
|
*
|
||||||
|
* - The symbols for 0..18 are Huffman coded, and so that code must be
|
||||||
|
* described first. This is simply a sequence of up to 19 three-bit values
|
||||||
|
* representing no code (0) or the code length for that symbol (1..7).
|
||||||
|
*
|
||||||
|
* - A dynamic block starts with three fixed-size counts from which is computed
|
||||||
|
* the number of literal/length code lengths, the number of distance code
|
||||||
|
* lengths, and the number of code length code lengths (ok, you come up with
|
||||||
|
* a better name!) in the code descriptions. For the literal/length and
|
||||||
|
* distance codes, lengths after those provided are considered zero, i.e. no
|
||||||
|
* code. The code length code lengths are received in a permuted order (see
|
||||||
|
* the order[] array below) to make a short code length code length list more
|
||||||
|
* likely. As it turns out, very short and very long codes are less likely
|
||||||
|
* to be seen in a dynamic code description, hence what may appear initially
|
||||||
|
* to be a peculiar ordering.
|
||||||
|
*
|
||||||
|
* - Given the number of literal/length code lengths (nlen) and distance code
|
||||||
|
* lengths (ndist), then they are treated as one long list of nlen + ndist
|
||||||
|
* code lengths. Therefore run-length coding can and often does cross the
|
||||||
|
* boundary between the two sets of lengths.
|
||||||
|
*
|
||||||
|
* - So to summarize, the code description at the start of a dynamic block is
|
||||||
|
* three counts for the number of code lengths for the literal/length codes,
|
||||||
|
* the distance codes, and the code length codes. This is followed by the
|
||||||
|
* code length code lengths, three bits each. This is used to construct the
|
||||||
|
* code length code which is used to read the remainder of the lengths. Then
|
||||||
|
* the literal/length code lengths and distance lengths are read as a single
|
||||||
|
* set of lengths using the code length codes. Codes are constructed from
|
||||||
|
* the resulting two sets of lengths, and then finally you can start
|
||||||
|
* decoding actual compressed data in the block.
|
||||||
|
*
|
||||||
|
* - For reference, a "typical" size for the code description in a dynamic
|
||||||
|
* block is around 80 bytes.
|
||||||
|
*/
|
||||||
|
local int dynamic(struct state *s)
|
||||||
|
{
|
||||||
|
int nlen, ndist, ncode; /* number of lengths in descriptor */
|
||||||
|
int index; /* index of lengths[] */
|
||||||
|
int err; /* construct() return value */
|
||||||
|
short lengths[MAXCODES]; /* descriptor code lengths */
|
||||||
|
short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */
|
||||||
|
short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */
|
||||||
|
struct huffman lencode, distcode; /* length and distance codes */
|
||||||
|
static const short order[19] = /* permutation of code length codes */
|
||||||
|
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
|
||||||
|
|
||||||
|
/* construct lencode and distcode */
|
||||||
|
lencode.count = lencnt;
|
||||||
|
lencode.symbol = lensym;
|
||||||
|
distcode.count = distcnt;
|
||||||
|
distcode.symbol = distsym;
|
||||||
|
|
||||||
|
/* get number of lengths in each table, check lengths */
|
||||||
|
nlen = bits(s, 5) + 257;
|
||||||
|
ndist = bits(s, 5) + 1;
|
||||||
|
ncode = bits(s, 4) + 4;
|
||||||
|
if (nlen > MAXLCODES || ndist > MAXDCODES)
|
||||||
|
return -3; /* bad counts */
|
||||||
|
|
||||||
|
/* read code length code lengths (really), missing lengths are zero */
|
||||||
|
for (index = 0; index < ncode; index++)
|
||||||
|
lengths[order[index]] = bits(s, 3);
|
||||||
|
for (; index < 19; index++)
|
||||||
|
lengths[order[index]] = 0;
|
||||||
|
|
||||||
|
/* build huffman table for code lengths codes (use lencode temporarily) */
|
||||||
|
err = construct(&lencode, lengths, 19);
|
||||||
|
if (err != 0) /* require complete code set here */
|
||||||
|
return -4;
|
||||||
|
|
||||||
|
/* read length/literal and distance code length tables */
|
||||||
|
index = 0;
|
||||||
|
while (index < nlen + ndist) {
|
||||||
|
int symbol; /* decoded value */
|
||||||
|
int len; /* last length to repeat */
|
||||||
|
|
||||||
|
symbol = decode(s, &lencode);
|
||||||
|
if (symbol < 0)
|
||||||
|
return symbol; /* invalid symbol */
|
||||||
|
if (symbol < 16) /* length in 0..15 */
|
||||||
|
lengths[index++] = symbol;
|
||||||
|
else { /* repeat instruction */
|
||||||
|
len = 0; /* assume repeating zeros */
|
||||||
|
if (symbol == 16) { /* repeat last length 3..6 times */
|
||||||
|
if (index == 0)
|
||||||
|
return -5; /* no last length! */
|
||||||
|
len = lengths[index - 1]; /* last length */
|
||||||
|
symbol = 3 + bits(s, 2);
|
||||||
|
}
|
||||||
|
else if (symbol == 17) /* repeat zero 3..10 times */
|
||||||
|
symbol = 3 + bits(s, 3);
|
||||||
|
else /* == 18, repeat zero 11..138 times */
|
||||||
|
symbol = 11 + bits(s, 7);
|
||||||
|
if (index + symbol > nlen + ndist)
|
||||||
|
return -6; /* too many lengths! */
|
||||||
|
while (symbol--) /* repeat last or zero symbol times */
|
||||||
|
lengths[index++] = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for end-of-block code -- there better be one! */
|
||||||
|
if (lengths[256] == 0)
|
||||||
|
return -9;
|
||||||
|
|
||||||
|
/* build huffman table for literal/length codes */
|
||||||
|
err = construct(&lencode, lengths, nlen);
|
||||||
|
if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
|
||||||
|
return -7; /* incomplete code ok only for single length 1 code */
|
||||||
|
|
||||||
|
/* build huffman table for distance codes */
|
||||||
|
err = construct(&distcode, lengths + nlen, ndist);
|
||||||
|
if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
|
||||||
|
return -8; /* incomplete code ok only for single length 1 code */
|
||||||
|
|
||||||
|
/* decode data until end-of-block code */
|
||||||
|
return codes(s, &lencode, &distcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inflate source to dest. On return, destlen and sourcelen are updated to the
|
||||||
|
* size of the uncompressed data and the size of the deflate data respectively.
|
||||||
|
* On success, the return value of puff() is zero. If there is an error in the
|
||||||
|
* source data, i.e. it is not in the deflate format, then a negative value is
|
||||||
|
* returned. If there is not enough input available or there is not enough
|
||||||
|
* output space, then a positive error is returned. In that case, destlen and
|
||||||
|
* sourcelen are not updated to facilitate retrying from the beginning with the
|
||||||
|
* provision of more input data or more output space. In the case of invalid
|
||||||
|
* inflate data (a negative error), the dest and source pointers are updated to
|
||||||
|
* facilitate the debugging of deflators.
|
||||||
|
*
|
||||||
|
* puff() also has a mode to determine the size of the uncompressed output with
|
||||||
|
* no output written. For this dest must be (unsigned char *)0. In this case,
|
||||||
|
* the input value of *destlen is ignored, and on return *destlen is set to the
|
||||||
|
* size of the uncompressed output.
|
||||||
|
*
|
||||||
|
* The return codes are:
|
||||||
|
*
|
||||||
|
* 2: available inflate data did not terminate
|
||||||
|
* 1: output space exhausted before completing inflate
|
||||||
|
* 0: successful inflate
|
||||||
|
* -1: invalid block type (type == 3)
|
||||||
|
* -2: stored block length did not match one's complement
|
||||||
|
* -3: dynamic block code description: too many length or distance codes
|
||||||
|
* -4: dynamic block code description: code lengths codes incomplete
|
||||||
|
* -5: dynamic block code description: repeat lengths with no first length
|
||||||
|
* -6: dynamic block code description: repeat more than specified lengths
|
||||||
|
* -7: dynamic block code description: invalid literal/length code lengths
|
||||||
|
* -8: dynamic block code description: invalid distance code lengths
|
||||||
|
* -9: dynamic block code description: missing end-of-block code
|
||||||
|
* -10: invalid literal/length or distance code in fixed or dynamic block
|
||||||
|
* -11: distance is too far back in fixed or dynamic block
|
||||||
|
*
|
||||||
|
* Format notes:
|
||||||
|
*
|
||||||
|
* - Three bits are read for each block to determine the kind of block and
|
||||||
|
* whether or not it is the last block. Then the block is decoded and the
|
||||||
|
* process repeated if it was not the last block.
|
||||||
|
*
|
||||||
|
* - The leftover bits in the last byte of the deflate data after the last
|
||||||
|
* block (if it was a fixed or dynamic block) are undefined and have no
|
||||||
|
* expected values to check.
|
||||||
|
*/
|
||||||
|
int puff(unsigned char *dest, /* pointer to destination pointer */
|
||||||
|
unsigned long *destlen, /* amount of output space */
|
||||||
|
const unsigned char *source, /* pointer to source data pointer */
|
||||||
|
unsigned long *sourcelen) /* amount of input available */
|
||||||
|
{
|
||||||
|
struct state s; /* input/output state */
|
||||||
|
int last, type; /* block information */
|
||||||
|
int err; /* return value */
|
||||||
|
|
||||||
|
/* initialize output state */
|
||||||
|
s.out = dest;
|
||||||
|
s.outlen = *destlen; /* ignored if dest is NIL */
|
||||||
|
s.outcnt = 0;
|
||||||
|
|
||||||
|
/* initialize input state */
|
||||||
|
s.in = source;
|
||||||
|
s.inlen = *sourcelen;
|
||||||
|
s.incnt = 0;
|
||||||
|
s.bitbuf = 0;
|
||||||
|
s.bitcnt = 0;
|
||||||
|
|
||||||
|
/* return if bits() or decode() tries to read past available input */
|
||||||
|
if (setjmp(s.env) != 0) /* if came back here via longjmp() */
|
||||||
|
err = 2; /* then skip do-loop, return error */
|
||||||
|
else {
|
||||||
|
/* process blocks until last block or error */
|
||||||
|
do {
|
||||||
|
last = bits(&s, 1); /* one if last block */
|
||||||
|
type = bits(&s, 2); /* block type 0..3 */
|
||||||
|
err = type == 0 ?
|
||||||
|
stored(&s) :
|
||||||
|
(type == 1 ?
|
||||||
|
fixed(&s) :
|
||||||
|
(type == 2 ?
|
||||||
|
dynamic(&s) :
|
||||||
|
-1)); /* type == 3, invalid */
|
||||||
|
if (err != 0)
|
||||||
|
break; /* return with error */
|
||||||
|
} while (!last);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update the lengths and return */
|
||||||
|
if (err <= 0) {
|
||||||
|
*destlen = s.outcnt;
|
||||||
|
*sourcelen = s.incnt;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
35
lib/obp60task/puff.h
Normal file
35
lib/obp60task/puff.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* puff.h
|
||||||
|
Copyright (C) 2002-2013 Mark Adler, all rights reserved
|
||||||
|
version 2.3, 21 Jan 2013
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the author be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
Mark Adler madler@alumni.caltech.edu
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See puff.c for purpose and usage.
|
||||||
|
*/
|
||||||
|
#ifndef NIL
|
||||||
|
# define NIL ((unsigned char *)0) /* for no output option */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int puff(unsigned char *dest, /* pointer to destination pointer */
|
||||||
|
unsigned long *destlen, /* amount of output space */
|
||||||
|
const unsigned char *source, /* pointer to source data pointer */
|
||||||
|
unsigned long *sourcelen); /* amount of input available */
|
||||||
Reference in New Issue
Block a user