add utf8, some glyphs, and more font rendering options

master
Ondřej Hruška 4 years ago
parent 7299521ab1
commit 12f9d2ec2c
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 6
      main/CMakeLists.txt
  2. 2
      main/app_main.c
  3. 145
      main/graphics/font.c
  4. 24
      main/graphics/font.h
  5. 225
      main/graphics/nokia.c
  6. 16
      main/graphics/nokia.h
  7. 116
      main/graphics/utf8.c
  8. 65
      main/graphics/utf8.h
  9. 4
      main/gui.c
  10. 2
      main/liquid/scene_car.c
  11. 24
      main/liquid/scene_root.c

@ -1,13 +1,15 @@
set(COMPONENT_SRCS set(COMPONENT_SRCS
"app_main.c" "app_main.c"
"nokia.c"
"knob.c" "knob.c"
"gui.c" "gui.c"
"analog.c" "analog.c"
"liquid/liquid.c" "liquid/liquid.c"
"liquid/scene_root.c" "liquid/scene_root.c"
"liquid/scene_car.c" "liquid/scene_car.c"
"graphics/nokia.c"
"graphics/utf8.c"
"graphics/font.c"
) )
set(COMPONENT_ADD_INCLUDEDIRS "liquid") set(COMPONENT_ADD_INCLUDEDIRS "liquid" "graphics")
register_component() register_component()

@ -11,7 +11,7 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_spi_flash.h" #include "esp_spi_flash.h"
#include "nokia.h" #include "graphics/nokia.h"
#include "knob.h" #include "knob.h"
#include "gui.h" #include "gui.h"
#include "analog.h" #include "analog.h"

