1
0
forked from me/IronOS

Merge pull request #896 from alvinhochun/extend-font-encoding

Extend font encoding changes
This commit is contained in:
Ben V. Brown
2021-03-20 19:32:56 +11:00
committed by GitHub
4 changed files with 115 additions and 29 deletions

View File

@@ -233,6 +233,55 @@ def getCJKGlyph(sym):
return s return s
def getCharsFromFontIndex(index: int) -> str:
'''
Converts the font table index into its corresponding string escape
sequence(s).
'''
# We want to be able to use more than 254 symbols (excluding \x00 null
# terminator and \x01 new-line) in the font table but without making all
# the chars take 2 bytes. To do this, we use \xF1 to \xFF as lead bytes
# to designate double-byte chars, and leave the remaining as single-byte
# chars.
#
# For the sake of sanity, \x00 always means the end of string, so we skip
# \xF1\x00 and others in the mapping.
#
# Mapping example:
#
# 0x02 => 2
# 0x03 => 3
# ...
# 0xEF => 239
# 0xF0 => 240
# 0xF1 0x01 => 1 * 0xFF - 15 + 1 = 241
# 0xF1 0x02 => 1 * 0xFF - 15 + 2 = 242
# ...
# 0xF1 0xFF => 1 * 0xFF - 15 + 255 = 495
# 0xF2 0x01 => 2 * 0xFF - 15 + 1 = 496
# ...
# 0xF2 0xFF => 2 * 0xFF - 15 + 255 = 750
# 0xF3 0x01 => 3 * 0xFF - 15 + 1 = 751
# ...
# 0xFF 0xFF => 15 * 0xFF - 15 + 255 = 4065
assert index >= 0
page = int((index + 14) / 0xFF)
assert page <= 0x0F
if page == 0:
return "\\x%0.2X" % index
else:
# Into extended range
# Leader is 0xFz where z is the page number
# Following char is the remainder
leader = page + 0xF0
value = ((index + 14) % 0xFF) + 1
assert leader <= 0xFF
assert value <= 0xFF
return "\\x%0.2X\\x%0.2X" % (leader, value)
def getFontMapAndTable(textList): def getFontMapAndTable(textList):
# the text list is sorted # the text list is sorted
# allocate out these in their order as number codes # allocate out these in their order as number codes
@@ -242,29 +291,20 @@ def getFontMapAndTable(textList):
forcedFirstSymbols = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] forcedFirstSymbols = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
# enforce numbers are first # enforce numbers are first
for sym in forcedFirstSymbols: for sym in forcedFirstSymbols:
symbolMap[sym] = "\\x%0.2X" % index symbolMap[sym] = getCharsFromFontIndex(index)
index = index + 1 index = index + 1
totalSymbolCount = len(set(textList) | set(forcedFirstSymbols)) totalSymbolCount = len(set(textList) | set(forcedFirstSymbols))
# \x00 is for NULL termination and \x01 is for newline, so the maximum # \x00 is for NULL termination and \x01 is for newline, so the maximum
# number of symbols allowed with 8 bits is `256 - 2`. # number of symbols allowed is as follow (see also the comments in
if totalSymbolCount > ((0xEE * 0x0F) - 2): # `getCharsFromFontIndex`):
if totalSymbolCount > (0x10 * 0xFF - 15) - 2:
log(f"Error, too many used symbols for this version (total {totalSymbolCount})") log(f"Error, too many used symbols for this version (total {totalSymbolCount})")
sys.exit(1) sys.exit(1)
log("Generating fonts for {} symbols".format(totalSymbolCount)) log("Generating fonts for {} symbols".format(totalSymbolCount))
for sym in textList: for sym in textList:
if sym not in symbolMap: if sym not in symbolMap:
page = int(index / 0xEF) symbolMap[sym] = getCharsFromFontIndex(index)
if page == 0:
symbolMap[sym] = "\\x%0.2X" % index
else:
# Into extended range
# Leader is 0xFz where z is the page number
# Following char is the remainder
leader = page + 0xF0
value = (index % 0xEF) + 1
symbolMap[sym] = "\\x%0.2X" % leader + "\\x%0.2X" % value
index = index + 1 index = index + 1
# Get the font table # Get the font table
fontTableStrings = [] fontTableStrings = []

View File

