summaryrefslogtreecommitdiff
path: root/code_refs
diff options
context:
space:
mode:
Diffstat (limited to 'code_refs')
-rw-r--r--code_refs/Adafruit_SharpMem.cpp277
-rw-r--r--code_refs/Adafruit_SharpMem.h64
-rw-r--r--code_refs/TinyGPS++.cpp520
-rw-r--r--code_refs/TinyGPS++.h285
-rw-r--r--code_refs/TinyGPSPlus.h26
-rw-r--r--code_refs/font_size_quarter_height.pngbin0 -> 1182 bytes
-rw-r--r--code_refs/fonts.c9
-rw-r--r--code_refs/fonts.h14
-rw-r--r--code_refs/image_2_bytes.py94
-rw-r--r--code_refs/output.txt1
-rw-r--r--code_refs/scratchpad.c37
-rw-r--r--code_refs/sharpmem.c87
-rw-r--r--code_refs/sharpmem.h36
-rw-r--r--code_refs/test_bw_image.pngbin0 -> 588 bytes
14 files changed, 1450 insertions, 0 deletions
diff --git a/code_refs/Adafruit_SharpMem.cpp b/code_refs/Adafruit_SharpMem.cpp
new file mode 100644
index 0000000..27b24c2
--- /dev/null
+++ b/code_refs/Adafruit_SharpMem.cpp
@@ -0,0 +1,277 @@
+/*********************************************************************
+This is an Arduino library for our Monochrome SHARP Memory Displays
+
+ Pick one up today in the adafruit shop!
+ ------> http://www.adafruit.com/products/1393
+
+These displays use SPI to communicate, 3 pins are required to
+interface
+
+Adafruit invests time and resources providing this open source code,
+please support Adafruit and open-source hardware by purchasing
+products from Adafruit!
+
+Written by Limor Fried/Ladyada for Adafruit Industries.
+BSD license, check license.txt for more information
+All text above, and the splash screen must be included in any redistribution
+*********************************************************************/
+
+#include "Adafruit_SharpMem.h"
+
+#ifndef _swap_int16_t
+#define _swap_int16_t(a, b) \
+ { \
+ int16_t t = a; \
+ a = b; \
+ b = t; \
+ }
+#endif
+#ifndef _swap_uint16_t
+#define _swap_uint16_t(a, b) \
+ { \
+ uint16_t t = a; \
+ a = b; \
+ b = t; \
+ }
+#endif
+
+/**************************************************************************
+ Sharp Memory Display Connector
+ -----------------------------------------------------------------------
+ Pin Function Notes
+ === ============== ===============================
+ 1 VIN 3.3-5.0V (into LDO supply)
+ 2 3V3 3.3V out
+ 3 GND
+ 4 SCLK Serial Clock
+ 5 MOSI Serial Data Input
+ 6 CS Serial Chip Select
+ 9 EXTMODE COM Inversion Select (Low = SW clock/serial)
+ 7 EXTCOMIN External COM Inversion Signal
+ 8 DISP Display On(High)/Off(Low)
+
+ **************************************************************************/
+
+#define TOGGLE_VCOM \
+ do { \
+ _sharpmem_vcom = _sharpmem_vcom ? 0x00 : SHARPMEM_BIT_VCOM; \
+ } while (0);
+
+/**
+ * @brief Construct a new Adafruit_SharpMem object with software SPI
+ *
+ * @param clk The clock pin
+ * @param mosi The MOSI pin
+ * @param cs The display chip select pin - **NOTE** this is ACTIVE HIGH!
+ * @param width The display width
+ * @param height The display height
+ * @param freq The SPI clock frequency desired (unlikely to be that fast in soft
+ * spi mode!)
+ */
+Adafruit_SharpMem::Adafruit_SharpMem(uint8_t clk, uint8_t mosi, uint8_t cs,
+ uint16_t width, uint16_t height,
+ uint32_t freq)
+ : Adafruit_GFX(width, height) {
+ _cs = cs;
+ if (spidev) {
+ delete spidev;
+ }
+ spidev =
+ new Adafruit_SPIDevice(cs, clk, -1, mosi, freq, SPI_BITORDER_LSBFIRST);
+}
+
+/**
+ * @brief Construct a new Adafruit_SharpMem object with hardware SPI
+ *
+ * @param theSPI Pointer to hardware SPI device you want to use
+ * @param cs The display chip select pin - **NOTE** this is ACTIVE HIGH!
+ * @param width The display width
+ * @param height The display height
+ * @param freq The SPI clock frequency desired
+ */
+Adafruit_SharpMem::Adafruit_SharpMem(SPIClass *theSPI, uint8_t cs,
+ uint16_t width, uint16_t height,
+ uint32_t freq)
+ : Adafruit_GFX(width, height) {
+ _cs = cs;
+ if (spidev) {
+ delete spidev;
+ }
+ spidev = new Adafruit_SPIDevice(cs, freq, SPI_BITORDER_LSBFIRST, SPI_MODE0,
+ theSPI);
+}
+
+/**
+ * @brief Start the driver object, setting up pins and configuring a buffer for
+ * the screen contents
+ *
+ * @return boolean true: success false: failure
+ */
+boolean Adafruit_SharpMem::begin(void) {
+ if (!spidev->begin()) {
+ return false;
+ }
+ // this display is weird in that _cs is active HIGH not LOW like every other
+ // SPI device
+ digitalWrite(_cs, LOW);
+
+ // Set the vcom bit to a defined state
+ _sharpmem_vcom = SHARPMEM_BIT_VCOM;
+
+ sharpmem_buffer = (uint8_t *)malloc((WIDTH * HEIGHT) / 8);
+
+ if (!sharpmem_buffer)
+ return false;
+
+ setRotation(0);
+
+ return true;
+}
+
+// 1<<n is a costly operation on AVR -- table usu. smaller & faster
+static const uint8_t PROGMEM set[] = {1, 2, 4, 8, 16, 32, 64, 128},
+ clr[] = {(uint8_t)~1, (uint8_t)~2, (uint8_t)~4,
+ (uint8_t)~8, (uint8_t)~16, (uint8_t)~32,
+ (uint8_t)~64, (uint8_t)~128};
+
+/**************************************************************************/
+/*!
+ @brief Draws a single pixel in image buffer
+
+ @param[in] x
+ The x position (0 based)
+ @param[in] y
+ The y position (0 based)
+ @param color The color to set:
+ * **0**: Black
+ * **1**: White
+*/
+/**************************************************************************/
+void Adafruit_SharpMem::drawPixel(int16_t x, int16_t y, uint16_t color) {
+ if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height))
+ return;
+
+ switch (rotation) {
+ case 1:
+ _swap_int16_t(x, y);
+ x = WIDTH - 1 - x;
+ break;
+ case 2:
+ x = WIDTH - 1 - x;
+ y = HEIGHT - 1 - y;
+ break;
+ case 3:
+ _swap_int16_t(x, y);
+ y = HEIGHT - 1 - y;
+ break;
+ }
+
+ if (color) {
+ sharpmem_buffer[(y * WIDTH + x) / 8] |= pgm_read_byte(&set[x & 7]);
+ } else {
+ sharpmem_buffer[(y * WIDTH + x) / 8] &= pgm_read_byte(&clr[x & 7]);
+ }
+}
+
+/**************************************************************************/
+/*!
+ @brief Gets the value (1 or 0) of the specified pixel from the buffer
+
+ @param[in] x
+ The x position (0 based)
+ @param[in] y
+ The y position (0 based)
+
+ @return 1 if the pixel is enabled, 0 if disabled
+*/
+/**************************************************************************/
+uint8_t Adafruit_SharpMem::getPixel(uint16_t x, uint16_t y) {
+ if ((x >= _width) || (y >= _height))
+ return 0; // <0 test not needed, unsigned
+
+ switch (rotation) {
+ case 1:
+ _swap_uint16_t(x, y);
+ x = WIDTH - 1 - x;
+ break;
+ case 2:
+ x = WIDTH - 1 - x;
+ y = HEIGHT - 1 - y;
+ break;
+ case 3:
+ _swap_uint16_t(x, y);
+ y = HEIGHT - 1 - y;
+ break;
+ }
+
+ return sharpmem_buffer[(y * WIDTH + x) / 8] & pgm_read_byte(&set[x & 7]) ? 1
+ : 0;
+}
+
+/**************************************************************************/
+/*!
+ @brief Clears the screen
+*/
+/**************************************************************************/
+void Adafruit_SharpMem::clearDisplay() {
+ memset(sharpmem_buffer, 0xff, (WIDTH * HEIGHT) / 8);
+
+ spidev->beginTransaction();
+ // Send the clear screen command rather than doing a HW refresh (quicker)
+ digitalWrite(_cs, HIGH);
+
+ uint8_t clear_data[2] = {(uint8_t)(_sharpmem_vcom | SHARPMEM_BIT_CLEAR),
+ 0x00};
+ spidev->transfer(clear_data, 2);
+
+ TOGGLE_VCOM;
+ digitalWrite(_cs, LOW);
+ spidev->endTransaction();
+}
+
+/**************************************************************************/
+/*!
+ @brief Renders the contents of the pixel buffer on the LCD
+*/
+/**************************************************************************/
+void Adafruit_SharpMem::refresh(void) {
+ uint16_t i, currentline;
+
+ spidev->beginTransaction();
+ // Send the write command
+ digitalWrite(_cs, HIGH);
+
+ spidev->transfer(_sharpmem_vcom | SHARPMEM_BIT_WRITECMD);
+ TOGGLE_VCOM;
+
+ uint8_t bytes_per_line = WIDTH / 8;
+ uint16_t totalbytes = (WIDTH * HEIGHT) / 8;
+
+ for (i = 0; i < totalbytes; i += bytes_per_line) {
+ uint8_t line[bytes_per_line + 2];
+
+ // Send address byte
+ currentline = ((i + 1) / (WIDTH / 8)) + 1;
+ line[0] = currentline;
+ // copy over this line
+ memcpy(line + 1, sharpmem_buffer + i, bytes_per_line);
+ // Send end of line
+ line[bytes_per_line + 1] = 0x00;
+ // send it!
+ spidev->transfer(line, bytes_per_line + 2);
+ }
+
+ // Send another trailing 8 bits for the last line
+ spidev->transfer(0x00);
+ digitalWrite(_cs, LOW);
+ spidev->endTransaction();
+}
+
+/**************************************************************************/
+/*!
+ @brief Clears the display buffer without outputting to the display
+*/
+/**************************************************************************/
+void Adafruit_SharpMem::clearDisplayBuffer() {
+ memset(sharpmem_buffer, 0xff, (WIDTH * HEIGHT) / 8);
+}
diff --git a/code_refs/Adafruit_SharpMem.h b/code_refs/Adafruit_SharpMem.h
new file mode 100644
index 0000000..260a3be
--- /dev/null
+++ b/code_refs/Adafruit_SharpMem.h
@@ -0,0 +1,64 @@
+/*********************************************************************
+This is an Arduino library for our Monochrome SHARP Memory Displays
+
+ Pick one up today in the adafruit shop!
+ ------> http://www.adafruit.com/products/1393
+
+These displays use SPI to communicate, 3 pins are required to
+interface
+
+Adafruit invests time and resources providing this open source code,
+please support Adafruit and open-source hardware by purchasing
+products from Adafruit!
+
+Written by Limor Fried/Ladyada for Adafruit Industries.
+BSD license, check license.txt for more information
+All text above, and the splash screen must be included in any redistribution
+*********************************************************************/
+#ifndef LIB_ADAFRUIT_SHARPMEM
+#define LIB_ADAFRUIT_SHARPMEM
+
+#include <Adafruit_GFX.h>
+#include <Adafruit_SPIDevice.h>
+#include <Arduino.h>
+
+#if defined(RAMSTART) && defined(RAMEND) && ((RAMEND - RAMSTART) < 4096)
+#warning "Display may not work on devices with less than 4K RAM"
+#endif
+
+#define SHARPMEM_BIT_WRITECMD (0x01) // 0x80 in LSB format
+#define SHARPMEM_BIT_VCOM (0x02) // 0x40 in LSB format
+#define SHARPMEM_BIT_CLEAR (0x04) // 0x20 in LSB format
+
+/**
+ * @brief Class to control a Sharp memory display
+ *
+ */
+class Adafruit_SharpMem : public Adafruit_GFX {
+public:
+ Adafruit_SharpMem(uint8_t clk, uint8_t mosi, uint8_t cs, uint16_t w = 96,
+ uint16_t h = 96, uint32_t freq = 2000000);
+ Adafruit_SharpMem(SPIClass *theSPI, uint8_t cs, uint16_t w = 96,
+ uint16_t h = 96, uint32_t freq = 2000000);
+ boolean begin();
+ void drawPixel(int16_t x, int16_t y, uint16_t color);
+ uint8_t getPixel(uint16_t x, uint16_t y);
+ void clearDisplay();
+ void refresh(void);
+ void clearDisplayBuffer();
+ /**
+ * @brief Get a pointer to the display buffer.
+ * This allows direct access to the internal framebuffer.
+ *
+ * @return uint8_t* Pointer to the framebuffer memory.
+ */
+ uint8_t *getBuffer() { return sharpmem_buffer; }
+
+private:
+ Adafruit_SPIDevice *spidev = NULL;
+ uint8_t *sharpmem_buffer = NULL;
+ uint8_t _cs;
+ uint8_t _sharpmem_vcom;
+};
+
+#endif
diff --git a/code_refs/TinyGPS++.cpp b/code_refs/TinyGPS++.cpp
new file mode 100644
index 0000000..6c8d472
--- /dev/null
+++ b/code_refs/TinyGPS++.cpp
@@ -0,0 +1,520 @@
+/*
+TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
+Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
+Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
+Location precision improvements suggested by Wayne Holder.
+Copyright (C) 2008-2024 Mikal Hart
+All rights reserved.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "TinyGPS++.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#define _RMCterm "RMC"
+#define _GGAterm "GGA"
+
+#if !defined(ARDUINO) && !defined(__AVR__)
+// Alternate implementation of millis() that relies on std
+unsigned long millis()
+{
+ static auto start_time = std::chrono::high_resolution_clock::now();
+
+ auto end_time = std::chrono::high_resolution_clock::now();
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
+
+ return static_cast<unsigned long>(duration.count());
+}
+#endif
+
+TinyGPSPlus::TinyGPSPlus()
+ : parity(0)
+ , isChecksumTerm(false)
+ , curSentenceType(GPS_SENTENCE_OTHER)
+ , curTermNumber(0)
+ , curTermOffset(0)
+ , sentenceHasFix(false)
+ , customElts(0)
+ , customCandidates(0)
+ , encodedCharCount(0)
+ , sentencesWithFixCount(0)
+ , failedChecksumCount(0)
+ , passedChecksumCount(0)
+{
+ term[0] = '\0';
+}
+
+//
+// public methods
+//
+
+bool TinyGPSPlus::encode(char c)
+{
+ ++encodedCharCount;
+
+ switch(c)
+ {
+ case ',': // term terminators
+ parity ^= (uint8_t)c;
+ case '\r':
+ case '\n':
+ case '*':
+ {
+ bool isValidSentence = false;
+ if (curTermOffset < sizeof(term))
+ {
+ term[curTermOffset] = 0;
+ isValidSentence = endOfTermHandler();
+ }
+ ++curTermNumber;
+ curTermOffset = 0;
+ isChecksumTerm = c == '*';
+ return isValidSentence;
+ }
+ break;
+
+ case '$': // sentence begin
+ curTermNumber = curTermOffset = 0;
+ parity = 0;
+ curSentenceType = GPS_SENTENCE_OTHER;
+ isChecksumTerm = false;
+ sentenceHasFix = false;
+ return false;
+
+ default: // ordinary characters
+ if (curTermOffset < sizeof(term) - 1)
+ term[curTermOffset++] = c;
+ if (!isChecksumTerm)
+ parity ^= c;
+ return false;
+ }
+
+ return false;
+}
+
+//
+// internal utilities
+//
+int TinyGPSPlus::fromHex(char a)
+{
+ if (a >= 'A' && a <= 'F')
+ return a - 'A' + 10;
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else
+ return a - '0';
+}
+
+// static
+// Parse a (potentially negative) number with up to 2 decimal digits -xxxx.yy
+int32_t TinyGPSPlus::parseDecimal(const char *term)
+{
+ bool negative = *term == '-';
+ if (negative) ++term;
+ int32_t ret = 100 * (int32_t)atol(term);
+ while (isdigit(*term)) ++term;
+ if (*term == '.' && isdigit(term[1]))
+ {
+ ret += 10 * (term[1] - '0');
+ if (isdigit(term[2]))
+ ret += term[2] - '0';
+ }
+ return negative ? -ret : ret;
+}
+
+// static
+// Parse degrees in that funny NMEA format DDMM.MMMM
+void TinyGPSPlus::parseDegrees(const char *term, RawDegrees &deg)
+{
+ uint32_t leftOfDecimal = (uint32_t)atol(term);
+ uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
+ uint32_t multiplier = 10000000UL;
+ uint32_t tenMillionthsOfMinutes = minutes * multiplier;
+
+ deg.deg = (int16_t)(leftOfDecimal / 100);
+
+ while (isdigit(*term))
+ ++term;
+
+ if (*term == '.')
+ while (isdigit(*++term))
+ {
+ multiplier /= 10;
+ tenMillionthsOfMinutes += (*term - '0') * multiplier;
+ }
+
+ deg.billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
+ deg.negative = false;
+}
+
+#define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
+
+// Processes a just-completed term
+// Returns true if new sentence has just passed checksum test and is validated
+bool TinyGPSPlus::endOfTermHandler()
+{
+ // If it's the checksum term, and the checksum checks out, commit
+ if (isChecksumTerm)
+ {
+ byte checksum = 16 * fromHex(term[0]) + fromHex(term[1]);
+ if (checksum == parity)
+ {
+ passedChecksumCount++;
+ if (sentenceHasFix)
+ ++sentencesWithFixCount;
+
+ switch(curSentenceType)
+ {
+ case GPS_SENTENCE_RMC:
+ date.commit();
+ time.commit();
+ if (sentenceHasFix)
+ {
+ location.commit();
+ speed.commit();
+ course.commit();
+ }
+ break;
+ case GPS_SENTENCE_GGA:
+ time.commit();
+ if (sentenceHasFix)
+ {
+ location.commit();
+ altitude.commit();
+ }
+ satellites.commit();
+ hdop.commit();
+ break;
+ }
+
+ // Commit all custom listeners of this sentence type
+ for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0; p = p->next)
+ p->commit();
+ return true;
+ }
+
+ else
+ {
+ ++failedChecksumCount;
+ }
+
+ return false;
+ }
+
+ // the first term determines the sentence type
+ if (curTermNumber == 0)
+ {
+ if (term[0] == 'G' && strchr("PNABL", term[1]) != NULL && !strcmp(term + 2, _RMCterm))
+ curSentenceType = GPS_SENTENCE_RMC;
+ else if (term[0] == 'G' && strchr("PNABL", term[1]) != NULL && !strcmp(term + 2, _GGAterm))
+ curSentenceType = GPS_SENTENCE_GGA;
+ else
+ curSentenceType = GPS_SENTENCE_OTHER;
+
+ // Any custom candidates of this sentence type?
+ for (customCandidates = customElts; customCandidates != NULL && strcmp(customCandidates->sentenceName, term) < 0; customCandidates = customCandidates->next);
+ if (customCandidates != NULL && strcmp(customCandidates->sentenceName, term) > 0)
+ customCandidates = NULL;
+
+ return false;
+ }
+
+ if (curSentenceType != GPS_SENTENCE_OTHER && term[0])
+ switch(COMBINE(curSentenceType, curTermNumber))
+ {
+ case COMBINE(GPS_SENTENCE_RMC, 1): // Time in both sentences
+ case COMBINE(GPS_SENTENCE_GGA, 1):
+ time.setTime(term);
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 2): // RMC validity
+ sentenceHasFix = term[0] == 'A';
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 3): // Latitude
+ case COMBINE(GPS_SENTENCE_GGA, 2):
+ location.setLatitude(term);
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 4): // N/S
+ case COMBINE(GPS_SENTENCE_GGA, 3):
+ location.rawNewLatData.negative = term[0] == 'S';
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 5): // Longitude
+ case COMBINE(GPS_SENTENCE_GGA, 4):
+ location.setLongitude(term);
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 6): // E/W
+ case COMBINE(GPS_SENTENCE_GGA, 5):
+ location.rawNewLngData.negative = term[0] == 'W';
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 7): // Speed (RMC)
+ speed.set(term);
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 8): // Course (RMC)
+ course.set(term);
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 9): // Date (RMC)
+ date.setDate(term);
+ break;
+ case COMBINE(GPS_SENTENCE_GGA, 6): // Fix data (GGA)
+ sentenceHasFix = term[0] > '0';
+ location.newFixQuality = (TinyGPSLocation::Quality)term[0];
+ break;
+ case COMBINE(GPS_SENTENCE_GGA, 7): // Satellites used (GGA)
+ satellites.set(term);
+ break;
+ case COMBINE(GPS_SENTENCE_GGA, 8): // HDOP
+ hdop.set(term);
+ break;
+ case COMBINE(GPS_SENTENCE_GGA, 9): // Altitude (GGA)
+ altitude.set(term);
+ break;
+ case COMBINE(GPS_SENTENCE_RMC, 12):
+ location.newFixMode = (TinyGPSLocation::Mode)term[0];
+ break;
+ }
+
+ // Set custom values as needed
+ for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber; p = p->next)
+ if (p->termNumber == curTermNumber)
+ p->set(term);
+
+ return false;
+}
+
+/* static */
+double TinyGPSPlus::distanceBetween(double lat1, double long1, double lat2, double long2)
+{
+ // returns distance in meters between two positions, both specified
+ // as signed decimal-degrees latitude and longitude. Uses great-circle
+ // distance computation for hypothetical sphere of radius 6371009 meters.
+ // Because Earth is no exact sphere, rounding errors may be up to 0.5%.
+ // Courtesy of Maarten Lamers
+ double delta = radians(long1-long2);
+ double sdlong = sin(delta);
+ double cdlong = cos(delta);
+ lat1 = radians(lat1);
+ lat2 = radians(lat2);
+ double slat1 = sin(lat1);
+ double clat1 = cos(lat1);
+ double slat2 = sin(lat2);
+ double clat2 = cos(lat2);
+ delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
+ delta = sq(delta);
+ delta += sq(clat2 * sdlong);
+ delta = sqrt(delta);
+ double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
+ delta = atan2(delta, denom);
+ return delta * _GPS_EARTH_MEAN_RADIUS;
+}
+
+double TinyGPSPlus::courseTo(double lat1, double long1, double lat2, double long2)
+{
+ // returns course in degrees (North=0, West=270) from position 1 to position 2,
+ // both specified as signed decimal-degrees latitude and longitude.
+ // Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
+ // Courtesy of Maarten Lamers
+ double dlon = radians(long2-long1);
+ lat1 = radians(lat1);
+ lat2 = radians(lat2);
+ double a1 = sin(dlon) * cos(lat2);
+ double a2 = sin(lat1) * cos(lat2) * cos(dlon);
+ a2 = cos(lat1) * sin(lat2) - a2;
+ a2 = atan2(a1, a2);
+ if (a2 < 0.0)
+ {
+ a2 += TWO_PI;
+ }
+ return degrees(a2);
+}
+
+const char *TinyGPSPlus::cardinal(double course)
+{
+ static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
+ int direction = (int)((course + 11.25f) / 22.5f);
+ return directions[direction % 16];
+}
+
+void TinyGPSLocation::commit()
+{
+ rawLatData = rawNewLatData;
+ rawLngData = rawNewLngData;
+ fixQuality = newFixQuality;
+ fixMode = newFixMode;
+ lastCommitTime = millis();
+ valid = updated = true;
+}
+
+void TinyGPSLocation::setLatitude(const char *term)
+{
+ TinyGPSPlus::parseDegrees(term, rawNewLatData);
+}
+
+void TinyGPSLocation::setLongitude(const char *term)
+{
+ TinyGPSPlus::parseDegrees(term, rawNewLngData);
+}
+
+double TinyGPSLocation::lat()
+{
+ updated = false;
+ double ret = rawLatData.deg + rawLatData.billionths / 1000000000.0;
+ return rawLatData.negative ? -ret : ret;
+}
+
+double TinyGPSLocation::lng()
+{
+ updated = false;
+ double ret = rawLngData.deg + rawLngData.billionths / 1000000000.0;
+ return rawLngData.negative ? -ret : ret;
+}
+
+void TinyGPSDate::commit()
+{
+ date = newDate;
+ lastCommitTime = millis();
+ valid = updated = true;
+}
+
+void TinyGPSTime::commit()
+{
+ time = newTime;
+ lastCommitTime = millis();
+ valid = updated = true;
+}
+
+void TinyGPSTime::setTime(const char *term)
+{
+ newTime = (uint32_t)TinyGPSPlus::parseDecimal(term);
+}
+
+void TinyGPSDate::setDate(const char *term)
+{
+ newDate = atol(term);
+}
+
+uint16_t TinyGPSDate::year()
+{
+ updated = false;
+ uint16_t year = date % 100;
+ return year + 2000;
+}
+
+uint8_t TinyGPSDate::month()
+{
+ updated = false;
+ return (date / 100) % 100;
+}
+
+uint8_t TinyGPSDate::day()
+{
+ updated = false;
+ return date / 10000;
+}
+
+uint8_t TinyGPSTime::hour()
+{
+ updated = false;
+ return time / 1000000;
+}
+
+uint8_t TinyGPSTime::minute()
+{
+ updated = false;
+ return (time / 10000) % 100;
+}
+
+uint8_t TinyGPSTime::second()
+{
+ updated = false;
+ return (time / 100) % 100;
+}
+
+uint8_t TinyGPSTime::centisecond()
+{
+ updated = false;
+ return time % 100;
+}
+
+void TinyGPSDecimal::commit()
+{
+ val = newval;
+ lastCommitTime = millis();
+ valid = updated = true;
+}
+
+void TinyGPSDecimal::set(const char *term)
+{
+ newval = TinyGPSPlus::parseDecimal(term);
+}
+
+void TinyGPSInteger::commit()
+{
+ val = newval;
+ lastCommitTime = millis();
+ valid = updated = true;
+}
+
+void TinyGPSInteger::set(const char *term)
+{
+ newval = atol(term);
+}
+
+TinyGPSCustom::TinyGPSCustom(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
+{
+ begin(gps, _sentenceName, _termNumber);
+}
+
+void TinyGPSCustom::begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
+{
+ lastCommitTime = 0;
+ updated = valid = false;
+ sentenceName = _sentenceName;
+ termNumber = _termNumber;
+ memset(stagingBuffer, '\0', sizeof(stagingBuffer));
+ memset(buffer, '\0', sizeof(buffer));
+
+ // Insert this item into the GPS tree
+ gps.insertCustom(this, _sentenceName, _termNumber);
+}
+
+void TinyGPSCustom::commit()
+{
+ strcpy(this->buffer, this->stagingBuffer);
+ lastCommitTime = millis();
+ valid = updated = true;
+}
+
+void TinyGPSCustom::set(const char *term)
+{
+ strncpy(this->stagingBuffer, term, sizeof(this->stagingBuffer) - 1);
+}
+
+void TinyGPSPlus::insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int termNumber)
+{
+ TinyGPSCustom **ppelt;
+
+ for (ppelt = &this->customElts; *ppelt != NULL; ppelt = &(*ppelt)->next)
+ {
+ int cmp = strcmp(sentenceName, (*ppelt)->sentenceName);
+ if (cmp < 0 || (cmp == 0 && termNumber < (*ppelt)->termNumber))
+ break;
+ }
+
+ pElt->next = *ppelt;
+ *ppelt = pElt;
+}
diff --git a/code_refs/TinyGPS++.h b/code_refs/TinyGPS++.h
new file mode 100644
index 0000000..2ee26e0
--- /dev/null
+++ b/code_refs/TinyGPS++.h
@@ -0,0 +1,285 @@
+/*
+TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
+Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
+Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
+Location precision improvements suggested by Wayne Holder.
+Copyright (C) 2008-2024 Mikal Hart
+All rights reserved.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+
+
+#ifndef __TinyGPSPlus_h
+#define __TinyGPSPlus_h
+
+#include <inttypes.h>
+#include "Arduino.h"
+#include <limits.h>
+
+#define _GPS_VERSION "1.1.0" // software version of this library
+#define _GPS_MPH_PER_KNOT 1.15077945
+#define _GPS_MPS_PER_KNOT 0.51444444
+#define _GPS_KMPH_PER_KNOT 1.852
+#define _GPS_MILES_PER_METER 0.00062137112
+#define _GPS_KM_PER_METER 0.001
+#define _GPS_FEET_PER_METER 3.2808399
+#define _GPS_MAX_FIELD_SIZE 15
+#define _GPS_EARTH_MEAN_RADIUS 6371009 // old: 6372795
+
+struct RawDegrees
+{
+ uint16_t deg;
+ uint32_t billionths;
+ bool negative;
+public:
+ RawDegrees() : deg(0), billionths(0), negative(false)
+ {}
+};
+
+struct TinyGPSLocation
+{
+ friend class TinyGPSPlus;
+public:
+ enum Quality { Invalid = '0', GPS = '1', DGPS = '2', PPS = '3', RTK = '4', FloatRTK = '5', Estimated = '6', Manual = '7', Simulated = '8' };
+ enum Mode { N = 'N', A = 'A', D = 'D', E = 'E'};
+
+ bool isValid() const { return valid; }
+ bool isUpdated() const { return updated; }
+ uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
+ const RawDegrees &rawLat() { updated = false; return rawLatData; }
+ const RawDegrees &rawLng() { updated = false; return rawLngData; }
+ double lat();
+ double lng();
+ Quality FixQuality() { updated = false; return fixQuality; }
+ Mode FixMode() { updated = false; return fixMode; }
+
+ TinyGPSLocation() : valid(false), updated(false), fixQuality(Invalid), fixMode(N)
+ {}
+
+private:
+ bool valid, updated;
+ RawDegrees rawLatData, rawLngData, rawNewLatData, rawNewLngData;
+ Quality fixQuality, newFixQuality;
+ Mode fixMode, newFixMode;
+ uint32_t lastCommitTime;
+ void commit();
+ void setLatitude(const char *term);
+ void setLongitude(const char *term);
+};
+
+struct TinyGPSDate
+{
+ friend class TinyGPSPlus;
+public:
+ bool isValid() const { return valid; }
+ bool isUpdated() const { return updated; }
+ uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
+
+ uint32_t value() { updated = false; return date; }
+ uint16_t year();
+ uint8_t month();
+ uint8_t day();
+
+ TinyGPSDate() : valid(false), updated(false), date(0)
+ {}
+
+private:
+ bool valid, updated;
+ uint32_t date, newDate;
+ uint32_t lastCommitTime;
+ void commit();
+ void setDate(const char *term);
+};
+
+struct TinyGPSTime
+{
+ friend class TinyGPSPlus;
+public:
+ bool isValid() const { return valid; }
+ bool isUpdated() const { return updated; }
+ uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
+
+ uint32_t value() { updated = false; return time; }
+ uint8_t hour();
+ uint8_t minute();
+ uint8_t second();
+ uint8_t centisecond();
+
+ TinyGPSTime() : valid(false), updated(false), time(0)
+ {}
+
+private:
+ bool valid, updated;
+ uint32_t time, newTime;
+ uint32_t lastCommitTime;
+ void commit();
+ void setTime(const char *term);
+};
+
+struct TinyGPSDecimal
+{
+ friend class TinyGPSPlus;
+public:
+ bool isValid() const { return valid; }
+ bool isUpdated() const { return updated; }
+ uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
+ int32_t value() { updated = false; return val; }
+
+ TinyGPSDecimal() : valid(false), updated(false), val(0)
+ {}
+
+private:
+ bool valid, updated;
+ uint32_t lastCommitTime;
+ int32_t val, newval;
+ void commit();
+ void set(const char *term);
+};
+
+struct TinyGPSInteger
+{
+ friend class TinyGPSPlus;
+public:
+ bool isValid() const { return valid; }
+ bool isUpdated() const { return updated; }
+ uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
+ uint32_t value() { updated = false; return val; }
+
+ TinyGPSInteger() : valid(false), updated(false), val(0)
+ {}
+
+private:
+ bool valid, updated;
+ uint32_t lastCommitTime;
+ uint32_t val, newval;
+ void commit();
+ void set(const char *term);
+};
+
+struct TinyGPSSpeed : TinyGPSDecimal
+{
+ double knots() { return value() / 100.0; }
+ double mph() { return _GPS_MPH_PER_KNOT * value() / 100.0; }
+ double mps() { return _GPS_MPS_PER_KNOT * value() / 100.0; }
+ double kmph() { return _GPS_KMPH_PER_KNOT * value() / 100.0; }
+};
+
+struct TinyGPSCourse : public TinyGPSDecimal
+{
+ double deg() { return value() / 100.0; }
+};
+
+struct TinyGPSAltitude : TinyGPSDecimal
+{
+ double meters() { return value() / 100.0; }
+ double miles() { return _GPS_MILES_PER_METER * value() / 100.0; }
+ double kilometers() { return _GPS_KM_PER_METER * value() / 100.0; }
+ double feet() { return _GPS_FEET_PER_METER * value() / 100.0; }
+};
+
+struct TinyGPSHDOP : TinyGPSDecimal
+{
+ double hdop() { return value() / 100.0; }
+};
+
+class TinyGPSPlus;
+class TinyGPSCustom
+{
+public:
+ TinyGPSCustom() {};
+ TinyGPSCustom(TinyGPSPlus &gps, const char *sentenceName, int termNumber);
+ void begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber);
+
+ bool isUpdated() const { return updated; }
+ bool isValid() const { return valid; }
+ uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
+ const char *value() { updated = false; return buffer; }
+
+private:
+ void commit();
+ void set(const char *term);
+
+ char stagingBuffer[_GPS_MAX_FIELD_SIZE + 1];
+ char buffer[_GPS_MAX_FIELD_SIZE + 1];
+ unsigned long lastCommitTime;
+ bool valid, updated;
+ const char *sentenceName;
+ int termNumber;
+ friend class TinyGPSPlus;
+ TinyGPSCustom *next;
+};
+
+class TinyGPSPlus
+{
+public:
+ TinyGPSPlus();
+ bool encode(char c); // process one character received from GPS
+ TinyGPSPlus &operator << (char c) {encode(c); return *this;}
+
+ TinyGPSLocation location;
+ TinyGPSDate date;
+ TinyGPSTime time;
+ TinyGPSSpeed speed;
+ TinyGPSCourse course;
+ TinyGPSAltitude altitude;
+ TinyGPSInteger satellites;
+ TinyGPSHDOP hdop;
+
+ static const char *libraryVersion() { return _GPS_VERSION; }
+
+ static double distanceBetween(double lat1, double long1, double lat2, double long2);
+ static double courseTo(double lat1, double long1, double lat2, double long2);
+ static const char *cardinal(double course);
+
+ static int32_t parseDecimal(const char *term);
+ static void parseDegrees(const char *term, RawDegrees &deg);
+
+ uint32_t charsProcessed() const { return encodedCharCount; }
+ uint32_t sentencesWithFix() const { return sentencesWithFixCount; }
+ uint32_t failedChecksum() const { return failedChecksumCount; }
+ uint32_t passedChecksum() const { return passedChecksumCount; }
+
+private:
+ enum {GPS_SENTENCE_GGA, GPS_SENTENCE_RMC, GPS_SENTENCE_OTHER};
+
+ // parsing state variables
+ uint8_t parity;
+ bool isChecksumTerm;
+ char term[_GPS_MAX_FIELD_SIZE];
+ uint8_t curSentenceType;
+ uint8_t curTermNumber;
+ uint8_t curTermOffset;
+ bool sentenceHasFix;
+
+ // custom element support
+ friend class TinyGPSCustom;
+ TinyGPSCustom *customElts;
+ TinyGPSCustom *customCandidates;
+ void insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int index);
+
+ // statistics
+ uint32_t encodedCharCount;
+ uint32_t sentencesWithFixCount;
+ uint32_t failedChecksumCount;
+ uint32_t passedChecksumCount;
+
+ // internal utilities
+ int fromHex(char a);
+ bool endOfTermHandler();
+};
+
+#endif // def(__TinyGPSPlus_h)
diff --git a/code_refs/TinyGPSPlus.h b/code_refs/TinyGPSPlus.h
new file mode 100644
index 0000000..23d9fef
--- /dev/null
+++ b/code_refs/TinyGPSPlus.h
@@ -0,0 +1,26 @@
+/*
+TinyGPSPlus - a small GPS library for Arduino providing universal NMEA parsing
+Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
+Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
+Location precision improvements suggested by Wayne Holder.
+Copyright (C) 2008-2024 Mikal Hart
+All rights reserved.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef __TinyGPSPlus_h
+#include "TinyGPS++.h"
+#endif \ No newline at end of file
diff --git a/code_refs/font_size_quarter_height.png b/code_refs/font_size_quarter_height.png
new file mode 100644
index 0000000..ef45d03
--- /dev/null
+++ b/code_refs/font_size_quarter_height.png
Binary files differ
diff --git a/code_refs/fonts.c b/code_refs/fonts.c
new file mode 100644
index 0000000..528cd89
--- /dev/null
+++ b/code_refs/fonts.c
@@ -0,0 +1,9 @@
+#include "fonts.h"
+
+void set_up_fonts() {
+ jetbrains_mono_quarter.char_w = 8;
+ jetbrains_mono_quarter.char_h = 17;
+ jetbrains_mono_quarter.bytes_per_char = 17;
+ jetbrains_mono_quarter.font_bytes[1598] = {255,255,255,231,231,215,215,219,219,131,189,189,61,255,255,255,255,255,255,255,193,189,189,189,193,157,189,189,189,193,255,255,255,255,255,255,255,195,187,189,253,253,253,253,189,187,195,255,255,255,255,255,255,255,193,157,189,189,189,189,189,189,157,193,255,255,255,255,255,255,255,129,249,249,249,129,249,249,249,249,129,255,255,255,255,255,255,255,129,253,253,253,129,249,249,249,249,249,255,255,255,255,255,255,255,195,187,253,253,141,189,189,189,187,195,255,255,255,255,255,255,255,189,189,189,189,129,189,189,189,189,189,255,255,255,255,255,255,255,131,239,239,239,239,239,239,239,239,131,255,255,255,255,255,255,255,191,191,191,191,191,191,191,189,157,195,255,255,255,255,255,255,255,61,189,221,205,225,205,221,157,189,61,255,255,255,255,255,255,255,251,251,251,251,251,251,251,251,251,3,255,255,255,255,255,255,255,185,153,149,165,165,173,189,189,189,189,255,255,255,255,255,255,255,185,185,181,181,173,173,173,157,157,157,255,255,255,255,255,255,255,195,187,189,189,189,189,189,189,187,195,255,255,255,255,255,255,255,193,189,61,61,189,129,253,253,253,253,255,255,255,255,255,255,255,195,185,189,189,189,189,189,189,185,195,223,159,191,255,255,255,255,193,189,189,189,193,205,221,221,189,61,255,255,255,255,255,255,255,195,187,189,249,227,159,191,189,185,195,255,255,255,255,255,255,255,1,239,239,239,239,239,239,239,239,239,255,255,255,255,255,255,255,189,189,189,189,189,189,189,189,187,195,255,255,255,255,255,255,255,61,189,185,187,219,219,215,215,231,231,255,255,255,255,255,255,255,110,101,101,101,85,149,149,153,153,155,255,255,255,255,255,255,255,61,187,219,215,231,231,215,219,185,61,255,255,255,255,255,255,255,61,189,155,219,215,231,239,239,239,239,255,255,255,255,255,255,255,129,191,223,207,239,247,247,251,249,129,255,255,255,255,255,255,255,255,255,195,185,191,131,185,189,153,163,255,255,255,255,255,255,255,253,253,197,185,189,189,189,189,185,197,255,255,255,255,255,255,255,255,255,195,187,189,253,253,189,187,195,255,255,255,255,255,255,255,191,191,163,155,189,189,189,189,155,163,255,255,255,255,255,255,255,255,255,195,187,189,129,253,253,187,195,255,255,255,255,255,255,255,143,247,247,129,247,247,247,247,247,247,255,255,255,255,255,255,255,255,255,163,155,189,189,189,189,155,163,191,191,195,255,255,255,255,253,253,197,153,185,189,189,189,189,189,255,255,255,255,255,255,207,207,255,227,239,239,239,239,239,239,1,255,255,255,255,255,255,159,159,255,193,223,223,223,223,223,223,223,223,207,225,255,255,255,255,249,249,57,153,217,225,201,217,185,57,255,255,255,255,255,255,255,240,247,247,247,247,247,247,247,247,15,255,255,255,255,255,255,255,255,255,145,173,45,45,45,45,45,45,255,255,255,255,255,255,255,255,255,197,153,185,189,189,189,189,189,255,255,255,255,255,255,255,255,255,195,187,189,189,189,189,187,195,255,255,255,255,255,255,255,255,255,197,185,189,189,189,189,185,197,253,253,253,255,255,255,255,255,255,163,155,189,189,189,189,155,163,191,191,191,255,255,255,255,255,255,195,187,187,187,251,251,251,251,255,255,255,255,255,255,255,255,255,195,185,253,227,159,191,185,195,255,255,255,255,255,255,255,247,247,129,247,247,247,247,247,247,143,255,255,255,255,255,255,255,255,255,189,189,189,189,189,189,155,195,255,255,255,255,255,255,255,255,255,61,185,187,219,219,215,231,231,255,255,255,255,255,255,255,255,255,108,101,101,165,149,149,153,155,255,255,255,255,255,255,255,255,255,185,219,215,231,231,211,155,61,255,255,255,255,255,255,255,255,255,61,185,187,219,211,215,231,239,231,247,247,255,255,255,255,255,255,129,159,223,239,247,243,251,129,255,255,255,255,255,255,255,231,235,237,239,239,239,239,239,239,1,255,255,255,255,255,255,255,195,185,189,191,191,223,239,247,251,129,255,255,255,255,255,255,255,129,223,239,199,159,191,191,189,153,195,255,255,255,255,255,255,255,223,239,231,247,187,185,189,129,191,191,255,255,255,255,255,255,255,129,253,249,193,159,191,191,189,153,195,255,255,255,255,255,255,255,207,247,247,195,187,189,189,189,185,195,255,255,255,255,255,255,255,1,189,189,159,223,223,239,239,231,247,255,255,255,255,255,255,255,195,185,189,187,199,153,189,189,185,195,255,255,255,255,255,255,255,195,185,189,189,185,131,223,207,239,247,255,255,255,255,255,255,255,195,185,189,189,165,189,189,189,185,195,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,231,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,239,231,231,247,255,255,255,255,239,239,239,239,239,239,239,255,255,231,255,255,255,255,255,255,255,195,185,125,77,45,117,117,117,109,141,253,249,199,255,239,239,199,139,173,233,235,195,143,175,173,173,195,239,239,255,255,255,255,255,113,182,214,209,239,23,103,107,109,28,255,255,255,255,255,255,239,231,215,219,187,189,255,255,255,255,255,255,255,255,255,255,255,255,195,219,187,251,241,109,156,156,141,97,255,255,255,255,255,191,207,231,247,247,247,247,246,247,247,247,238,207,191,255,255,255,251,243,239,239,223,223,223,223,223,207,239,239,243,251,255,255,255,159,239,239,239,239,239,241,239,239,239,239,239,143,255,255,255,255,241,231,247,247,247,247,143,247,247,247,247,231,241,255,255,255,255,199,247,247,247,247,247,247,247,247,247,247,247,199,255,255,255,255,227,239,239,239,239,239,239,239,239,239,239,239,227,255,255,255,255,255,255,239,239,239,239,255,255,255,255,255,255,255,255,255,255,255,255,255,215,215,215,215,255,255,255,255,255,255,255,255,255,255,255,255,255,195,159,191,159,199,247,247,255,255,231,255,255,255,255,255,255,255,255,127,63,207,243,251,231,143,63,255,255,255,255,255,255,255,255,255,255,252,243,207,223,231,241,252,255,255,255,255,255,255,255,255,255,255,231,231,255,255,255,255,231,231,255,255,255,255,255,255,255,255,255,231,231,255,255,255,255,255,239,231,247,247,255,255,253,249,251,251,247,247,231,239,239,207,223,223,191,191,255,255,255,191,191,159,223,223,239,239,239,247,247,243,251,251,253,255,255,255,255,255,255,255,255,255,255,195,255,255,255,255,255,255,255,255,255,255,255,255,255,239,239,239,129,239,239,239,255,255,255,255,255,255,255,255,255,255,255,129,255,255,129,255,255,255,255,255,255,255,255,255,255,255,255,255,179,173,141,255,255,255,255,255,255,255,255,255,255,255,199,219,219,199,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,1,255,255,255,255,255,255,255,239,239,45,131,231,211,155,255,255,255,255,255,255,255,239,239,239,239,239,239,239,239,239,239,239,239,239,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};
+ jetbrains_mono_quarter.font_lookup[128] = {93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,64,77,93,66,67,69,76,70,71,91,86,63,85,62,84,61,52,53,54,55,56,57,58,59,60,81,82,79,87,80,78,65,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,74,83,75,68,90,89,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,72,92,73,88,93};
+} \ No newline at end of file
diff --git a/code_refs/fonts.h b/code_refs/fonts.h
new file mode 100644
index 0000000..f204f2c
--- /dev/null
+++ b/code_refs/fonts.h
@@ -0,0 +1,14 @@
+#include <stdint.h>
+
+typedef struct {
+ uint8_t char_w;
+ uint8_t char_h;
+ uint16_t bytes_per_char;
+ uint8_t *font_bytes;
+ uint8_t *font_lookup;
+} bitmap_font_t;
+
+bitmap_font_t jetbrains_mono_quarter;
+
+void set_up_fonts();
+
diff --git a/code_refs/image_2_bytes.py b/code_refs/image_2_bytes.py
new file mode 100644
index 0000000..62524a3
--- /dev/null
+++ b/code_refs/image_2_bytes.py
@@ -0,0 +1,94 @@
+from PIL import Image
+import sys
+import os
+from math import pow, ceil
+
+IMG_HEADER = "uint8_t image[1360] = {"
+IMG_END = "};"
+#
+# ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.,!@$%^&(){}[]'"?<>:;\/-+=~`_*|
+#
+byte_array = []
+
+if len(sys.argv) != 3:
+ print("Incorrect arguments supplied. Usage: python image_2_bytes.py <inputfile> <font/img>.")
+ quit()
+
+filename = sys.argv[1]
+
+if not os.path.exists(filename):
+ print("Image file does not exist.")
+ quit()
+
+img = Image.open(filename)
+
+if sys.argv[2] == "img":
+ if img.size != (160, 68):
+ print("Image is of incorrect size, must be 160x68.")
+ quit()
+
+ byte_index = 0
+ current_byte = 0
+ for pixel in list(img.getdata()):
+ if pixel != 0: # if not black, then white
+ current_byte += int(pow(2, (byte_index)))
+ byte_index += 1
+ if byte_index == 8:
+ byte_array.append(str(current_byte))
+ current_byte = 0
+ byte_index = 0
+
+ file_string = IMG_HEADER + ",".join(byte_array) + IMG_END
+ with open("image.txt", "w") as f:
+ f.write(file_string)
+
+ print("Image converted successfully.")
+elif sys.argv[2] == "font":
+ character_width = int(input("Width of each character: "))
+ character_height = int(input("Height of each character: "))
+ if img.size[0] % character_width != 0:
+ print("Image width must be a multiple of the character width.")
+ quit()
+ if img.size[1] % character_height != 0:
+ print("Image height must be a multiple of the character height.")
+ quit()
+
+ bytes_per_char = character_height * ceil(character_width/8)
+
+ charstr = input("Input string of characters present in image: ")
+
+ font_index = [-1 for _ in range(128)]
+ spacechar = "-1"
+ for i, character in enumerate(charstr):
+ if character == " ":
+ spacechar = i
+ font_index[ord(character)] = str(i) # ascii -> glyph index
+ x_offset = i*character_width % img.size[0]
+ y_offset = character_height * (i*character_width // img.size[0])
+ for y in range(character_height):
+ byte_index = 0
+ current_byte = 0
+ for x in range(character_width):
+ if img.getpixel((x_offset+x, y_offset+y)) != 0:
+ current_byte += int(pow(2, (byte_index)))
+ byte_index += 1
+ if byte_index == 8:
+ byte_array.append(str(current_byte))
+ current_byte = 0
+ byte_index = 0
+ if byte_index != 0: # character width isn't multiple of 8
+ byte_array.append(str(current_byte))
+ if spacechar != "-1":
+ for i in range(128):
+ if font_index[i] == -1:
+ font_index[i] = str(spacechar)
+ file_string = f"uint8_t char_w = {character_width};\nuint8_t char_h = {character_height};\nuint16_t bytes_per_char = {bytes_per_char};\n"
+ file_string += f"uint8_t font_bytes[{len(byte_array)}] = " + "{" + ",".join(byte_array) + "};\n"
+ file_string += "int8_t font_lookup[128] = {" + ",".join(font_index) + "};"
+ with open("font.h", "w") as f:
+ f.write(file_string)
+
+ print("Image converted successfully.")
+else:
+ print("Invalid operation. Must be either 'img' or 'font'.")
+ quit() \ No newline at end of file
diff --git a/code_refs/output.txt b/code_refs/output.txt
new file mode 100644
index 0000000..4e4d0ed
--- /dev/null
+++ b/code_refs/output.txt
@@ -0,0 +1 @@
+uint8_t testimg[1360] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,7,192,1,252,240,0,248,31,248,199,3,0,0,7,112,224,143,223,255,255,7,192,1,60,192,0,248,31,224,199,3,0,0,7,112,128,143,223,255,255,255,254,253,159,255,223,255,223,231,215,127,255,251,247,127,191,47,223,255,255,255,254,253,223,255,223,255,223,207,155,127,255,251,247,127,63,111,223,255,255,255,254,253,223,255,223,255,223,207,187,127,255,251,247,127,191,111,222,255,255,255,254,1,156,255,223,255,223,239,187,127,255,251,7,112,159,239,222,255,255,255,254,1,60,248,223,255,223,231,125,127,255,251,7,112,192,239,220,255,255,255,254,253,255,225,223,255,31,240,125,127,255,251,247,127,224,239,221,255,255,255,254,253,255,207,223,255,31,252,0,127,255,251,247,127,207,239,219,255,255,255,254,253,255,159,223,255,223,255,0,126,255,251,247,127,223,239,219,255,255,255,254,253,255,159,223,255,223,255,254,126,255,251,247,127,191,239,215,255,255,255,254,253,255,207,223,255,223,127,254,124,255,251,247,127,63,239,199,255,255,255,254,1,28,224,223,255,223,127,255,125,255,251,7,112,127,238,207,255,255,255,254,1,124,248,223,255,223,127,255,125,255,251,7,112,255,236,207,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,31,255,255,255,255,249,255,255,255,255,255,63,255,255,255,255,255,255,255,255,207,255,255,255,255,249,255,255,255,255,255,63,255,255,255,255,255,255,255,255,231,255,255,255,243,249,255,255,255,255,255,255,255,63,255,255,255,255,255,255,231,255,255,255,243,249,255,255,255,255,255,255,255,63,255,255,255,255,255,255,131,143,159,249,129,153,63,252,63,124,56,51,103,30,248,255,255,255,255,255,231,115,30,248,243,57,206,249,207,31,55,48,231,56,255,255,255,255,255,255,231,243,156,255,243,121,206,243,199,159,63,63,231,57,255,255,255,255,255,255,231,241,156,255,243,121,6,240,135,143,63,63,231,57,255,255,255,255,255,255,231,241,156,255,243,121,198,255,15,140,63,63,231,57,255,255,255,255,255,255,231,241,156,255,243,121,198,255,127,136,63,63,231,57,255,255,255,255,255,255,231,243,156,255,243,121,206,255,255,153,63,63,231,57,255,255,255,255,255,255,231,115,158,255,227,121,142,247,247,28,55,63,231,60,254,255,255,255,255,255,231,143,159,255,143,121,62,248,15,127,56,63,39,254,248,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}; \ No newline at end of file
diff --git a/code_refs/scratchpad.c b/code_refs/scratchpad.c
new file mode 100644
index 0000000..0fc1cfa
--- /dev/null
+++ b/code_refs/scratchpad.c
@@ -0,0 +1,37 @@
+ W25Q_STATE s = W25Q_Init(); // init the chip
+ s = W25Q_EraseSector(0); // erase 4K sector - required before recording
+
+ // make test data
+ u8_t byte = 0x6D;
+ u8_t byte_read = 0;
+ u8_t in_page_shift = 0;
+ u8_t page_number = 0;
+ // write data
+ s= W25Q_ProgramByte(byte, in_page_shift, page_number);
+ // read data
+ s = W25Q_ReadByte(&byte_read, in_page_shift, page_number);
+ s = W25Q_Sleep();
+ char str[10];
+ sprintf(str, "read: %i", byte_read);
+ SHARPMEM_write(&lcd, str, 0, 0, 51, true, false);
+ SHARPMEM_refresh_display(&lcd);
+
+ if(!HAL_I2C_IsDeviceReady(&hi2c1, 0x32, 3, 1000)) {
+ SHARPMEM_write(&lcd, "I2C works", 0, 0, 17, true, false);
+ SHARPMEM_refresh_display(&lcd);
+ uint8_t whoami[1] = {0};
+ char whoami_str[10];
+ HAL_StatusTypeDef e = HAL_I2C_Mem_Read(&hi2c1, 0x3C, 0x22, 1, whoami, 1, 1000);
+ if(!e){
+ sprintf(whoami_str, "%i", byte_read);
+ SHARPMEM_write(&lcd, whoami_str, 0, 0, 34, true, false);
+ SHARPMEM_refresh_display(&lcd);
+ } else {
+ sprintf(whoami_str, "err: %x", (uint8_t)e);
+ SHARPMEM_write(&lcd, whoami_str, 0, 0, 34, true, false);
+ SHARPMEM_refresh_display(&lcd);
+ }
+ } else {
+ SHARPMEM_write(&lcd, "I2C doesn't work", 0, 0, 17, true, false);
+ SHARPMEM_refresh_display(&lcd);
+ }
diff --git a/code_refs/sharpmem.c b/code_refs/sharpmem.c
new file mode 100644
index 0000000..4e0040a
--- /dev/null
+++ b/code_refs/sharpmem.c
@@ -0,0 +1,87 @@
+#include "sharpmem.h"
+
+void SHARPMEM_TOGGLEVCOM(SharpMemDisplay_t *display) {
+ display->_sharpmem_vcom = display->_sharpmem_vcom ? 0x00 : SHARPMEM_BIT_VCOM;
+}
+
+void SHARPMEM_draw_pixel(SharpMemDisplay_t *display, uint16_t x, uint16_t y, bool white) {
+ if ((x < 0) || (x >= display->width) || (y < 0) || (y >= display->height))
+ return;
+
+ if (black) {
+ display->buffer[(y * WIDTH + x) / 8] |= (0x1 << (x & 7)); //potentially expensive when run many times, use lookup from adafruit lib
+ } else {
+ display->buffer[(y * WIDTH + x) / 8] &= ~(0x1 << (x & 7));
+ }
+}
+
+void SHARPMEM_draw_line(SharpMemDisplay_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool white, uint8_t thickness) {
+
+}
+
+void SHARPMEM_draw_circle(SharpMemDisplay_t *display, uint16_t x, uint16_t y, uint8_t r, bool filled) {
+
+}
+
+void SHARPMEM_draw_rect(SharpMemDisplay_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool filled) {
+
+}
+
+uint8_t SHARPMEM_get_pixel(SharpMemDisplay_t *display, uint16_t x, uint16_t y) {
+
+}
+
+void SHARPMEM_clear_display(SharpMemDisplay_t *display) {
+ memset(display->_buffer, 0xff, (display->width * display->height) / 8);
+
+ // Send the clear screen command rather than doing a HW refresh (quicker)
+
+ uint8_t clear_data[2] = {(uint8_t)(display->_sharpmem_vcom | SHARPMEM_BIT_CLEAR),
+ 0x00};
+
+ HAL_GPIO_WritePin(display->cs_pin_bank, display->cs_pin, GPIO_PIN_SET);
+ HAL_SPI_Transmit(&display->spidev, clear_data, 2);
+ HAL_GPIO_WritePin(display->cs_pin_bank, display->cs_pin, GPIO_PIN_RESET);
+
+ SHARPMEM_TOGGLEVCOM(display);
+}
+
+void SHARPMEM_refresh_display(SharpMemDisplay_t *display) {
+ uint16_t i, currentline;
+
+ spidev->beginTransaction();
+ // Send the write command
+ HAL_GPIO_WritePin(display->cs_pin_bank, display->cs_pin, GPIO_PIN_SET);
+
+ HAL_SPI_Transmit(&display->spidev, (_sharpmem_vcom | SHARPMEM_BIT_WRITECMD), 1);
+ SHARPMEM_TOGGLEVCOM(display);;
+
+ uint8_t bytes_per_line = display->width / 8;
+ uint16_t totalbytes = (display->width * display->height) / 8;
+
+ for (i = 0; i < totalbytes; i += bytes_per_line) {
+ uint8_t line[bytes_per_line + 2];
+
+ // Send address byte
+ currentline = ((i + 1) / (WIDTH / 8)) + 1;
+ line[0] = currentline;
+ // copy over this line
+ memcpy(line + 1, display->_buffer + i, bytes_per_line);
+ // Send end of line
+ line[bytes_per_line + 1] = 0x00;
+ // send it!
+ HAL_SPI_Transmit(&display->spidev, line, bytes_per_line + 2);
+ }
+
+ // Send another trailing 8 bits for the last line
+ HAL_SPI_Transmit(&display->spidev, (0x00), 1);
+ HAL_GPIO_WritePin(display->cs_pin_bank, display->cs_pin, GPIO_PIN_RESET);
+}
+
+void SHARPMEM_clear_display_buffer(SharpMemDisplay_t *display) {
+
+}
+
+uint8_t *SHARPMEM_get_buffer(SharpMemDisplay_t *display) {
+
+} \ No newline at end of file
diff --git a/code_refs/sharpmem.h b/code_refs/sharpmem.h
new file mode 100644
index 0000000..288a18b
--- /dev/null
+++ b/code_refs/sharpmem.h
@@ -0,0 +1,36 @@
+#include <stdbool.h>
+
+#ifndef _STM32_SHARPMEM
+#define _STM32_SHARPMEM
+
+#define SHARPMEM_BIT_WRITECMD (0x01) // 0x80 in LSB format
+#define SHARPMEM_BIT_VCOM (0x02) // 0x40 in LSB format
+#define SHARPMEM_BIT_CLEAR (0x04) // 0x20 in LSB format
+
+typedef struct
+{
+ uint16_t width;
+ uint16_t height;
+ uint16_t cs_pin;
+ GPIO_TypeDef *cs_pin_bank;
+ uint16_t lcdmode_pin;
+ GPIO_TypeDef *lcdmode_pin_bank;
+ SPI_HandleTypeDef *spidev;
+
+ uint8_t *_buffer;
+ uint8_t _sharpmem_vcom;
+} SharpMemDisplay_t;
+
+void SHARPMEM_draw_pixel(SharpMemDisplay_t *display, uint16_t x, uint16_t y, bool white);
+void SHARPMEM_draw_line(SharpMemDisplay_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool white, uint8_t thickness)
+void SHARPMEM_draw_circle(SharpMemDisplay_t *display, uint16_t x, uint16_t y, uint8_t r, bool filled);
+void SHARPMEM_draw_rect(SharpMemDisplay_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool filled);
+uint8_t SHARPMEM_get_pixel(SharpMemDisplay_t *display, uint16_t x, uint16_t y);
+void SHARPMEM_clear_display(SharpMemDisplay_t *display);
+void SHARPMEM_refresh_display(SharpMemDisplay_t *display);
+void SHARPMEM_clear_display_buffer(SharpMemDisplay_t *display);
+uint8_t *SHARPMEM_get_buffer(SharpMemDisplay_t *display);
+
+void SHARPMEM_TOGGLEVCOM(SharpMemDisplay_t *display);
+
+#endif \ No newline at end of file
diff --git a/code_refs/test_bw_image.png b/code_refs/test_bw_image.png
new file mode 100644
index 0000000..649b568
--- /dev/null
+++ b/code_refs/test_bw_image.png
Binary files differ