mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-03 08:30:45 +00:00
just a cleanup of the graphics
This commit is contained in:
829
src/graphics/Screen.cpp
Normal file
829
src/graphics/Screen.cpp
Normal file
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
|
||||
SSD1306 - Screen module
|
||||
|
||||
Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "configuration.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "Screen.h"
|
||||
#include "utils.h"
|
||||
#include "configs.h"
|
||||
|
||||
using namespace meshtastic; /** @todo remove */
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
// A text message frame + debug frame + all the node infos
|
||||
static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||
static char btPIN[16] = "888888";
|
||||
|
||||
uint8_t imgBattery[16] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C };
|
||||
uint8_t imgSatellite[8] = { 0x70, 0x71, 0x22, 0xFA, 0xFA, 0x22, 0x71, 0x70 };
|
||||
|
||||
uint32_t dopThresholds[5] = { 2000, 1000, 500, 200, 100 };
|
||||
|
||||
#ifdef SHOW_REDRAWS
|
||||
static bool heartbeat = false;
|
||||
#endif
|
||||
|
||||
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// draw an xbm image.
|
||||
// Please note that everything that should be transitioned
|
||||
// needs to be drawn relative to x and y
|
||||
display->drawXbm(x + 32, y, icon_width, icon_height, (const uint8_t *)icon_bits);
|
||||
|
||||
display->setFont(ArialMT_Plain_16);
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(64 + x, SCREEN_HEIGHT - FONT_HEIGHT_16, "meshtastic.org");
|
||||
display->setFont(ArialMT_Plain_10);
|
||||
const char *region = xstr(HW_VERSION);
|
||||
if (*region && region[3] == '-') // Skip past 1.0- in the 1.0-EU865 string
|
||||
region += 4;
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%s",
|
||||
xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long
|
||||
display->drawString(SCREEN_WIDTH - 20, 0, buf);
|
||||
}
|
||||
|
||||
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(ArialMT_Plain_16);
|
||||
display->drawString(64 + x, y, "Bluetooth");
|
||||
|
||||
display->setFont(ArialMT_Plain_10);
|
||||
display->drawString(64 + x, FONT_HEIGHT + y + 2, "Enter this code");
|
||||
|
||||
display->setFont(ArialMT_Plain_24);
|
||||
display->drawString(64 + x, 26 + y, btPIN);
|
||||
|
||||
display->setFont(ArialMT_Plain_10);
|
||||
char buf[30];
|
||||
const char *name = "Name: ";
|
||||
strcpy(buf, name);
|
||||
strcat(buf, getDeviceName());
|
||||
display->drawString(64 + x, 48 + y, buf);
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
displayedNodeNum = 0; // Not currently showing a node pane
|
||||
|
||||
MeshPacket &mp = devicestate.rx_text_message;
|
||||
NodeInfo *node = nodeDB.getNode(mp.from);
|
||||
// DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from,
|
||||
// mp.decoded.variant.data.decoded.bytes);
|
||||
|
||||
// Demo for drawStringMaxWidth:
|
||||
// with the third parameter you can define the width after which words will
|
||||
// be wrapped. Currently only spaces and "-" are allowed for wrapping
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(ArialMT_Plain_16);
|
||||
String sender = (node && node->has_user) ? node->user.short_name : "???";
|
||||
display->drawString(0 + x, 0 + y, sender);
|
||||
display->setFont(ArialMT_Plain_10);
|
||||
|
||||
// the max length of this buffer is much longer than we can possibly print
|
||||
static char tempBuf[96];
|
||||
assert(mp.decoded.which_payload == SubPacket_data_tag);
|
||||
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
|
||||
|
||||
display->drawStringMaxWidth(4 + x, 10 + y, 128, tempBuf);
|
||||
}
|
||||
|
||||
/// Draw a series of fields in a column, wrapping to multiple colums if needed
|
||||
static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
||||
{
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
const char **f = fields;
|
||||
int xo = x, yo = y;
|
||||
while (*f) {
|
||||
display->drawString(xo, yo, *f);
|
||||
yo += FONT_HEIGHT;
|
||||
if (yo > SCREEN_HEIGHT - FONT_HEIGHT) {
|
||||
xo += SCREEN_WIDTH / 2;
|
||||
yo = 0;
|
||||
}
|
||||
f++;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/// Draw a series of fields in a row, wrapping to multiple rows if needed
|
||||
/// @return the max y we ended up printing to
|
||||
static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
||||
{
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
const char **f = fields;
|
||||
int xo = x, yo = y;
|
||||
const int COLUMNS = 2; // hardwired for two columns per row....
|
||||
int col = 0; // track which column we are on
|
||||
while (*f) {
|
||||
display->drawString(xo, yo, *f);
|
||||
xo += SCREEN_WIDTH / COLUMNS;
|
||||
// Wrap to next row, if needed.
|
||||
if (++col >= COLUMNS) {
|
||||
xo = x;
|
||||
yo += FONT_HEIGHT;
|
||||
col = 0;
|
||||
}
|
||||
f++;
|
||||
}
|
||||
if (col != 0) {
|
||||
// Include last incomplete line in our total.
|
||||
yo += FONT_HEIGHT;
|
||||
}
|
||||
|
||||
return yo;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
|
||||
static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
|
||||
{
|
||||
static const uint8_t powerBar[3] = {0x81, 0xBD, 0xBD};
|
||||
static const uint8_t lightning[8] = {0xA1, 0xA1, 0xA5, 0xAD, 0xB5, 0xA5, 0x85, 0x85};
|
||||
// Clear the bar area on the battery image
|
||||
for (int i = 1; i < 14; i++) {
|
||||
imgBuffer[i] = 0x81;
|
||||
}
|
||||
// If charging, draw a charging indicator
|
||||
if (powerStatus->getIsCharging()) {
|
||||
memcpy(imgBuffer + 3, lightning, 8);
|
||||
// If not charging, Draw power bars
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (powerStatus->getBatteryChargePercent() >= 25 * i)
|
||||
memcpy(imgBuffer + 1 + (i * 3), powerBar, 3);
|
||||
}
|
||||
}
|
||||
display->drawFastImage(x, y, 16, 8, imgBuffer);
|
||||
}
|
||||
|
||||
// Draw nodes status
|
||||
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *nodeStatus)
|
||||
{
|
||||
char usersString[20];
|
||||
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
||||
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||
display->drawString(x + 10, y - 2, usersString);
|
||||
}
|
||||
|
||||
// Draw GPS status summary
|
||||
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
if (!gps->getIsConnected())
|
||||
{
|
||||
display->drawString(x, y - 2, "No GPS");
|
||||
return;
|
||||
}
|
||||
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
|
||||
if (!gps->getHasLock())
|
||||
{
|
||||
display->drawString(x + 8, y - 2, "No sats");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
char satsString[3];
|
||||
uint8_t bar[2] = { 0 };
|
||||
|
||||
//Draw DOP signal bars
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
if (gps->getDOP() <= dopThresholds[i])
|
||||
bar[0] = ~((1 << (5 - i)) - 1);
|
||||
else
|
||||
bar[0] = 0b10000000;
|
||||
//bar[1] = bar[0];
|
||||
display->drawFastImage(x + 9 + (i * 2), y, 2, 8, bar);
|
||||
}
|
||||
|
||||
//Draw satellite image
|
||||
display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
|
||||
|
||||
//Draw the number of satellites
|
||||
sprintf(satsString, "%d", gps->getNumSatellites());
|
||||
display->drawString(x + 34, y - 2, satsString);
|
||||
}
|
||||
}
|
||||
|
||||
/// Ported from my old java code, returns distance in meters along the globe
|
||||
/// surface (by magic?)
|
||||
static float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
||||
{
|
||||
double pk = (180 / 3.14169);
|
||||
double a1 = lat_a / pk;
|
||||
double a2 = lng_a / pk;
|
||||
double b1 = lat_b / pk;
|
||||
double b2 = lng_b / pk;
|
||||
double cos_b1 = cos(b1);
|
||||
double cos_a1 = cos(a1);
|
||||
double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2);
|
||||
double t2 = cos_a1 * sin(a2) * cos_b1 * sin(b2);
|
||||
double t3 = sin(a1) * sin(b1);
|
||||
double tt = acos(t1 + t2 + t3);
|
||||
if (isnan(tt))
|
||||
tt = 0.0; // Must have been the same point?
|
||||
|
||||
return (float)(6366000 * tt);
|
||||
}
|
||||
|
||||
static inline double toRadians(double deg)
|
||||
{
|
||||
return deg * PI / 180;
|
||||
}
|
||||
|
||||
static inline double toDegrees(double r)
|
||||
{
|
||||
return r * 180 / PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bearing in degrees between two points on Earth. Ported from my
|
||||
* old Gaggle android app.
|
||||
*
|
||||
* @param lat1
|
||||
* Latitude of the first point
|
||||
* @param lon1
|
||||
* Longitude of the first point
|
||||
* @param lat2
|
||||
* Latitude of the second point
|
||||
* @param lon2
|
||||
* Longitude of the second point
|
||||
* @return Bearing between the two points in radians. A value of 0 means due
|
||||
* north.
|
||||
*/
|
||||
static float bearing(double lat1, double lon1, double lat2, double lon2)
|
||||
{
|
||||
double lat1Rad = toRadians(lat1);
|
||||
double lat2Rad = toRadians(lat2);
|
||||
double deltaLonRad = toRadians(lon2 - lon1);
|
||||
double y = sin(deltaLonRad) * cos(lat2Rad);
|
||||
double x = cos(lat1Rad) * sin(lat2Rad) - (sin(lat1Rad) * cos(lat2Rad) * cos(deltaLonRad));
|
||||
return atan2(y, x);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/// A basic 2D point class for drawing
|
||||
class Point
|
||||
{
|
||||
public:
|
||||
float x, y;
|
||||
|
||||
Point(float _x, float _y) : x(_x), y(_y) {}
|
||||
|
||||
/// Apply a rotation around zero (standard rotation matrix math)
|
||||
void rotate(float radian)
|
||||
{
|
||||
float cos = cosf(radian), sin = sinf(radian);
|
||||
float rx = x * cos - y * sin, ry = x * sin + y * cos;
|
||||
|
||||
x = rx;
|
||||
y = ry;
|
||||
}
|
||||
|
||||
void translate(int16_t dx, int dy)
|
||||
{
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
|
||||
void scale(float f)
|
||||
{
|
||||
x *= f;
|
||||
y *= f;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void drawLine(OLEDDisplay *d, const Point &p1, const Point &p2)
|
||||
{
|
||||
d->drawLine(p1.x, p1.y, p2.x, p2.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a recent lat/lon return a guess of the heading the user is walking on.
|
||||
*
|
||||
* We keep a series of "after you've gone 10 meters, what is your heading since
|
||||
* the last reference point?"
|
||||
*/
|
||||
static float estimatedHeading(double lat, double lon)
|
||||
{
|
||||
static double oldLat, oldLon;
|
||||
static float b;
|
||||
|
||||
if (oldLat == 0) {
|
||||
// just prepare for next time
|
||||
oldLat = lat;
|
||||
oldLon = lon;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
float d = latLongToMeter(oldLat, oldLon, lat, lon);
|
||||
if (d < 10) // haven't moved enough, just keep current bearing
|
||||
return b;
|
||||
|
||||
b = bearing(oldLat, oldLon, lat, lon);
|
||||
oldLat = lat;
|
||||
oldLon = lon;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Sometimes we will have Position objects that only have a time, so check for
|
||||
/// valid lat/lon
|
||||
static bool hasPosition(NodeInfo *n)
|
||||
{
|
||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
||||
}
|
||||
|
||||
/// We will skip one node - the one for us, so we just blindly loop over all
|
||||
/// nodes
|
||||
static size_t nodeIndex;
|
||||
static int8_t prevFrame = -1;
|
||||
|
||||
// Draw the arrow pointing to a node's location
|
||||
static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian)
|
||||
{
|
||||
Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially
|
||||
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
|
||||
Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY);
|
||||
|
||||
|
||||
Point *arrowPoints[] = {&tip, &tail, &leftArrow, &rightArrow};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
arrowPoints[i]->rotate(headingRadian);
|
||||
arrowPoints[i]->scale(COMPASS_DIAM * 0.6);
|
||||
arrowPoints[i]->translate(compassX, compassY);
|
||||
}
|
||||
drawLine(display, tip, tail);
|
||||
drawLine(display, leftArrow, tip);
|
||||
drawLine(display, rightArrow, tip);
|
||||
}
|
||||
|
||||
// Draw the compass heading
|
||||
static void drawCompassHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading)
|
||||
{
|
||||
Point N1(-0.04f, -0.65f), N2( 0.04f, -0.65f);
|
||||
Point N3(-0.04f, -0.55f), N4( 0.04f, -0.55f);
|
||||
Point *rosePoints[] = {&N1, &N2, &N3, &N4};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
rosePoints[i]->rotate(myHeading);
|
||||
rosePoints[i]->scale(COMPASS_DIAM);
|
||||
rosePoints[i]->translate(compassX, compassY);
|
||||
}
|
||||
drawLine(display, N1, N3);
|
||||
drawLine(display, N2, N4);
|
||||
drawLine(display, N1, N4);
|
||||
}
|
||||
|
||||
/// Convert an integer GPS coords to a floating point
|
||||
#define DegD(i) (i * 1e-7)
|
||||
|
||||
static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// We only advance our nodeIndex if the frame # has changed - because
|
||||
// drawNodeInfo will be called repeatedly while the frame is shown
|
||||
if (state->currentFrame != prevFrame) {
|
||||
prevFrame = state->currentFrame;
|
||||
|
||||
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
|
||||
NodeInfo *n = nodeDB.getNodeByIndex(nodeIndex);
|
||||
if (n->num == nodeDB.getNodeNum()) {
|
||||
// Don't show our node, just skip to next
|
||||
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
|
||||
n = nodeDB.getNodeByIndex(nodeIndex);
|
||||
}
|
||||
displayedNodeNum = n->num;
|
||||
|
||||
// We just changed to a new node screen, ask that node for updated state if it's older than 2 minutes
|
||||
if(sinceLastSeen(n) > 120)
|
||||
{
|
||||
service.sendNetworkPing(displayedNodeNum, true);
|
||||
}
|
||||
}
|
||||
|
||||
NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
|
||||
|
||||
display->setFont(ArialMT_Plain_10);
|
||||
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
const char *username = node->has_user ? node->user.long_name : "Unknown Name";
|
||||
|
||||
static char signalStr[20];
|
||||
snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100));
|
||||
|
||||
uint32_t agoSecs = sinceLastSeen(node);
|
||||
static char lastStr[20];
|
||||
if (agoSecs < 120) // last 2 mins?
|
||||
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
|
||||
else if (agoSecs < 120 * 60) // last 2 hrs
|
||||
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
||||
else
|
||||
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
|
||||
|
||||
static char distStr[20];
|
||||
strcpy(distStr, "? km"); // might not have location data
|
||||
float headingRadian;
|
||||
NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
|
||||
// coordinates for the center of the compass/circle
|
||||
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
||||
bool hasNodeHeading = false;
|
||||
|
||||
if(ourNode && hasPosition(ourNode))
|
||||
{
|
||||
Position &op = ourNode->position;
|
||||
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
drawCompassHeading(display, compassX, compassY, myHeading);
|
||||
|
||||
if(hasPosition(node))
|
||||
{
|
||||
// display direction toward node
|
||||
hasNodeHeading = true;
|
||||
Position &p = node->position;
|
||||
float d = latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
|
||||
// FIXME, also keep the guess at the operators heading and add/substract
|
||||
// it. currently we don't do this and instead draw north up only.
|
||||
float bearingToOther = bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
headingRadian = bearingToOther - myHeading;
|
||||
drawNodeHeading(display, compassX, compassY, headingRadian);
|
||||
}
|
||||
}
|
||||
if(!hasNodeHeading)
|
||||
// direction to node is unknown so display question mark
|
||||
// Debug info for gps lock errors
|
||||
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
|
||||
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?");
|
||||
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
|
||||
|
||||
|
||||
// Must be after distStr is populated
|
||||
drawColumns(display, x, y, fields);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void _screen_header()
|
||||
{
|
||||
if (!disp)
|
||||
return;
|
||||
|
||||
// Message count
|
||||
//snprintf(buffer, sizeof(buffer), "#%03d", ttn_get_count() % 1000);
|
||||
//display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
//display->drawString(0, 2, buffer);
|
||||
|
||||
// Datetime
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(display->getWidth()/2, 2, gps.getTimeStr());
|
||||
|
||||
// Satellite count
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
char buffer[10];
|
||||
display->drawString(display->getWidth() - SATELLITE_IMAGE_WIDTH - 4, 2, itoa(gps.satellites.value(), buffer, 10));
|
||||
display->drawXbm(display->getWidth() - SATELLITE_IMAGE_WIDTH, 0, SATELLITE_IMAGE_WIDTH, SATELLITE_IMAGE_HEIGHT, SATELLITE_IMAGE);
|
||||
}
|
||||
#endif
|
||||
|
||||
Screen::Screen(uint8_t address, int sda, int scl) : cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) {}
|
||||
|
||||
void Screen::handleSetOn(bool on)
|
||||
{
|
||||
if (!useDisplay)
|
||||
return;
|
||||
|
||||
if (on != screenOn) {
|
||||
if (on) {
|
||||
DEBUG_MSG("Turning on screen\n");
|
||||
dispdev.displayOn();
|
||||
dispdev.displayOn();
|
||||
} else {
|
||||
DEBUG_MSG("Turning off screen\n");
|
||||
dispdev.displayOff();
|
||||
}
|
||||
screenOn = on;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::setup()
|
||||
{
|
||||
concurrency::PeriodicTask::setup();
|
||||
|
||||
// We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device
|
||||
// is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device.
|
||||
useDisplay = true;
|
||||
|
||||
dispdev.resetOrientation();
|
||||
|
||||
// Initialising the UI will init the display too.
|
||||
ui.init();
|
||||
ui.setTimePerTransition(300); // msecs
|
||||
ui.setIndicatorPosition(BOTTOM);
|
||||
// Defines where the first frame is located in the bar.
|
||||
ui.setIndicatorDirection(LEFT_RIGHT);
|
||||
ui.setFrameAnimation(SLIDE_LEFT);
|
||||
// Don't show the page swipe dots while in boot screen.
|
||||
ui.disableAllIndicators();
|
||||
// Store a pointer to Screen so we can get to it from static functions.
|
||||
ui.getUiState()->userData = this;
|
||||
|
||||
// Set the utf8 conversion function
|
||||
dispdev.setFontTableLookupFunction(customFontTableLookup);
|
||||
|
||||
// Add frames.
|
||||
static FrameCallback bootFrames[] = {drawBootScreen};
|
||||
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
|
||||
ui.setFrames(bootFrames, bootFrameCount);
|
||||
// No overlays.
|
||||
ui.setOverlays(nullptr, 0);
|
||||
|
||||
// Require presses to switch between frames.
|
||||
ui.disableAutoTransition();
|
||||
|
||||
// Set up a log buffer with 3 lines, 32 chars each.
|
||||
dispdev.setLogBuffer(3, 32);
|
||||
|
||||
#ifdef FLIP_SCREEN_VERTICALLY
|
||||
dispdev.flipScreenVertically();
|
||||
#endif
|
||||
|
||||
// Turn on the display.
|
||||
handleSetOn(true);
|
||||
|
||||
// On some ssd1306 clones, the first draw command is discarded, so draw it
|
||||
// twice initially.
|
||||
ui.update();
|
||||
ui.update();
|
||||
|
||||
// Subscribe to status updates
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
}
|
||||
|
||||
void Screen::doTask()
|
||||
{
|
||||
// If we don't have a screen, don't ever spend any CPU for us.
|
||||
if (!useDisplay) {
|
||||
setPeriod(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process incoming commands.
|
||||
for (;;) {
|
||||
ScreenCmd cmd;
|
||||
if (!cmdQueue.dequeue(&cmd, 0)) {
|
||||
break;
|
||||
}
|
||||
switch (cmd.cmd) {
|
||||
case Cmd::SET_ON:
|
||||
handleSetOn(true);
|
||||
break;
|
||||
case Cmd::SET_OFF:
|
||||
handleSetOn(false);
|
||||
break;
|
||||
case Cmd::ON_PRESS:
|
||||
handleOnPress();
|
||||
break;
|
||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||
break;
|
||||
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
|
||||
case Cmd::STOP_BOOT_SCREEN:
|
||||
setFrames();
|
||||
break;
|
||||
case Cmd::PRINT:
|
||||
handlePrint(cmd.print_text);
|
||||
free(cmd.print_text);
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("BUG: invalid cmd");
|
||||
}
|
||||
}
|
||||
|
||||
if (!screenOn) { // If we didn't just wake and the screen is still off, then
|
||||
// stop updating until it is on again
|
||||
setPeriod(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch to a low framerate (to save CPU) when we are not in transition
|
||||
// but we should only call setTargetFPS when framestate changes, because
|
||||
// otherwise that breaks animations.
|
||||
if (targetFramerate != IDLE_FRAMERATE && ui.getUiState()->frameState == FIXED) {
|
||||
// oldFrameState = ui.getUiState()->frameState;
|
||||
DEBUG_MSG("Setting idle framerate\n");
|
||||
targetFramerate = IDLE_FRAMERATE;
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
}
|
||||
|
||||
// While showing the bootscreen or Bluetooth pair screen all of our
|
||||
// standard screen switching is stopped.
|
||||
if (showingNormalScreen) {
|
||||
// standard screen loop handling here
|
||||
}
|
||||
|
||||
ui.update();
|
||||
|
||||
// DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate,
|
||||
// ui.getUiState()->frameState); If we are scrolling we need to be called
|
||||
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
|
||||
// as fast as we really need so that any rounding errors still result with
|
||||
// the correct framerate
|
||||
setPeriod(1000 / targetFramerate);
|
||||
}
|
||||
|
||||
void Screen::drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
Screen *screen = reinterpret_cast<Screen *>(state->userData);
|
||||
screen->debugInfo.drawFrame(display, state, x, y);
|
||||
}
|
||||
|
||||
// restore our regular frame list
|
||||
void Screen::setFrames()
|
||||
{
|
||||
DEBUG_MSG("showing standard frames\n");
|
||||
showingNormalScreen = true;
|
||||
|
||||
// We don't show the node info our our node (if we have it yet - we should)
|
||||
size_t numnodes = nodeStatus->getNumTotal();
|
||||
if (numnodes > 0)
|
||||
numnodes--;
|
||||
|
||||
size_t numframes = 0;
|
||||
|
||||
// If we have a text message - show it first
|
||||
if (devicestate.has_rx_text_message)
|
||||
normalFrames[numframes++] = drawTextMessageFrame;
|
||||
|
||||
// then all the nodes
|
||||
for (size_t i = 0; i < numnodes; i++)
|
||||
normalFrames[numframes++] = drawNodeInfo;
|
||||
|
||||
// then the debug info
|
||||
//
|
||||
// Since frames are basic function pointers, we have to use a helper to
|
||||
// call a method on debugInfo object.
|
||||
normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline;
|
||||
|
||||
ui.setFrames(normalFrames, numframes);
|
||||
ui.enableAllIndicators();
|
||||
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||
// just changed)
|
||||
}
|
||||
|
||||
void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
||||
{
|
||||
DEBUG_MSG("showing bluetooth screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback btFrames[] = {drawFrameBluetooth};
|
||||
|
||||
snprintf(btPIN, sizeof(btPIN), "%06u", pin);
|
||||
|
||||
ui.disableAllIndicators();
|
||||
ui.setFrames(btFrames, 1);
|
||||
}
|
||||
|
||||
void Screen::handlePrint(const char *text)
|
||||
{
|
||||
DEBUG_MSG("Screen: %s", text);
|
||||
if (!useDisplay)
|
||||
return;
|
||||
|
||||
dispdev.print(text);
|
||||
}
|
||||
|
||||
void Screen::handleOnPress()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise advance to next frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
setPeriod(1); // redraw ASAP
|
||||
ui.nextFrame();
|
||||
|
||||
DEBUG_MSG("Setting fast framerate\n");
|
||||
|
||||
// We are about to start a transition so speed up fps
|
||||
targetFramerate = TRANSITION_FRAMERATE;
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
displayedNodeNum = 0; // Not currently showing a node pane
|
||||
|
||||
display->setFont(ArialMT_Plain_10);
|
||||
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
char channelStr[20];
|
||||
{
|
||||
concurrency::LockGuard guard(&lock);
|
||||
snprintf(channelStr, sizeof(channelStr), "#%s", channelName.c_str());
|
||||
|
||||
// Display power status
|
||||
if (powerStatus->getHasBattery())
|
||||
drawBattery(display, x, y + 2, imgBattery, powerStatus);
|
||||
else
|
||||
display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
|
||||
// Display nodes status
|
||||
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
|
||||
// Display GPS status
|
||||
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
|
||||
}
|
||||
|
||||
display->drawString(x, y + FONT_HEIGHT, channelStr);
|
||||
|
||||
display->drawLogBuffer(x, y + (FONT_HEIGHT * 2));
|
||||
|
||||
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||||
#ifdef SHOW_REDRAWS
|
||||
if (heartbeat)
|
||||
display->setPixel(0, 0);
|
||||
heartbeat = !heartbeat;
|
||||
#endif
|
||||
}
|
||||
|
||||
// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true
|
||||
void Screen::adjustBrightness()
|
||||
{
|
||||
if (brightness == 254) {
|
||||
brightness = 0;
|
||||
} else {
|
||||
brightness++;
|
||||
}
|
||||
int width = brightness / (254.00 / SCREEN_WIDTH);
|
||||
dispdev.drawRect(0, 30, SCREEN_WIDTH, 4);
|
||||
dispdev.fillRect(0, 31, width, 2);
|
||||
dispdev.display();
|
||||
dispdev.setBrightness(brightness);
|
||||
}
|
||||
|
||||
int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
{
|
||||
//DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
|
||||
switch(arg->getStatusType())
|
||||
{
|
||||
case STATUS_TYPE_NODE:
|
||||
if (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal())
|
||||
setFrames();
|
||||
prevFrame = -1;
|
||||
nodeDB.updateGUI = false;
|
||||
nodeDB.updateTextMessage = false;
|
||||
break;
|
||||
}
|
||||
setPeriod(1); // Update the screen right away
|
||||
return 0;
|
||||
}
|
||||
} // namespace graphics
|
||||
228
src/graphics/Screen.h
Normal file
228
src/graphics/Screen.h
Normal file
@@ -0,0 +1,228 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
#ifdef USE_SH1106
|
||||
#include <SH1106Wire.h>
|
||||
#else
|
||||
#include <SSD1306Wire.h>
|
||||
#endif
|
||||
|
||||
#include "concurrency/PeriodicTask.h"
|
||||
#include "TypedQueue.h"
|
||||
#include "concurrency/LockGuard.h"
|
||||
#include "power.h"
|
||||
#include "commands.h"
|
||||
#include <string>
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
// Forward declarations
|
||||
class Screen;
|
||||
|
||||
/// Handles gathering and displaying debug information.
|
||||
class DebugInfo
|
||||
{
|
||||
public:
|
||||
DebugInfo(const DebugInfo &) = delete;
|
||||
DebugInfo &operator=(const DebugInfo &) = delete;
|
||||
|
||||
/// Sets the name of the channel.
|
||||
void setChannelNameStatus(const char *name)
|
||||
{
|
||||
concurrency::LockGuard guard(&lock);
|
||||
channelName = name;
|
||||
}
|
||||
|
||||
private:
|
||||
friend Screen;
|
||||
|
||||
DebugInfo() {}
|
||||
|
||||
/// Renders the debug screen.
|
||||
void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
std::string channelName;
|
||||
|
||||
/// Protects all of internal state.
|
||||
concurrency::Lock lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class deals with showing things on the screen of the device.
|
||||
*
|
||||
* @details Other than setup(), this class is thread-safe as long as drawFrame is not called
|
||||
* multiple times simultaneously. All state-changing calls are queued and executed
|
||||
* when the main loop calls us.
|
||||
*/
|
||||
class Screen : public concurrency::PeriodicTask
|
||||
{
|
||||
CallbackObserver<Screen, const meshtastic::Status *> powerStatusObserver = CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||
CallbackObserver<Screen, const meshtastic::Status *> gpsStatusObserver = CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||
CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver = CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||
|
||||
public:
|
||||
Screen(uint8_t address, int sda = -1, int scl = -1);
|
||||
|
||||
Screen(const Screen &) = delete;
|
||||
Screen &operator=(const Screen &) = delete;
|
||||
|
||||
/// Initializes the UI, turns on the display, starts showing boot screen.
|
||||
//
|
||||
// Not thread safe - must be called before any other methods are called.
|
||||
void setup();
|
||||
|
||||
/// Turns the screen on/off.
|
||||
void setOn(bool on)
|
||||
{
|
||||
if (!on)
|
||||
handleSetOn(
|
||||
false); // We handle off commands immediately, because they might be called because the CPU is shutting down
|
||||
else
|
||||
enqueueCmd(ScreenCmd{.cmd = on ? Cmd::SET_ON : Cmd::SET_OFF});
|
||||
}
|
||||
|
||||
/// Handles a button press.
|
||||
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
|
||||
|
||||
// Implementation to Adjust Brightness
|
||||
void adjustBrightness();
|
||||
uint8_t brightness = 150;
|
||||
|
||||
/// Starts showing the Bluetooth PIN screen.
|
||||
//
|
||||
// Switches over to a static frame showing the Bluetooth pairing screen
|
||||
// with the PIN.
|
||||
void startBluetoothPinScreen(uint32_t pin)
|
||||
{
|
||||
ScreenCmd cmd;
|
||||
cmd.cmd = Cmd::START_BLUETOOTH_PIN_SCREEN;
|
||||
cmd.bluetooth_pin = pin;
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
/// Stops showing the bluetooth PIN screen.
|
||||
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
|
||||
|
||||
/// Stops showing the boot screen.
|
||||
void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); }
|
||||
|
||||
/// Writes a string to the screen.
|
||||
void print(const char *text)
|
||||
{
|
||||
ScreenCmd cmd;
|
||||
cmd.cmd = Cmd::PRINT;
|
||||
// TODO(girts): strdup() here is scary, but we can't use std::string as
|
||||
// FreeRTOS queue is just dumbly copying memory contents. It would be
|
||||
// nice if we had a queue that could copy objects by value.
|
||||
cmd.print_text = strdup(text);
|
||||
if (!enqueueCmd(cmd)) {
|
||||
free(cmd.print_text);
|
||||
}
|
||||
}
|
||||
|
||||
/// Overrides the default utf8 character conversion, to replace empty space with question marks
|
||||
static char customFontTableLookup(const uint8_t ch) {
|
||||
// UTF-8 to font table index converter
|
||||
// Code form http://playground.arduino.cc/Main/Utf8ascii
|
||||
static uint8_t LASTCHAR;
|
||||
static bool SKIPREST; // Only display a single unconvertable-character symbol per sequence of unconvertable characters
|
||||
|
||||
if (ch < 128) { // Standard ASCII-set 0..0x7F handling
|
||||
LASTCHAR = 0;
|
||||
SKIPREST = false;
|
||||
return ch;
|
||||
}
|
||||
|
||||
uint8_t last = LASTCHAR; // get last char
|
||||
LASTCHAR = ch;
|
||||
|
||||
switch (last) { // conversion depnding on first UTF8-character
|
||||
case 0xC2: { SKIPREST = false; return (uint8_t) ch; }
|
||||
case 0xC3: { SKIPREST = false; return (uint8_t) (ch | 0xC0); }
|
||||
}
|
||||
|
||||
// We want to strip out prefix chars for two-byte char formats
|
||||
if (ch == 0xC2 || ch == 0xC3 || ch == 0x82) return (uint8_t) 0;
|
||||
|
||||
// If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the rest of it
|
||||
if (SKIPREST) return (uint8_t) 0;
|
||||
SKIPREST = true;
|
||||
|
||||
return (uint8_t) 191; // otherwise: return ¿ if character can't be converted (note that the font map we're using doesn't stick to standard EASCII codes)
|
||||
}
|
||||
|
||||
/// Returns a handle to the DebugInfo screen.
|
||||
//
|
||||
// Use this handle to set things like battery status, user count, GPS status, etc.
|
||||
DebugInfo* debug_info() { return &debugInfo; }
|
||||
|
||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||
|
||||
protected:
|
||||
/// Updates the UI.
|
||||
//
|
||||
// Called periodically from the main loop.
|
||||
void doTask() final;
|
||||
|
||||
private:
|
||||
struct ScreenCmd {
|
||||
Cmd cmd;
|
||||
union {
|
||||
uint32_t bluetooth_pin;
|
||||
char *print_text;
|
||||
};
|
||||
};
|
||||
|
||||
/// Enques given command item to be processed by main loop().
|
||||
bool enqueueCmd(const ScreenCmd &cmd)
|
||||
{
|
||||
if (!useDisplay)
|
||||
return true; // claim success if our display is not in use
|
||||
else {
|
||||
bool success = cmdQueue.enqueue(cmd, 0);
|
||||
setPeriod(1); // handle ASAP
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
// Implementations of various commands, called from doTask().
|
||||
void handleSetOn(bool on);
|
||||
void handleOnPress();
|
||||
void handleStartBluetoothPinScreen(uint32_t pin);
|
||||
void handlePrint(const char *text);
|
||||
|
||||
/// Rebuilds our list of frames (screens) to default ones.
|
||||
void setFrames();
|
||||
|
||||
/// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame.
|
||||
static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
/// Queue of commands to execute in doTask.
|
||||
TypedQueue<ScreenCmd> cmdQueue;
|
||||
/// Whether we are using a display
|
||||
bool useDisplay = false;
|
||||
/// Whether the display is currently powered
|
||||
bool screenOn = false;
|
||||
// Whether we are showing the regular screen (as opposed to booth screen or
|
||||
// Bluetooth PIN screen)
|
||||
bool showingNormalScreen = false;
|
||||
|
||||
/// Holds state for debug information
|
||||
DebugInfo debugInfo;
|
||||
|
||||
/// Display device
|
||||
/** @todo display abstraction */
|
||||
#ifdef USE_SH1106
|
||||
SH1106Wire dispdev;
|
||||
#else
|
||||
SSD1306Wire dispdev;
|
||||
#endif
|
||||
/// UI helper for rendering to frames and switching between them
|
||||
OLEDDisplayUi ui;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
17
src/graphics/configs.h
Normal file
17
src/graphics/configs.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "fonts.h"
|
||||
|
||||
#define FONT_HEIGHT 14 // actually 13 for "Arial 10" but want a little extra space
|
||||
#define FONT_HEIGHT_16 (ArialMT_Plain_16[1] + 1)
|
||||
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define TRANSITION_FRAMERATE 30 // fps
|
||||
#define IDLE_FRAMERATE 1 // in fps
|
||||
#define COMPASS_DIAM 44
|
||||
|
||||
// DEBUG
|
||||
#define NUM_EXTRA_FRAMES 2 // text message and debug frame
|
||||
// if defined a pixel will blink to show redraws
|
||||
// #define SHOW_REDRAWS
|
||||
425
src/graphics/fonts.h
Normal file
425
src/graphics/fonts.h
Normal file
@@ -0,0 +1,425 @@
|
||||
#pragma once
|
||||
|
||||
const uint8_t Custom_ArialMT_Plain_10[] PROGMEM = {
|
||||
0x0A, // Width: 10
|
||||
0x0A, // Height: 10
|
||||
0x20, // First Char: 32
|
||||
0xE0, // Numbers of Chars: 224
|
||||
|
||||
// Jump Table:
|
||||
0xFF, 0xFF, 0x00, 0x03, // 32:65535
|
||||
0x00, 0x00, 0x04, 0x03, // 33:0
|
||||
0x00, 0x04, 0x05, 0x04, // 34:4
|
||||
0x00, 0x09, 0x09, 0x06, // 35:9
|
||||
0x00, 0x12, 0x0A, 0x06, // 36:18
|
||||
0x00, 0x1C, 0x10, 0x09, // 37:28
|
||||
0x00, 0x2C, 0x0E, 0x07, // 38:44
|
||||
0x00, 0x3A, 0x01, 0x02, // 39:58
|
||||
0x00, 0x3B, 0x06, 0x03, // 40:59
|
||||
0x00, 0x41, 0x06, 0x03, // 41:65
|
||||
0x00, 0x47, 0x05, 0x04, // 42:71
|
||||
0x00, 0x4C, 0x09, 0x06, // 43:76
|
||||
0x00, 0x55, 0x04, 0x03, // 44:85
|
||||
0x00, 0x59, 0x03, 0x03, // 45:89
|
||||
0x00, 0x5C, 0x04, 0x03, // 46:92
|
||||
0x00, 0x60, 0x05, 0x03, // 47:96
|
||||
0x00, 0x65, 0x0A, 0x06, // 48:101
|
||||
0x00, 0x6F, 0x08, 0x06, // 49:111
|
||||
0x00, 0x77, 0x0A, 0x06, // 50:119
|
||||
0x00, 0x81, 0x0A, 0x06, // 51:129
|
||||
0x00, 0x8B, 0x0B, 0x06, // 52:139
|
||||
0x00, 0x96, 0x0A, 0x06, // 53:150
|
||||
0x00, 0xA0, 0x0A, 0x06, // 54:160
|
||||
0x00, 0xAA, 0x09, 0x06, // 55:170
|
||||
0x00, 0xB3, 0x0A, 0x06, // 56:179
|
||||
0x00, 0xBD, 0x0A, 0x06, // 57:189
|
||||
0x00, 0xC7, 0x04, 0x03, // 58:199
|
||||
0x00, 0xCB, 0x04, 0x03, // 59:203
|
||||
0x00, 0xCF, 0x0A, 0x06, // 60:207
|
||||
0x00, 0xD9, 0x09, 0x06, // 61:217
|
||||
0x00, 0xE2, 0x09, 0x06, // 62:226
|
||||
0x00, 0xEB, 0x0B, 0x06, // 63:235
|
||||
0x00, 0xF6, 0x14, 0x0A, // 64:246
|
||||
0x01, 0x0A, 0x0E, 0x07, // 65:266
|
||||
0x01, 0x18, 0x0C, 0x07, // 66:280
|
||||
0x01, 0x24, 0x0C, 0x07, // 67:292
|
||||
0x01, 0x30, 0x0B, 0x07, // 68:304
|
||||
0x01, 0x3B, 0x0C, 0x07, // 69:315
|
||||
0x01, 0x47, 0x09, 0x06, // 70:327
|
||||
0x01, 0x50, 0x0D, 0x08, // 71:336
|
||||
0x01, 0x5D, 0x0C, 0x07, // 72:349
|
||||
0x01, 0x69, 0x04, 0x03, // 73:361
|
||||
0x01, 0x6D, 0x08, 0x05, // 74:365
|
||||
0x01, 0x75, 0x0E, 0x07, // 75:373
|
||||
0x01, 0x83, 0x0C, 0x06, // 76:387
|
||||
0x01, 0x8F, 0x10, 0x08, // 77:399
|
||||
0x01, 0x9F, 0x0C, 0x07, // 78:415
|
||||
0x01, 0xAB, 0x0E, 0x08, // 79:427
|
||||
0x01, 0xB9, 0x0B, 0x07, // 80:441
|
||||
0x01, 0xC4, 0x0E, 0x08, // 81:452
|
||||
0x01, 0xD2, 0x0C, 0x07, // 82:466
|
||||
0x01, 0xDE, 0x0C, 0x07, // 83:478
|
||||
0x01, 0xEA, 0x0B, 0x06, // 84:490
|
||||
0x01, 0xF5, 0x0C, 0x07, // 85:501
|
||||
0x02, 0x01, 0x0D, 0x07, // 86:513
|
||||
0x02, 0x0E, 0x11, 0x09, // 87:526
|
||||
0x02, 0x1F, 0x0E, 0x07, // 88:543
|
||||
0x02, 0x2D, 0x0D, 0x07, // 89:557
|
||||
0x02, 0x3A, 0x0C, 0x06, // 90:570
|
||||
0x02, 0x46, 0x06, 0x03, // 91:582
|
||||
0x02, 0x4C, 0x06, 0x03, // 92:588
|
||||
0x02, 0x52, 0x04, 0x03, // 93:594
|
||||
0x02, 0x56, 0x09, 0x05, // 94:598
|
||||
0x02, 0x5F, 0x0C, 0x06, // 95:607
|
||||
0x02, 0x6B, 0x03, 0x03, // 96:619
|
||||
0x02, 0x6E, 0x0A, 0x06, // 97:622
|
||||
0x02, 0x78, 0x0A, 0x06, // 98:632
|
||||
0x02, 0x82, 0x0A, 0x05, // 99:642
|
||||
0x02, 0x8C, 0x0A, 0x06, // 100:652
|
||||
0x02, 0x96, 0x0A, 0x06, // 101:662
|
||||
0x02, 0xA0, 0x05, 0x03, // 102:672
|
||||
0x02, 0xA5, 0x0A, 0x06, // 103:677
|
||||
0x02, 0xAF, 0x0A, 0x06, // 104:687
|
||||
0x02, 0xB9, 0x04, 0x02, // 105:697
|
||||
0x02, 0xBD, 0x04, 0x02, // 106:701
|
||||
0x02, 0xC1, 0x08, 0x05, // 107:705
|
||||
0x02, 0xC9, 0x04, 0x02, // 108:713
|
||||
0x02, 0xCD, 0x10, 0x08, // 109:717
|
||||
0x02, 0xDD, 0x0A, 0x06, // 110:733
|
||||
0x02, 0xE7, 0x0A, 0x06, // 111:743
|
||||
0x02, 0xF1, 0x0A, 0x06, // 112:753
|
||||
0x02, 0xFB, 0x0A, 0x06, // 113:763
|
||||
0x03, 0x05, 0x05, 0x03, // 114:773
|
||||
0x03, 0x0A, 0x08, 0x05, // 115:778
|
||||
0x03, 0x12, 0x06, 0x03, // 116:786
|
||||
0x03, 0x18, 0x0A, 0x06, // 117:792
|
||||
0x03, 0x22, 0x09, 0x05, // 118:802
|
||||
0x03, 0x2B, 0x0E, 0x07, // 119:811
|
||||
0x03, 0x39, 0x0A, 0x05, // 120:825
|
||||
0x03, 0x43, 0x09, 0x05, // 121:835
|
||||
0x03, 0x4C, 0x0A, 0x05, // 122:844
|
||||
0x03, 0x56, 0x06, 0x03, // 123:854
|
||||
0x03, 0x5C, 0x04, 0x03, // 124:860
|
||||
0x03, 0x60, 0x05, 0x03, // 125:864
|
||||
0x03, 0x65, 0x09, 0x06, // 126:869
|
||||
0xFF, 0xFF, 0x00, 0x00, // 127:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 128:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 129:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 130:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 131:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 132:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 133:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 134:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 135:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 136:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 137:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 138:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 139:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 140:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 141:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 142:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 143:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 144:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 145:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 146:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 147:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 148:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 149:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 150:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 151:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 152:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 153:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 154:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 155:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 156:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 157:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 158:65535
|
||||
0xFF, 0xFF, 0x00, 0x0A, // 159:65535
|
||||
0xFF, 0xFF, 0x00, 0x03, // 160:65535
|
||||
0x03, 0x6E, 0x04, 0x03, // 161:878
|
||||
0x03, 0x72, 0x0A, 0x06, // 162:882
|
||||
0x03, 0x7C, 0x0C, 0x06, // 163:892
|
||||
0x03, 0x88, 0x0A, 0x06, // 164:904
|
||||
0x03, 0x92, 0x0A, 0x06, // 165:914
|
||||
0x03, 0x9C, 0x04, 0x03, // 166:924
|
||||
0x03, 0xA0, 0x0A, 0x06, // 167:928
|
||||
0x03, 0xAA, 0x05, 0x03, // 168:938
|
||||
0x03, 0xAF, 0x0D, 0x07, // 169:943
|
||||
0x03, 0xBC, 0x07, 0x04, // 170:956
|
||||
0x03, 0xC3, 0x0A, 0x06, // 171:963
|
||||
0x03, 0xCD, 0x09, 0x06, // 172:973
|
||||
0x03, 0xD6, 0x03, 0x03, // 173:982
|
||||
0x03, 0xD9, 0x0D, 0x07, // 174:985
|
||||
0x03, 0xE6, 0x0B, 0x06, // 175:998
|
||||
0x03, 0xF1, 0x07, 0x04, // 176:1009
|
||||
0x03, 0xF8, 0x0A, 0x05, // 177:1016
|
||||
0x04, 0x02, 0x05, 0x03, // 178:1026
|
||||
0x04, 0x07, 0x05, 0x03, // 179:1031
|
||||
0x04, 0x0C, 0x05, 0x03, // 180:1036
|
||||
0x04, 0x11, 0x0A, 0x06, // 181:1041
|
||||
0x04, 0x1B, 0x09, 0x05, // 182:1051
|
||||
0x04, 0x24, 0x03, 0x03, // 183:1060
|
||||
0x04, 0x27, 0x06, 0x03, // 184:1063
|
||||
0x04, 0x2D, 0x05, 0x03, // 185:1069
|
||||
0x04, 0x32, 0x07, 0x04, // 186:1074
|
||||
0x04, 0x39, 0x0A, 0x06, // 187:1081
|
||||
0x04, 0x43, 0x10, 0x08, // 188:1091
|
||||
0x04, 0x53, 0x10, 0x08, // 189:1107
|
||||
0x04, 0x63, 0x10, 0x08, // 190:1123
|
||||
0x04, 0x73, 0x0A, 0x06, // 191:1139
|
||||
0x04, 0x7D, 0x0E, 0x07, // 192:1149
|
||||
0x04, 0x8B, 0x0E, 0x07, // 193:1163
|
||||
0x04, 0x99, 0x0E, 0x07, // 194:1177
|
||||
0x04, 0xA7, 0x0E, 0x07, // 195:1191
|
||||
0x04, 0xB5, 0x0E, 0x07, // 196:1205
|
||||
0x04, 0xC3, 0x0E, 0x07, // 197:1219
|
||||
0x04, 0xD1, 0x12, 0x0A, // 198:1233
|
||||
0x04, 0xE3, 0x0C, 0x07, // 199:1251
|
||||
0x04, 0xEF, 0x0C, 0x07, // 200:1263
|
||||
0x04, 0xFB, 0x0C, 0x07, // 201:1275
|
||||
0x05, 0x07, 0x0C, 0x07, // 202:1287
|
||||
0x05, 0x13, 0x0C, 0x07, // 203:1299
|
||||
0x05, 0x1F, 0x05, 0x03, // 204:1311
|
||||
0x05, 0x24, 0x04, 0x03, // 205:1316
|
||||
0x05, 0x28, 0x04, 0x03, // 206:1320
|
||||
0x05, 0x2C, 0x05, 0x03, // 207:1324
|
||||
0x05, 0x31, 0x0B, 0x07, // 208:1329
|
||||
0x05, 0x3C, 0x0C, 0x07, // 209:1340
|
||||
0x05, 0x48, 0x0E, 0x08, // 210:1352
|
||||
0x05, 0x56, 0x0E, 0x08, // 211:1366
|
||||
0x05, 0x64, 0x0E, 0x08, // 212:1380
|
||||
0x05, 0x72, 0x0E, 0x08, // 213:1394
|
||||
0x05, 0x80, 0x0E, 0x08, // 214:1408
|
||||
0x05, 0x8E, 0x0A, 0x06, // 215:1422
|
||||
0x05, 0x98, 0x0D, 0x08, // 216:1432
|
||||
0x05, 0xA5, 0x0C, 0x07, // 217:1445
|
||||
0x05, 0xB1, 0x0C, 0x07, // 218:1457
|
||||
0x05, 0xBD, 0x0C, 0x07, // 219:1469
|
||||
0x05, 0xC9, 0x0C, 0x07, // 220:1481
|
||||
0x05, 0xD5, 0x0D, 0x07, // 221:1493
|
||||
0x05, 0xE2, 0x0B, 0x07, // 222:1506
|
||||
0x05, 0xED, 0x0C, 0x06, // 223:1517
|
||||
0x05, 0xF9, 0x0A, 0x06, // 224:1529
|
||||
0x06, 0x03, 0x0A, 0x06, // 225:1539
|
||||
0x06, 0x0D, 0x0A, 0x06, // 226:1549
|
||||
0x06, 0x17, 0x0A, 0x06, // 227:1559
|
||||
0x06, 0x21, 0x0A, 0x06, // 228:1569
|
||||
0x06, 0x2B, 0x0A, 0x06, // 229:1579
|
||||
0x06, 0x35, 0x10, 0x09, // 230:1589
|
||||
0x06, 0x45, 0x0A, 0x05, // 231:1605
|
||||
0x06, 0x4F, 0x0A, 0x06, // 232:1615
|
||||
0x06, 0x59, 0x0A, 0x06, // 233:1625
|
||||
0x06, 0x63, 0x0A, 0x06, // 234:1635
|
||||
0x06, 0x6D, 0x0A, 0x06, // 235:1645
|
||||
0x06, 0x77, 0x05, 0x03, // 236:1655
|
||||
0x06, 0x7C, 0x04, 0x03, // 237:1660
|
||||
0x06, 0x80, 0x05, 0x03, // 238:1664
|
||||
0x06, 0x85, 0x05, 0x03, // 239:1669
|
||||
0x06, 0x8A, 0x0A, 0x06, // 240:1674
|
||||
0x06, 0x94, 0x0A, 0x06, // 241:1684
|
||||
0x06, 0x9E, 0x0A, 0x06, // 242:1694
|
||||
0x06, 0xA8, 0x0A, 0x06, // 243:1704
|
||||
0x06, 0xB2, 0x0A, 0x06, // 244:1714
|
||||
0x06, 0xBC, 0x0A, 0x06, // 245:1724
|
||||
0x06, 0xC6, 0x0A, 0x06, // 246:1734
|
||||
0x06, 0xD0, 0x09, 0x05, // 247:1744
|
||||
0x06, 0xD9, 0x0A, 0x06, // 248:1753
|
||||
0x06, 0xE3, 0x0A, 0x06, // 249:1763
|
||||
0x06, 0xED, 0x0A, 0x06, // 250:1773
|
||||
0x06, 0xF7, 0x0A, 0x06, // 251:1783
|
||||
0x07, 0x01, 0x0A, 0x06, // 252:1793
|
||||
0x07, 0x0B, 0x09, 0x05, // 253:1803
|
||||
0x07, 0x14, 0x0A, 0x06, // 254:1812
|
||||
0x07, 0x1E, 0x09, 0x05, // 255:1822
|
||||
|
||||
// Font Data:
|
||||
0x00, 0x00, 0xF8, 0x02, // 33
|
||||
0x38, 0x00, 0x00, 0x00, 0x38, // 34
|
||||
0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35
|
||||
0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36
|
||||
0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37
|
||||
0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38
|
||||
0x38, // 39
|
||||
0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40
|
||||
0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41
|
||||
0x28, 0x00, 0x18, 0x00, 0x28, // 42
|
||||
0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43
|
||||
0x00, 0x00, 0x00, 0x06, // 44
|
||||
0x80, 0x00, 0x80, // 45
|
||||
0x00, 0x00, 0x00, 0x02, // 46
|
||||
0x00, 0x03, 0xE0, 0x00, 0x18, // 47
|
||||
0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48
|
||||
0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49
|
||||
0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50
|
||||
0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51
|
||||
0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52
|
||||
0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53
|
||||
0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54
|
||||
0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55
|
||||
0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56
|
||||
0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57
|
||||
0x00, 0x00, 0x20, 0x02, // 58
|
||||
0x00, 0x00, 0x20, 0x06, // 59
|
||||
0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60
|
||||
0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61
|
||||
0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62
|
||||
0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63
|
||||
0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0, 0x04, // 64
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67
|
||||
0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70
|
||||
0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71
|
||||
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72
|
||||
0x00, 0x00, 0xF8, 0x03, // 73
|
||||
0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74
|
||||
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75
|
||||
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76
|
||||
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77
|
||||
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82
|
||||
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83
|
||||
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84
|
||||
0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85
|
||||
0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86
|
||||
0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87
|
||||
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88
|
||||
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89
|
||||
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90
|
||||
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91
|
||||
0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92
|
||||
0x08, 0x08, 0xF8, 0x0F, // 93
|
||||
0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94
|
||||
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95
|
||||
0x08, 0x00, 0x10, // 96
|
||||
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97
|
||||
0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101
|
||||
0x20, 0x00, 0xF0, 0x03, 0x28, // 102
|
||||
0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103
|
||||
0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104
|
||||
0x00, 0x00, 0xE8, 0x03, // 105
|
||||
0x00, 0x08, 0xE8, 0x07, // 106
|
||||
0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107
|
||||
0x00, 0x00, 0xF8, 0x03, // 108
|
||||
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109
|
||||
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111
|
||||
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113
|
||||
0x00, 0x00, 0xE0, 0x03, 0x20, // 114
|
||||
0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115
|
||||
0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116
|
||||
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117
|
||||
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118
|
||||
0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119
|
||||
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120
|
||||
0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121
|
||||
0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122
|
||||
0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123
|
||||
0x00, 0x00, 0xF8, 0x0F, // 124
|
||||
0x08, 0x08, 0x78, 0x0F, 0x80, // 125
|
||||
0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126
|
||||
0x00, 0x00, 0xA0, 0x0F, // 161
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x0F, 0x78, 0x02, 0x40, 0x01, // 162
|
||||
0x40, 0x02, 0x70, 0x03, 0xC8, 0x02, 0x48, 0x02, 0x08, 0x02, 0x10, 0x02, // 163
|
||||
0x00, 0x00, 0xE0, 0x01, 0x20, 0x01, 0x20, 0x01, 0xE0, 0x01, // 164
|
||||
0x48, 0x01, 0x70, 0x01, 0xC0, 0x03, 0x70, 0x01, 0x48, 0x01, // 165
|
||||
0x00, 0x00, 0x38, 0x0F, // 166
|
||||
0xD0, 0x04, 0x28, 0x09, 0x48, 0x09, 0x48, 0x0A, 0x90, 0x05, // 167
|
||||
0x08, 0x00, 0x00, 0x00, 0x08, // 168
|
||||
0xE0, 0x00, 0x10, 0x01, 0x48, 0x02, 0xA8, 0x02, 0xA8, 0x02, 0x10, 0x01, 0xE0, // 169
|
||||
0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x78, // 170
|
||||
0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, // 171
|
||||
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, // 172
|
||||
0x80, 0x00, 0x80, // 173
|
||||
0xE0, 0x00, 0x10, 0x01, 0xE8, 0x02, 0x68, 0x02, 0xC8, 0x02, 0x10, 0x01, 0xE0, // 174
|
||||
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 175
|
||||
0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176
|
||||
0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177
|
||||
0x48, 0x00, 0x68, 0x00, 0x58, // 178
|
||||
0x48, 0x00, 0x58, 0x00, 0x68, // 179
|
||||
0x00, 0x00, 0x10, 0x00, 0x08, // 180
|
||||
0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 181
|
||||
0x70, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0xF8, 0x0F, 0x08, // 182
|
||||
0x00, 0x00, 0x40, // 183
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x18, // 184
|
||||
0x00, 0x00, 0x10, 0x00, 0x78, // 185
|
||||
0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 186
|
||||
0x00, 0x00, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, // 187
|
||||
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188
|
||||
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189
|
||||
0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190
|
||||
0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0xA0, 0x09, 0x00, 0x04, // 191
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 192
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 193
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 194
|
||||
0x00, 0x02, 0xC2, 0x01, 0xB1, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 195
|
||||
0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x88, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 196
|
||||
0x00, 0x02, 0xC0, 0x01, 0xBE, 0x00, 0x8A, 0x00, 0xBE, 0x00, 0xC0, 0x01, 0x00, 0x02, // 197
|
||||
0x00, 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x98, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 198
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x16, 0x08, 0x1A, 0x10, 0x01, // 199
|
||||
0x00, 0x00, 0xF8, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 200
|
||||
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x4A, 0x02, 0x49, 0x02, 0x48, 0x02, // 201
|
||||
0x00, 0x00, 0xFA, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 202
|
||||
0x00, 0x00, 0xF8, 0x03, 0x4A, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x48, 0x02, // 203
|
||||
0x00, 0x00, 0xF9, 0x03, 0x02, // 204
|
||||
0x02, 0x00, 0xF9, 0x03, // 205
|
||||
0x01, 0x00, 0xFA, 0x03, // 206
|
||||
0x02, 0x00, 0xF8, 0x03, 0x02, // 207
|
||||
0x40, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x10, 0x01, 0xE0, // 208
|
||||
0x00, 0x00, 0xFA, 0x03, 0x31, 0x00, 0x42, 0x00, 0x81, 0x01, 0xF8, 0x03, // 209
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 210
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x08, 0x02, 0xF0, 0x01, // 211
|
||||
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0xF0, 0x01, // 212
|
||||
0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x09, 0x02, 0xF0, 0x01, // 213
|
||||
0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 214
|
||||
0x10, 0x01, 0xA0, 0x00, 0xE0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 215
|
||||
0x00, 0x00, 0xF0, 0x02, 0x08, 0x03, 0xC8, 0x02, 0x28, 0x02, 0x18, 0x03, 0xE8, // 216
|
||||
0x00, 0x00, 0xF8, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02, 0xF8, 0x01, // 217
|
||||
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, 0xF8, 0x01, // 218
|
||||
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0xF8, 0x01, // 219
|
||||
0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0xF8, 0x01, // 220
|
||||
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC2, 0x03, 0x21, 0x00, 0x10, 0x00, 0x08, // 221
|
||||
0x00, 0x00, 0xF8, 0x03, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xE0, // 222
|
||||
0x00, 0x00, 0xF0, 0x03, 0x08, 0x01, 0x48, 0x02, 0xB0, 0x02, 0x80, 0x01, // 223
|
||||
0x00, 0x00, 0x00, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE0, 0x03, // 224
|
||||
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE0, 0x03, // 225
|
||||
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE8, 0x03, // 226
|
||||
0x00, 0x00, 0x08, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE4, 0x03, // 227
|
||||
0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA0, 0x02, 0xE8, 0x03, // 228
|
||||
0x00, 0x00, 0x00, 0x03, 0xAE, 0x02, 0xAA, 0x02, 0xEE, 0x03, // 229
|
||||
0x00, 0x00, 0x40, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 230
|
||||
0x00, 0x00, 0xC0, 0x01, 0x20, 0x16, 0x20, 0x1A, 0x40, 0x01, // 231
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA4, 0x02, 0xA8, 0x02, 0xC0, 0x02, // 232
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC0, 0x02, // 233
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC8, 0x02, // 234
|
||||
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA0, 0x02, 0xC8, 0x02, // 235
|
||||
0x00, 0x00, 0xE4, 0x03, 0x08, // 236
|
||||
0x08, 0x00, 0xE4, 0x03, // 237
|
||||
0x08, 0x00, 0xE4, 0x03, 0x08, // 238
|
||||
0x08, 0x00, 0xE0, 0x03, 0x08, // 239
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x38, 0x02, 0xE0, 0x01, // 240
|
||||
0x00, 0x00, 0xE8, 0x03, 0x24, 0x00, 0x28, 0x00, 0xC4, 0x03, // 241
|
||||
0x00, 0x00, 0xC0, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC0, 0x01, // 242
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC0, 0x01, // 243
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC8, 0x01, // 244
|
||||
0x00, 0x00, 0xC8, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC4, 0x01, // 245
|
||||
0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x20, 0x02, 0xC8, 0x01, // 246
|
||||
0x40, 0x00, 0x40, 0x00, 0x50, 0x01, 0x40, 0x00, 0x40, // 247
|
||||
0x00, 0x00, 0xC0, 0x02, 0xA0, 0x03, 0x60, 0x02, 0xA0, 0x01, // 248
|
||||
0x00, 0x00, 0xE0, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 249
|
||||
0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x04, 0x02, 0xE0, 0x03, // 250
|
||||
0x00, 0x00, 0xE8, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 251
|
||||
0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x00, 0x02, 0xE8, 0x03, // 252
|
||||
0x20, 0x00, 0xC0, 0x09, 0x08, 0x06, 0xC4, 0x01, 0x20, // 253
|
||||
0x00, 0x00, 0xF8, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 254
|
||||
0x20, 0x00, 0xC8, 0x09, 0x00, 0x06, 0xC8, 0x01, 0x20 // 255
|
||||
};
|
||||
45
src/graphics/images.h
Normal file
45
src/graphics/images.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#define SATELLITE_IMAGE_WIDTH 16
|
||||
#define SATELLITE_IMAGE_HEIGHT 15
|
||||
const uint8_t SATELLITE_IMAGE[] PROGMEM = {0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0x20, 0x07, 0x70, 0x02,
|
||||
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
|
||||
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
|
||||
|
||||
const uint8_t imgUSB[] PROGMEM = { 0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C };
|
||||
const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22 };
|
||||
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
|
||||
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
|
||||
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
|
||||
|
||||
#include "img/icon.xbm"
|
||||
|
||||
// We now programmatically draw our compass
|
||||
#if 0
|
||||
const
|
||||
#include "img/compass.xbm"
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
const uint8_t activeSymbol[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00100100,
|
||||
B01000010,
|
||||
B01000010,
|
||||
B00100100,
|
||||
B00011000
|
||||
};
|
||||
|
||||
const uint8_t inactiveSymbol[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00011000,
|
||||
B00000000,
|
||||
B00000000
|
||||
};
|
||||
#endif
|
||||
28
src/graphics/img/compass.xbm
Normal file
28
src/graphics/img/compass.xbm
Normal file
@@ -0,0 +1,28 @@
|
||||
#define compass_width 48
|
||||
#define compass_height 48
|
||||
static char compass_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00,
|
||||
0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00,
|
||||
0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00,
|
||||
0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00,
|
||||
0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01,
|
||||
0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01,
|
||||
0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
|
||||
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
|
||||
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
|
||||
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
|
||||
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
|
||||
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03,
|
||||
0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01,
|
||||
0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00,
|
||||
0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00,
|
||||
0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00,
|
||||
0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00,
|
||||
0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
33
src/graphics/img/icon.xbm
Normal file
33
src/graphics/img/icon.xbm
Normal file
@@ -0,0 +1,33 @@
|
||||
#define icon_width 50
|
||||
#define icon_height 50
|
||||
static char icon_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF,
|
||||
0xFF, 0x07, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00,
|
||||
0xF0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFE, 0x0F, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00,
|
||||
0xFF, 0x03, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xFC, 0x07, 0x00, 0xC0, 0x3F,
|
||||
0xE0, 0x1F, 0xF0, 0x0F, 0x00, 0xC0, 0x1F, 0xFC, 0xFF, 0xE0, 0x0F, 0x00,
|
||||
0xE0, 0x0F, 0xFF, 0xFF, 0xC3, 0x1F, 0x00, 0xF0, 0x87, 0xFF, 0xFF, 0x87,
|
||||
0x3F, 0x00, 0xF0, 0xC3, 0xFF, 0xFF, 0x0F, 0x3F, 0x00, 0xF8, 0xE3, 0x7F,
|
||||
0xF8, 0x1F, 0x7F, 0x00, 0xF8, 0xF1, 0x0F, 0xC0, 0x3F, 0x7E, 0x00, 0xF8,
|
||||
0xF1, 0x07, 0x80, 0x3F, 0x7E, 0x00, 0xFC, 0xF8, 0x03, 0x00, 0x7F, 0xFC,
|
||||
0x00, 0xFC, 0xF8, 0x81, 0x07, 0x7E, 0xFC, 0x00, 0x7C, 0xF8, 0xE0, 0x1F,
|
||||
0x7C, 0xF8, 0x00, 0x7C, 0xFC, 0xF0, 0x3F, 0xFC, 0xF8, 0x00, 0x7C, 0xFC,
|
||||
0xF0, 0x3F, 0xFC, 0xF8, 0x00, 0x7C, 0x7C, 0xF8, 0x7F, 0xF8, 0xF8, 0x00,
|
||||
0x7C, 0x7C, 0xF8, 0x7F, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0,
|
||||
0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x03, 0x00,
|
||||
0x00, 0x00, 0x80, 0x7F, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, };
|
||||
6
src/graphics/img/pin.xbm
Normal file
6
src/graphics/img/pin.xbm
Normal file
@@ -0,0 +1,6 @@
|
||||
#define pin_width 13
|
||||
#define pin_height 13
|
||||
static char pin_bits[] = {
|
||||
0x00, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xBC, 0x07, 0xBC, 0x07,
|
||||
0xFC, 0x07, 0xF8, 0x03, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0xE0, 0x00,
|
||||
0x00, 0x00, };
|
||||
Reference in New Issue
Block a user