@@ -0,0 +1,21 @@
import unittest
class TestMakeTranslation(unittest.TestCase):
def test_getCharsFromFontIndex(self):
from make_translation import getCharsFromFontIndex
self.assertEqual(getCharsFromFontIndex(2), "\\x02")
self.assertEqual(getCharsFromFontIndex(239), "\\xEF")
self.assertEqual(getCharsFromFontIndex(240), "\\xF0")
self.assertEqual(getCharsFromFontIndex(241), "\\xF1\\x01")
self.assertEqual(getCharsFromFontIndex(495), "\\xF1\\xFF")
self.assertEqual(getCharsFromFontIndex(496), "\\xF2\\x01")
self.assertEqual(getCharsFromFontIndex(750), "\\xF2\\xFF")
self.assertEqual(getCharsFromFontIndex(751), "\\xF3\\x01")
self.assertEqual(getCharsFromFontIndex(0x10 * 0xFF - 15), "\\xFF\\xFF")
with self.assertRaises(AssertionError):
getCharsFromFontIndex(0x10 * 0xFF - 14)
if __name__ == '__main__':
unittest.main()

View File

@@ -235,20 +235,21 @@ void OLED::setRotation(bool leftHanded) {
} }
// print a string to the current cursor location // print a string to the current cursor location
void OLED::print(const char *str) { void OLED::print(const char *const str) {
uint16_t page = 0; const uint8_t *next = reinterpret_cast<const uint8_t *>(str);
while (str[0]) { while (next[0]) {
if (static_cast<uint8_t>(str[0]) >= 0xF0) { uint16_t index;
page = static_cast<uint16_t>(str[0] & 0x0F); if (next[0] <= 0xF0) {
} else if (page != 0) { index = next[0];
page *= 0xEF; next++;
page += static_cast<uint8_t>(str[0]) - 1;
drawChar(page);
page = 0;
} else { } else {
drawChar(str[0]); if (!next[1]) {
return;
}
index = (next[0] - 0xF0) * 0xFF - 15 + next[1];
next += 2;
} }
str++; drawChar(index);
} }
} }

View File

@@ -12,7 +12,6 @@
#include "Translation.h" #include "Translation.h"
#include "cmsis_os.h" #include "cmsis_os.h"
#include "main.hpp" #include "main.hpp"
#include "string.h"
void gui_Menu(const menuitem *menu); void gui_Menu(const menuitem *menu);
@@ -274,8 +273,33 @@ static void printShortDescription(uint32_t shortDescIndex, uint16_t cursorCharPo
OLED::setCursor(OLED::getCursorX() - 2, 0); OLED::setCursor(OLED::getCursorX() - 2, 0);
} }
/**
* Counts the number of chars in the string excluding the null terminator.
* This is a custom version of `strlen` which takes into account our custom
* double-byte char encoding.
* @param str The input string.
* @return The length of the string.
*/
static uint16_t str_display_len(const char *const str) {
const uint8_t *next = reinterpret_cast<const uint8_t *>(str);
uint16_t count = 0;
while (next[0]) {
if (next[0] <= 0xF0) {
count++;
next++;
} else {
if (!next[1]) {
break;
}
count++;
next += 2;
}
}
return count;
}
static int userConfirmation(const char *message) { static int userConfirmation(const char *message) {
uint16_t messageWidth = FONT_12_WIDTH * (strlen(message) + 7); uint16_t messageWidth = FONT_12_WIDTH * (str_display_len(message) + 7);
uint32_t messageStart = xTaskGetTickCount(); uint32_t messageStart = xTaskGetTickCount();
OLED::setFont(0); OLED::setFont(0);
@@ -1144,7 +1168,7 @@ void gui_Menu(const menuitem *menu) {
if (descriptionStart == 0) if (descriptionStart == 0)
descriptionStart = xTaskGetTickCount(); descriptionStart = xTaskGetTickCount();
// lower the value - higher the speed // lower the value - higher the speed
int16_t descriptionWidth = FONT_12_WIDTH * (strlen(menu[currentScreen].description) + 7); int16_t descriptionWidth = FONT_12_WIDTH * (str_display_len(menu[currentScreen].description) + 7);
int16_t descriptionOffset = ((xTaskGetTickCount() - descriptionStart) / (systemSettings.descriptionScrollSpeed == 1 ? (TICKS_100MS / 10) : (TICKS_100MS / 5))); int16_t descriptionOffset = ((xTaskGetTickCount() - descriptionStart) / (systemSettings.descriptionScrollSpeed == 1 ? (TICKS_100MS / 10) : (TICKS_100MS / 5)));
descriptionOffset %= descriptionWidth; // Roll around at the end descriptionOffset %= descriptionWidth; // Roll around at the end
if (lastOffset != descriptionOffset) { if (lastOffset != descriptionOffset) {