@ -0,0 +1,145 @@
#include "font.h"
#include "utf8.h"
#include <stdint.h>
#define FONT_EXTRAS_START (0x7e - 0x20 + 1)
const struct FontSymbol font[] = {
// ASCII from 0x20 to 0x7e are ordered at the beginning for quick access by index
{.symbol=" ", .graphic = {0x00, 0x00, 0x00, 0x00, 0x00}}, // 0x20
{.symbol="!", .graphic = {0x00, 0x00, 0x5f, 0x00, 0x00}}, // 0x21
{.symbol="\"", .graphic = {0x00, 0x07, 0x00, 0x07, 0x00}}, // 0x22
{.symbol="#", .graphic = {0x14, 0x7f, 0x14, 0x7f, 0x14}}, // 0x23
{.symbol="$", .graphic = {0x24, 0x2a, 0x7f, 0x2a, 0x12}}, // 0x24
{.symbol="%", .graphic = {0x23, 0x13, 0x08, 0x64, 0x62}}, // 0x25
{.symbol="&", .graphic = {0x36, 0x49, 0x55, 0x22, 0x50}}, // 0x26
{.symbol="'", .graphic = {0x00, 0x05, 0x03, 0x00, 0x00}}, // 0x27
{.symbol="(", .graphic = {0x00, 0x1c, 0x22, 0x41, 0x00}}, // 0x28
{.symbol=")", .graphic = {0x00, 0x41, 0x22, 0x1c, 0x00}}, // 0x29
{.symbol="*", .graphic = {0x14, 0x08, 0x3e, 0x08, 0x14}}, // 0x2a
{.symbol="+", .graphic = {0x08, 0x08, 0x3e, 0x08, 0x08}}, // 0x2b
{.symbol=",", .graphic = {0x00, 0x50, 0x30, 0x00, 0x00}}, // 0x2c
{.symbol="-", .graphic = {0x08, 0x08, 0x08, 0x08, 0x08}}, // 0x2d
{.symbol=".", .graphic = {0x00, 0x60, 0x60, 0x00, 0x00}}, // 0x2e
{.symbol="/", .graphic = {0x20, 0x10, 0x08, 0x04, 0x02}}, // 0x2f
{.symbol="0", .graphic = {0x3e, 0x51, 0x49, 0x45, 0x3e}}, // 0x30
{.symbol="1", .graphic = {0x00, 0x42, 0x7f, 0x40, 0x00}}, // 0x31
{.symbol="2", .graphic = {0x42, 0x61, 0x51, 0x49, 0x46}}, // 0x32
{.symbol="3", .graphic = {0x21, 0x41, 0x45, 0x4b, 0x31}}, // 0x33
{.symbol="4", .graphic = {0x18, 0x14, 0x12, 0x7f, 0x10}}, // 0x34
{.symbol="5", .graphic = {0x27, 0x45, 0x45, 0x45, 0x39}}, // 0x35
{.symbol="6", .graphic = {0x3c, 0x4a, 0x49, 0x49, 0x30}}, // 0x36
{.symbol="7", .graphic = {0x01, 0x71, 0x09, 0x05, 0x03}}, // 0x37
{.symbol="8", .graphic = {0x36, 0x49, 0x49, 0x49, 0x36}}, // 0x38
{.symbol="9", .graphic = {0x06, 0x49, 0x49, 0x29, 0x1e}}, // 0x39
{.symbol=":", .graphic = {0x00, 0x36, 0x36, 0x00, 0x00}}, // 0x3a
{.symbol=";", .graphic = {0x00, 0x56, 0x36, 0x00, 0x00}}, // 0x3b
{.symbol="<", .graphic = {0x08, 0x14, 0x22, 0x41, 0x00}}, // 0x3c
{.symbol="=", .graphic = {0x14, 0x14, 0x14, 0x14, 0x14}}, // 0x3d
{.symbol=">", .graphic = {0x00, 0x41, 0x22, 0x14, 0x08}}, // 0x3e
{.symbol="?", .graphic = {0x02, 0x01, 0x51, 0x09, 0x06}}, // 0x3f
{.symbol="@", .graphic = {0x32, 0x49, 0x79, 0x41, 0x3e}}, // 0x40
{.symbol="A", .graphic = {0x7e, 0x11, 0x11, 0x11, 0x7e}}, // 0x41
{.symbol="B", .graphic = {0x7f, 0x49, 0x49, 0x49, 0x36}}, // 0x42
{.symbol="C", .graphic = {0x3e, 0x41, 0x41, 0x41, 0x22}}, // 0x43
{.symbol="D", .graphic = {0x7f, 0x41, 0x41, 0x22, 0x1c}}, // 0x44
{.symbol="E", .graphic = {0x7f, 0x49, 0x49, 0x49, 0x41}}, // 0x45
{.symbol="F", .graphic = {0x7f, 0x09, 0x09, 0x09, 0x01}}, // 0x46
{.symbol="G", .graphic = {0x3e, 0x41, 0x49, 0x49, 0x7a}}, // 0x47
{.symbol="H", .graphic = {0x7f, 0x08, 0x08, 0x08, 0x7f}}, // 0x48
{.symbol="I", .graphic = {0x00, 0x41, 0x7f, 0x41, 0x00}}, // 0x49
{.symbol="J", .graphic = {0x20, 0x40, 0x41, 0x3f, 0x01}}, // 0x4a
{.symbol="K", .graphic = {0x7f, 0x08, 0x14, 0x22, 0x41}}, // 0x4b
{.symbol="L", .graphic = {0x7f, 0x40, 0x40, 0x40, 0x40}}, // 0x4c
{.symbol="M", .graphic = {0x7f, 0x02, 0x0c, 0x02, 0x7f}}, // 0x4d
{.symbol="N", .graphic = {0x7f, 0x04, 0x08, 0x10, 0x7f}}, // 0x4e
{.symbol="O", .graphic = {0x3e, 0x41, 0x41, 0x41, 0x3e}}, // 0x4f
{.symbol="P", .graphic = {0x7f, 0x09, 0x09, 0x09, 0x06}}, // 0x50
{.symbol="Q", .graphic = {0x3e, 0x41, 0x51, 0x21, 0x5e}}, // 0x51
{.symbol="R", .graphic = {0x7f, 0x09, 0x19, 0x29, 0x46}}, // 0x52
{.symbol="S", .graphic = {0x46, 0x49, 0x49, 0x49, 0x31}}, // 0x53
{.symbol="T", .graphic = {0x01, 0x01, 0x7f, 0x01, 0x01}}, // 0x54
{.symbol="U", .graphic = {0x3f, 0x40, 0x40, 0x40, 0x3f}}, // 0x55
{.symbol="V", .graphic = {0x1f, 0x20, 0x40, 0x20, 0x1f}}, // 0x56
{.symbol="W", .graphic = {0x3f, 0x40, 0x38, 0x40, 0x3f}}, // 0x57
{.symbol="X", .graphic = {0x63, 0x14, 0x08, 0x14, 0x63}}, // 0x58
{.symbol="Y", .graphic = {0x07, 0x08, 0x70, 0x08, 0x07}}, // 0x59
{.symbol="Z", .graphic = {0x61, 0x51, 0x49, 0x45, 0x43}}, // 0x5a
{.symbol="[", .graphic = {0x00, 0x7f, 0x41, 0x41, 0x00}}, // 0x5b
{.symbol="\\", .graphic = {0x02, 0x04, 0x08, 0x10, 0x20}}, // 0x5c
{.symbol="]", .graphic = {0x00, 0x41, 0x41, 0x7f, 0x00}}, // 0x5d
{.symbol="^", .graphic = {0x04, 0x02, 0x01, 0x02, 0x04}}, // 0x5e
{.symbol="_", .graphic = {0x40, 0x40, 0x40, 0x40, 0x40}}, // 0x5f
{.symbol="`", .graphic = {0x00, 0x01, 0x02, 0x04, 0x00}}, // 0x60
{.symbol="a", .graphic = {0x20, 0x54, 0x54, 0x54, 0x78}}, // 0x61
{.symbol="b", .graphic = {0x7f, 0x48, 0x44, 0x44, 0x38}}, // 0x62
{.symbol="c", .graphic = {0x38, 0x44, 0x44, 0x44, 0x20}}, // 0x63
{.symbol="d", .graphic = {0x38, 0x44, 0x44, 0x48, 0x7f}}, // 0x64
{.symbol="e", .graphic = {0x38, 0x54, 0x54, 0x54, 0x18}}, // 0x65
{.symbol="f", .graphic = {0x08, 0x7e, 0x09, 0x01, 0x02}}, // 0x66
{.symbol="g", .graphic = {0x0c, 0x52, 0x52, 0x52, 0x3e}}, // 0x67
{.symbol="h", .graphic = {0x7f, 0x08, 0x04, 0x04, 0x78}}, // 0x68
{.symbol="i", .graphic = {0x00, 0x44, 0x7d, 0x40, 0x00}}, // 0x69
{.symbol="j", .graphic = {0x20, 0x40, 0x44, 0x3d, 0x00}}, // 0x6a
{.symbol="k", .graphic = {0x7f, 0x10, 0x28, 0x44, 0x00}}, // 0x6b
{.symbol="l", .graphic = {0x00, 0x41, 0x7f, 0x40, 0x00}}, // 0x6c
{.symbol="m", .graphic = {0x7c, 0x04, 0x18, 0x04, 0x78}}, // 0x6d
{.symbol="n", .graphic = {0x7c, 0x08, 0x04, 0x04, 0x78}}, // 0x6e
{.symbol="o", .graphic = {0x38, 0x44, 0x44, 0x44, 0x38}}, // 0x6f
{.symbol="p", .graphic = {0x7c, 0x14, 0x14, 0x14, 0x08}}, // 0x70
{.symbol="q", .graphic = {0x08, 0x14, 0x14, 0x18, 0x7c}}, // 0x71
{.symbol="r", .graphic = {0x7c, 0x08, 0x04, 0x04, 0x08}}, // 0x72
{.symbol="s", .graphic = {0x48, 0x54, 0x54, 0x54, 0x20}}, // 0x73
{.symbol="t", .graphic = {0x04, 0x3f, 0x44, 0x40, 0x20}}, // 0x74
{.symbol="u", .graphic = {0x3c, 0x40, 0x40, 0x20, 0x7c}}, // 0x75
{.symbol="v", .graphic = {0x1c, 0x20, 0x40, 0x20, 0x1c}}, // 0x76
{.symbol="w", .graphic = {0x3c, 0x40, 0x30, 0x40, 0x3c}}, // 0x77
{.symbol="x", .graphic = {0x44, 0x28, 0x10, 0x28, 0x44}}, // 0x78
{.symbol="y", .graphic = {0x0c, 0x50, 0x50, 0x50, 0x3c}}, // 0x79
{.symbol="z", .graphic = {0x44, 0x64, 0x54, 0x4c, 0x44}}, // 0x7a
{.symbol="{", .graphic = {0x00, 0x08, 0x36, 0x41, 0x00}}, // 0x7b
{.symbol="|", .graphic = {0x00, 0x00, 0x7f, 0x00, 0x00}}, // 0x7c
{.symbol="}", .graphic = {0x00, 0x41, 0x36, 0x08, 0x00}}, // 0x7d
{.symbol="~", .graphic = {0x10, 0x08, 0x08, 0x10, 0x08}}, // 0x7e
// start of UTF8 glyphs. These can include custom graphics mapped to codepoints
{.symbol="<EFBFBD>", .graphic = {0xFF, 0x81, 0x81, 0x81, 0xFF}}, // box
{.symbol="×", .graphic = { 0x22, 0x14, 0x08, 0x14, 0x22 }}, // cross
{.symbol="", .graphic = { 0x08, 0x04, 0x3e, 0x04, 0x08 }}, // arrow_up
{.symbol="", .graphic = { 0x08, 0x10, 0x3e, 0x10, 0x08 }}, // arrow_down
{.symbol="", .graphic = { 0x08, 0x1c, 0x2a, 0x08, 0x08 }}, // arrow_left
{.symbol="", .graphic = { 0x08, 0x08, 0x2a, 0x1c, 0x08 }}, // arrow_right
{.symbol="", .graphic = { 0x1c, 0x22, 0x2e, 0x2a, 0x1c }}, // clock
{.symbol="", .graphic = { 0x63, 0x55, 0x4d, 0x55, 0x63 }}, // hourglass
{.symbol="", .graphic = { 0x1c, 0x22, 0x2a, 0x22, 0x1c }}, // wheel
{.symbol="", .graphic = { 0x10, 0x38, 0x54, 0x10, 0x1e }}, // return
{.symbol="🌡", .graphic = { 0x60, 0x9e, 0x81, 0x9e, 0x6a }}, // thermometer
{.symbol="°", .graphic = { 0x00, 0x07, 0x05, 0x07, 0x00 }}, // degree
{.symbol="🔙", .graphic = { 0x04, 0x4e, 0x55, 0x44, 0x38 }}, // back
{.symbol="", .graphic = { 0x7f, 0x3e, 0x1c, 0x08, 0x00 }}, // tri_right
{.symbol="", .graphic = { 0x00, 0x08, 0x1c, 0x3e, 0x7f }}, // tri_left
// End of the list
{},
};
const struct FontSymbol *Font_GetSymbol(struct Utf8Char ch) {
if (ch.bytes[0] < ' ') {
return &font[FONT_EXTRAS_START]; // replacement character
}
if (ch.bytes[0] < 127) {
return &font[ch.bytes[0] - 0x20];
}
const struct FontSymbol *sym = &font[FONT_EXTRAS_START];
while (sym->symbol[0]) {
if (sym->uint == ch.uint) {
return sym;
}
sym++;
}
return &font[FONT_EXTRAS_START]; // replacement character
}

@ -0,0 +1,24 @@
/**
* TODO file description
*
* Created on 2020/01/04.
*/
#ifndef REFLOWER_FONT_H
#define REFLOWER_FONT_H
#include "font.h"
#include "utf8.h"
#include <stdint.h>
struct FontSymbol {
union {
const char symbol[4];
const uint32_t uint;
};
uint8_t graphic[5];
};
const struct FontSymbol *Font_GetSymbol(struct Utf8Char ch);
#endif //REFLOWER_FONT_H

@ -2,6 +2,8 @@
#include <arch/cc.h> #include <arch/cc.h>
#include <driver/spi_master.h> #include <driver/spi_master.h>
#include "nokia.h" #include "nokia.h"
#include "utf8.h"
#include "font.h"
#include <string.h> #include <string.h>
/* Pin definitions: /* Pin definitions:
@ -22,112 +24,6 @@ static const int sclkPin = 13; // SCLK - Serial clock, pin 7 on LCD.
static spi_device_handle_t hSPI; static spi_device_handle_t hSPI;
/* Font table:
This table contains the hex values that represent pixels for a
font that is 5 pixels wide and 8 pixels high. Each byte in a row
represents one, 8-pixel, vertical column of a character. 5 bytes
per character. */
static const uint8_t ASCII[][5] = {
// First 32 characters (0x00-0x19) are ignored. These are
// non-displayable, control characters.
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20
{0x00, 0x00, 0x5f, 0x00, 0x00}, // 0x21 !
{0x00, 0x07, 0x00, 0x07, 0x00}, // 0x22 "
{0x14, 0x7f, 0x14, 0x7f, 0x14}, // 0x23 #
{0x24, 0x2a, 0x7f, 0x2a, 0x12}, // 0x24 $
{0x23, 0x13, 0x08, 0x64, 0x62}, // 0x25 %
{0x36, 0x49, 0x55, 0x22, 0x50}, // 0x26 &
{0x00, 0x05, 0x03, 0x00, 0x00}, // 0x27 '
{0x00, 0x1c, 0x22, 0x41, 0x00}, // 0x28 (
{0x00, 0x41, 0x22, 0x1c, 0x00}, // 0x29 )
{0x14, 0x08, 0x3e, 0x08, 0x14}, // 0x2a *
{0x08, 0x08, 0x3e, 0x08, 0x08}, // 0x2b +
{0x00, 0x50, 0x30, 0x00, 0x00}, // 0x2c ,
{0x08, 0x08, 0x08, 0x08, 0x08}, // 0x2d -
{0x00, 0x60, 0x60, 0x00, 0x00}, // 0x2e .
{0x20, 0x10, 0x08, 0x04, 0x02}, // 0x2f /
{0x3e, 0x51, 0x49, 0x45, 0x3e}, // 0x30 0
{0x00, 0x42, 0x7f, 0x40, 0x00}, // 0x31 1
{0x42, 0x61, 0x51, 0x49, 0x46}, // 0x32 2
{0x21, 0x41, 0x45, 0x4b, 0x31}, // 0x33 3
{0x18, 0x14, 0x12, 0x7f, 0x10}, // 0x34 4
{0x27, 0x45, 0x45, 0x45, 0x39}, // 0x35 5
{0x3c, 0x4a, 0x49, 0x49, 0x30}, // 0x36 6
{0x01, 0x71, 0x09, 0x05, 0x03}, // 0x37 7
{0x36, 0x49, 0x49, 0x49, 0x36}, // 0x38 8
{0x06, 0x49, 0x49, 0x29, 0x1e}, // 0x39 9
{0x00, 0x36, 0x36, 0x00, 0x00}, // 0x3a :
{0x00, 0x56, 0x36, 0x00, 0x00}, // 0x3b ;
{0x08, 0x14, 0x22, 0x41, 0x00}, // 0x3c <
{0x14, 0x14, 0x14, 0x14, 0x14}, // 0x3d =
{0x00, 0x41, 0x22, 0x14, 0x08}, // 0x3e >
{0x02, 0x01, 0x51, 0x09, 0x06}, // 0x3f ?
{0x32, 0x49, 0x79, 0x41, 0x3e}, // 0x40 @
{0x7e, 0x11, 0x11, 0x11, 0x7e}, // 0x41 A
{0x7f, 0x49, 0x49, 0x49, 0x36}, // 0x42 B
{0x3e, 0x41, 0x41, 0x41, 0x22}, // 0x43 C
{0x7f, 0x41, 0x41, 0x22, 0x1c}, // 0x44 D
{0x7f, 0x49, 0x49, 0x49, 0x41}, // 0x45 E
{0x7f, 0x09, 0x09, 0x09, 0x01}, // 0x46 F
{0x3e, 0x41, 0x49, 0x49, 0x7a}, // 0x47 G
{0x7f, 0x08, 0x08, 0x08, 0x7f}, // 0x48 H
{0x00, 0x41, 0x7f, 0x41, 0x00}, // 0x49 I
{0x20, 0x40, 0x41, 0x3f, 0x01}, // 0x4a J
{0x7f, 0x08, 0x14, 0x22, 0x41}, // 0x4b K
{0x7f, 0x40, 0x40, 0x40, 0x40}, // 0x4c L
{0x7f, 0x02, 0x0c, 0x02, 0x7f}, // 0x4d M
{0x7f, 0x04, 0x08, 0x10, 0x7f}, // 0x4e N
{0x3e, 0x41, 0x41, 0x41, 0x3e}, // 0x4f O
{0x7f, 0x09, 0x09, 0x09, 0x06}, // 0x50 P
{0x3e, 0x41, 0x51, 0x21, 0x5e}, // 0x51 Q
{0x7f, 0x09, 0x19, 0x29, 0x46}, // 0x52 R
{0x46, 0x49, 0x49, 0x49, 0x31}, // 0x53 S
{0x01, 0x01, 0x7f, 0x01, 0x01}, // 0x54 T
{0x3f, 0x40, 0x40, 0x40, 0x3f}, // 0x55 U
{0x1f, 0x20, 0x40, 0x20, 0x1f}, // 0x56 V
{0x3f, 0x40, 0x38, 0x40, 0x3f}, // 0x57 W
{0x63, 0x14, 0x08, 0x14, 0x63}, // 0x58 X
{0x07, 0x08, 0x70, 0x08, 0x07}, // 0x59 Y
{0x61, 0x51, 0x49, 0x45, 0x43}, // 0x5a Z
{0x00, 0x7f, 0x41, 0x41, 0x00}, // 0x5b [
{0x02, 0x04, 0x08, 0x10, 0x20}, // 0x5c \ (keep this to escape the backslash)
{0x00, 0x41, 0x41, 0x7f, 0x00}, // 0x5d ]
{0x04, 0x02, 0x01, 0x02, 0x04}, // 0x5e ^
{0x40, 0x40, 0x40, 0x40, 0x40}, // 0x5f _
{0x00, 0x01, 0x02, 0x04, 0x00}, // 0x60 `
{0x20, 0x54, 0x54, 0x54, 0x78}, // 0x61 a
{0x7f, 0x48, 0x44, 0x44, 0x38}, // 0x62 b
{0x38, 0x44, 0x44, 0x44, 0x20}, // 0x63 c
{0x38, 0x44, 0x44, 0x48, 0x7f}, // 0x64 d
{0x38, 0x54, 0x54, 0x54, 0x18}, // 0x65 e
{0x08, 0x7e, 0x09, 0x01, 0x02}, // 0x66 f
{0x0c, 0x52, 0x52, 0x52, 0x3e}, // 0x67 g
{0x7f, 0x08, 0x04, 0x04, 0x78}, // 0x68 h
{0x00, 0x44, 0x7d, 0x40, 0x00}, // 0x69 i
{0x20, 0x40, 0x44, 0x3d, 0x00}, // 0x6a j
{0x7f, 0x10, 0x28, 0x44, 0x00}, // 0x6b k
{0x00, 0x41, 0x7f, 0x40, 0x00}, // 0x6c l
{0x7c, 0x04, 0x18, 0x04, 0x78}, // 0x6d m
{0x7c, 0x08, 0x04, 0x04, 0x78}, // 0x6e n
{0x38, 0x44, 0x44, 0x44, 0x38}, // 0x6f o
{0x7c, 0x14, 0x14, 0x14, 0x08}, // 0x70 p
{0x08, 0x14, 0x14, 0x18, 0x7c}, // 0x71 q
{0x7c, 0x08, 0x04, 0x04, 0x08}, // 0x72 r
{0x48, 0x54, 0x54, 0x54, 0x20}, // 0x73 s
{0x04, 0x3f, 0x44, 0x40, 0x20}, // 0x74 t
{0x3c, 0x40, 0x40, 0x20, 0x7c}, // 0x75 u
{0x1c, 0x20, 0x40, 0x20, 0x1c}, // 0x76 v
{0x3c, 0x40, 0x30, 0x40, 0x3c}, // 0x77 w
{0x44, 0x28, 0x10, 0x28, 0x44}, // 0x78 x
{0x0c, 0x50, 0x50, 0x50, 0x3c}, // 0x79 y
{0x44, 0x64, 0x54, 0x4c, 0x44}, // 0x7a z
{0x00, 0x08, 0x36, 0x41, 0x00}, // 0x7b {
{0x00, 0x00, 0x7f, 0x00, 0x00}, // 0x7c |
{0x00, 0x41, 0x36, 0x08, 0x00}, // 0x7d }
{0x10, 0x08, 0x08, 0x10, 0x08}, // 0x7e ~
{0x78, 0x46, 0x41, 0x46, 0x78}, // 0x7f DEL
};
/* The displayMap variable stores a buffer representation of the /* The displayMap variable stores a buffer representation of the
pixels on our display. There are 504 total bits in this array, pixels on our display. There are 504 total bits in this array,
same as how many pixels there are on a 84 x 48 display. same as how many pixels there are on a 84 x 48 display.
@ -325,18 +221,52 @@ void LCD_setCircle(int x0, int y0, int radius, bool bw, int lineThickness)
// This function will draw a char (defined in the ASCII table // This function will draw a char (defined in the ASCII table
// near the beginning of this sketch) at a defined x and y). // near the beginning of this sketch) at a defined x and y).
// The color can be either black (1) or white (0). // The color can be either black (1) or white (0).
void LCD_setChar(char character, int x, int y, bool bw) void LCD_setChar(struct Utf8Char character, int x, int y, bool bw)
{
LCD_setCharEx(character, x, y, bw, 1);
}
void LCD_setCharEx(struct Utf8Char character, int x, int y, bool bw, uint8_t size)
{ {
const struct FontSymbol *symbol = Font_GetSymbol(character);
bool backfill = size &0x80;
size &= 0x7F;
uint8_t column; // temp byte to store character's column bitmap uint8_t column; // temp byte to store character's column bitmap
for (int i = 0; i < 5; i++) // 5 columns (x) per character for (int i = 0; i < 5; i++) // 5 columns (x) per character
{ {
column = ASCII[character - 0x20][i]; column = symbol->graphic[i];
for (int j = 0; j < 8; j++) // 8 rows (y) per character for (int j = 0; j < 8; j++) // 8 rows (y) per character
{ {
if (column & (0x01 << j)) // test bits to set pixels bool bit = column & (0x01 << j);
LCD_setPixel(x + i, y + j, bw);
else if (size == 1) {
LCD_setPixel(x + i, y + j, !bw); if (bit) {// test bits to set pixels
LCD_setPixel(x + i, y + j, bw);
} else if(backfill) {
LCD_setPixel(x + i, y + j, !bw);
}
} else if (size == 2) {
if (bit) {// test bits to set pixels
LCD_setPixel(x + i * 2, y + j * 2, bw);
LCD_setPixel(x + i * 2 + 1, y + j * 2, bw);
LCD_setPixel(x + i * 2, y + j * 2 + 1, bw);
LCD_setPixel(x + i * 2 + 1, y + j * 2 + 1, bw);
} else if(backfill) {
LCD_setPixel(x + i * 2, y + j * 2, !bw);
LCD_setPixel(x + i * 2 + 1, y + j * 2, !bw);
LCD_setPixel(x + i * 2, y + j * 2 + 1, !bw);
LCD_setPixel(x + i * 2 + 1, y + j * 2 + 1, !bw);
}
} else if (size == 3) {
if (bit) {// test bits to set pixels
LCD_setPixel(x + i, y + j, bw);
LCD_setPixel(x + i + 1, y + j, bw);
} else if(backfill) {
LCD_setPixel(x + i, y + j, !bw);
LCD_setPixel(x + i + 1, y + j, !bw);
}
}
} }
} }
} }
@ -347,18 +277,65 @@ void LCD_setChar(char character, int x, int y, bool bw)
// library. // library.
void LCD_setStr(const char *dString, int x, int y, bool bw) void LCD_setStr(const char *dString, int x, int y, bool bw)
{ {
while (*dString != 0x00) // loop until null terminator LCD_setStrEx(dString, x, y, bw, 1);
{ }
LCD_setChar(*dString++, x, y, bw);
x += 5; // setStr draws a string of characters, calling setChar with
for (int i = y; i < y + 8; i++) { // progressive coordinates until it's done.
LCD_setPixel(x, i, !bw); // This function was grabbed from the SparkFun ColorLCDShield
} // library.
x++; void LCD_setStrEx(const char *dString, int x, int y, bool bw, uint8_t size)
if (x > (LCD_WIDTH - 5)) // Enables wrap around {
{ struct Utf8Iterator iter;
x = 0; Utf8Iterator_Start(&iter, dString);
y += 8; bool backfill = size & 0x80;
uint8_t size_real = size & 0x7F;
struct Utf8Char uchar;
while ((uchar = Utf8Iterator_Next(&iter)).uint) {
LCD_setCharEx(uchar, x, y, bw, size);
if (size_real == 1) {
x += 5;
if (backfill) {
for (int i = y; i < y + 8; i++) {
LCD_setPixel(x, i, !bw);
}
}
x++;
if (x > (LCD_WIDTH - 5)) // Enables wrap around
{
x = 0;
y += 8;
}
} else if (size_real == 2) {
x += 10;
if (backfill) {
for (int i = y; i < y + 16; i++) {
LCD_setPixel(x, i, !bw);
LCD_setPixel(x + 1, i, !bw);
}
}
x+=2;
if (x > (LCD_WIDTH - 10)) // Enables wrap around
{
x = 0;
y += 16;
}
} else if (size_real == 3) {
x += 6;
if (backfill) {
for (int i = y; i < y + 8; i++) {
LCD_setPixel(x, i, !bw);
LCD_setPixel(x + 1, i, !bw);
}
}
x+=1;
if (x > (LCD_WIDTH - 6)) // Enables wrap around
{
x = 0;
y += 8;
}
} }
} }
} }

@ -12,6 +12,7 @@ LED (backlight) pin should remain on a PWM-capable pin. */
/* 84x48 LCD Defines: */ /* 84x48 LCD Defines: */
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "utf8.h"
#define LCD_WIDTH 84 // Note: x-coordinates go wide #define LCD_WIDTH 84 // Note: x-coordinates go wide
#define LCD_HEIGHT 48 // Note: y-coordinates go high #define LCD_HEIGHT 48 // Note: y-coordinates go high
@ -35,10 +36,21 @@ void LCD_setRect(int x0, int y0, int x1, int y1, bool fill, bool bw);
// thickness ranging from 1 to the radius of the circle. // thickness ranging from 1 to the radius of the circle.
void LCD_setCircle (int x0, int y0, int radius, bool bw, int lineThickness); void LCD_setCircle (int x0, int y0, int radius, bool bw, int lineThickness);
/*
FONT FUNCTIONS
size = 1 ... normal
size = 2 ... 2x
size = 3 ... normal bold
size | 0x80 ... clear background behind characters
*/
// This function will draw a char (defined in the ASCII table // This function will draw a char (defined in the ASCII table
// near the beginning of this sketch) at a defined x and y). // near the beginning of this sketch) at a defined x and y).
// The color can be either black (1) or white (0). // The color can be either black (1) or white (0).
void LCD_setChar(char character, int x, int y, bool bw); void LCD_setChar(struct Utf8Char character, int x, int y, bool bw);
void LCD_setCharEx(struct Utf8Char character, int x, int y, bool bw, uint8_t size);
// setStr draws a string of characters, calling setChar with // setStr draws a string of characters, calling setChar with
// progressive coordinates until it's done. // progressive coordinates until it's done.
@ -46,6 +58,8 @@ void LCD_setChar(char character, int x, int y, bool bw);
// library. // library.
void LCD_setStr(const char * dString, int x, int y, bool bw); void LCD_setStr(const char * dString, int x, int y, bool bw);
void LCD_setStrEx(const char *dString, int x, int y, bool bw, uint8_t size);
// This function clears the entire display either white (0) or // This function clears the entire display either white (0) or
// black (1). // black (1).
// The screen won't actually clear until you call updateDisplay()! // The screen won't actually clear until you call updateDisplay()!

@ -0,0 +1,116 @@
#include <stdint.h>
#include "utf8.h"
#include <string.h>
//
// Created by MightyPork on 2017/08/20.
//
// UTF-8 parser - collects bytes of a code point before writing them
// into a screen cell.
//
const struct Utf8Char EMPTY_CHAR = (struct Utf8Char) { .uint = 0 };
// Code Points First Byte Second Byte Third Byte Fourth Byte
// U+0000 - U+007F 00 - 7F
// U+0080 - U+07FF C2 - DF 80 - BF
// U+0800 - U+0FFF E0 *A0 - BF 80 - BF
// U+1000 - U+CFFF E1 - EC 80 - BF 80 - BF
// U+D000 - U+D7FF ED 80 - *9F 80 - BF
// U+E000 - U+FFFF EE - EF 80 - BF 80 - BF
// U+10000 - U+3FFFF F0 *90 - BF 80 - BF 80 - BF
// U+40000 - U+FFFFF F1 - F3 80 - BF 80 - BF 80 - BF
// U+100000 - U+10FFFF F4 80 - *8F 80 - BF 80 - BF
/**
* Handle a received character
*/
struct Utf8Char Utf8Parser_Handle(struct Utf8Parser *self, char c)
{
uint8_t *bytes = self->buffer.bytes;
uint8_t uc = (uint8_t)c;
// collecting unicode glyphs...
if (uc & 0x80) {
if (self->utf_len == 0) {
bytes[0] = uc;
self->utf_j = 1;
// start
if (uc == 0xC0 || uc == 0xC1 || uc > 0xF4) {
// forbidden start codes
goto fail;
}
if ((uc & 0xE0) == 0xC0) {
self->utf_len = 2;
}
else if ((uc & 0xF0) == 0xE0) {
self->utf_len = 3;
}
else if ((uc & 0xF8) == 0xF0) {
self->utf_len = 4;
}
else {
// chars over 127 that don't start unicode sequences
goto fail;
}
}
else {
if ((uc & 0xC0) != 0x80) {
bytes[self->utf_j++] = uc;
goto fail;
}
else {
bytes[self->utf_j++] = uc;
if (self->utf_j >= self->utf_len) {
// check for bad sequences - overlong or some other problem
if (bytes[0] == 0xF4 && bytes[1] > 0x8F) goto fail;
if (bytes[0] == 0xF0 && bytes[1] < 0x90) goto fail;
if (bytes[0] == 0xED && bytes[1] > 0x9F) goto fail;
if (bytes[0] == 0xE0 && bytes[1] < 0xA0) goto fail;
// trap for surrogates - those break javascript
if (bytes[0] == 0xED && bytes[1] >= 0xA0 && bytes[1] <= 0xBF) goto fail;
goto success;
}
}
}
}
else {
bytes[0] = uc;
goto success;
}
return EMPTY_CHAR;
success:;
struct Utf8Char result = self->buffer;
self->buffer.uint = 0; // erase the buffer
self->utf_len = 0;
return result;
fail:
self->buffer.uint = 0; // erase the buffer
self->utf_len = 0;
return EMPTY_CHAR;
}
void Utf8Iterator_Start(struct Utf8Iterator *self, const char *source) {
memset(self, 0, sizeof(struct Utf8Iterator));
self->source = source;
}
struct Utf8Char Utf8Iterator_Next(struct Utf8Iterator *self) {
char c;
struct Utf8Char uchar;
while ((c = *self->source++) != 0) {
uchar = Utf8Parser_Handle(&self->parser, c);
if (uchar.uint) {
return uchar;
}
}
return EMPTY_CHAR;
}

@ -0,0 +1,65 @@
/**
* TODO file description
*
* Created on 2020/01/04.
*/
#ifndef LIQUIDTYPE_UTF8_H
#define LIQUIDTYPE_UTF8_H
#include <stddef.h>
#include <stdint.h>
struct Utf8Char {
union {
uint8_t bytes[4];
uint32_t uint;
};
};
struct Utf8Parser {
struct Utf8Char buffer;
uint8_t utf_len;
uint8_t utf_j;
};
/**
* Utf8 character iterator.
*
* Usage:
* struct Utf8Iterator iter;
* Utf8Iterator_Start(&iter, myString);
*
* union Utf8Char uchar;
* while ((uchar = Utf8Iterator_Next(&iter)).uint) {
* // do something with the char
* }
*
* // Free myString if needed.
* // The iterator does not need any cleanup if it lives on stack.
*/
struct Utf8Iterator {
/* Characters to parse. The pointer is advanced as the iterator progresses. */
const char *source;
struct Utf8Parser parser;
};
void Utf8Iterator_Start(struct Utf8Iterator *self, const char *source);
/**
* Get the next character from the iterator; Returns empty character if there are no more characters to parse.
*
* Invalid characters are skipped.
*/
struct Utf8Char Utf8Iterator_Next(struct Utf8Iterator *self);
/**
* Parse a character.
*
* The returned struct contains NIL (uint == 0) if no character is yet available.
*
* ASCII is passed through, utf-8 is collected and returned in one piece.
*/
struct Utf8Char Utf8Parser_Handle(struct Utf8Parser *self, char c);
#endif //LIQUIDTYPE_UTF8_H

@ -1,5 +1,5 @@
#include "gui.h" #include "gui.h"
#include "nokia.h" #include "graphics/nokia.h"
#include "analog.h" #include "analog.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
@ -17,7 +17,7 @@ void gui_init() {
printf("GUI init\n"); printf("GUI init\n");
LCD_setup(); LCD_setup();
LCD_setContrast(60); LCD_setContrast(48);
LCD_clearDisplay(0); LCD_clearDisplay(0);
LCD_setStr("Hello World", 0, 0, 1); LCD_setStr("Hello World", 0, 0, 1);

@ -1,6 +1,6 @@
#include "scenes.h" #include "scenes.h"
#include "liquid.h" #include "liquid.h"
#include "../nokia.h" #include "../graphics/nokia.h"
#include <malloc.h> #include <malloc.h>
struct private { struct private {

@ -1,6 +1,6 @@
#include "scenes.h" #include "scenes.h"
#include "liquid.h" #include "liquid.h"
#include "../nokia.h" #include "../graphics/nokia.h"
#include "../analog.h" #include "../analog.h"
#include <malloc.h> #include <malloc.h>
#include <stdio.h> #include <stdio.h>
@ -51,27 +51,29 @@ static void Root_paint(struct Scene *scene)
const char *header = "???"; const char *header = "???";
switch (priv->timer_phase) { switch (priv->timer_phase) {
case 0: case 0:
header = "ICE"; header = "Drink water";
break; break;
case 1: case 1:
header = " COLD"; header = " Drink water";
break; break;
case 2: case 2:
header = "COCA"; header = " Drink water";
break; break;
case 3: case 3:
header = " COLA"; header = " Drink water";
break; break;
} }
LCD_setStr(header, 20, 3, 1); LCD_setStrEx(header, 0, 3, 1, 3);
LCD_setRect(0, 15, 83, 35, 1, 1); LCD_setRect(0, 12, 83, 33, 1, 1);
char buf[10]; char buf[10];
sprintf(buf, "%3d", priv->pos); // sprintf(buf, "%3d", priv->pos);
LCD_setStr(buf, 2, 17, 0); // LCD_setStr(buf, 2, 15, 0);
sprintf(buf, "%.0f C", analog_read()); sprintf(buf, "🌡%.0f°C", analog_read());
LCD_setStr(buf, 2, 26, 0); LCD_setStrEx(buf, 2, 15, 0, 2);
LCD_setStr("×↑↓←→⏰⌛☸⏎🌡°🔙▶◀", 2, 33, 1);
LCD_updateDisplay(); LCD_updateDisplay();
} }

Loading…
Cancel
Save