diff --git a/src/util.h b/src/util.h index 586d0ec..32ab2a1 100644 --- a/src/util.h +++ b/src/util.h @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + // TODO: reverse engineer builtin and custom bitmaps // seems like our sign listens to messages on this address @@ -246,6 +250,78 @@ enum class ExtendedChar { GreekSmallLetterPhi = 0xed, }; +std::unordered_map createUnicodeToCP437Map() { + std::unordered_map cp437_map; + + cp437_map[0x00E4] = 0x84; // ä in UTF-16 + cp437_map[0xC3A4] = 0x84; // ä in UTF-8 + cp437_map[0x00F6] = 0x94; // ö in UTF-16 + cp437_map[0xC3B6] = 0x94; // ö in UTF-8 + cp437_map[0x00FC] = 0x81; // ü in UTF-16 + cp437_map[0xC3BC] = 0x81; // ü in UTF-8 + cp437_map[0x00C4] = 0x8E; // Ä in UTF-16 + cp437_map[0xC384] = 0x8E; // Ä in UTF-8 + cp437_map[0x00D6] = 0x99; // Ö in UTF-16 + cp437_map[0xC396] = 0x99; // Ö in UTF-8 + cp437_map[0x00DC] = 0x9A; // Ü in UTF-16 + cp437_map[0xC39C] = 0x9A; // Ü in UTF-8 + cp437_map[0x00DF] = 0xE1; // ß in UTF-16 + cp437_map[0xC39F] = 0xE1; // ß in UTF-8 + cp437_map[0x20AC] = 0xB1; // € in UTF-16 + cp437_map[0xE282AC] = 0xB1; // € in UTF-8 (3 Bytes) + cp437_map[0x00B5] = 0xE6; // µ in UTF-16 + cp437_map[0xC2B5] = 0xE6; // µ in UTF-8 + + return cp437_map; +} + +String convertToCP437(const String& input) { + std::unordered_map cp437_map = createUnicodeToCP437Map(); + String output = ""; + size_t len = input.length(); + + for (size_t i = 0; i < len; i++) { + char ch = input[i]; + + // UTF-8 detection: check for 3 byte UTF-8 + if ((ch & 0xF0) == 0xE0) { + if (i + 2 < len) { + uint32_t utf8_char = ((uint8_t)input[i] << 16) | ((uint8_t)input[i + 1] << 8) | (uint8_t)input[i + 2]; + i += 2; // skip 2 additional bytes + if (cp437_map.find(utf8_char) != cp437_map.end()) { + output += static_cast(cp437_map[utf8_char]); + continue; + } + } + } + // UTF-8 detection: check for 2 byte UTF-8 + else if ((ch & 0xE0) == 0xC0) { + if (i + 1 < len) { + uint16_t utf8_char = ((uint8_t)input[i] << 8) | (uint8_t)input[i + 1]; + i++; // skip second byte + if (cp437_map.find(utf8_char) != cp437_map.end()) { + output += static_cast(cp437_map[utf8_char]); + continue; + } + } + } + // single UTF-16 character (or plain ANSI character) + else if ((uint8_t)ch < 0x80) { // keep ASCII as is + output += ch; + } + else { + uint16_t utf16_char = (uint8_t)ch; // UTF-16 range + if (cp437_map.find(utf16_char) != cp437_map.end()) { + output += static_cast(cp437_map[utf16_char]); + } else { + output += '?'; + } + } + } + + return output; +} + String hexDump(String in) { String out; for (size_t i = 0; i < in.length(); ++i) { @@ -287,7 +363,6 @@ String hexDump(String in) { * - stay time: 4 * - brightness: bright */ - void sendTextToSign( const String &text, const Method method = Method::Cyclic, @@ -307,7 +382,9 @@ void sendTextToSign( Serial.println("Sending text: \"" + text + "\""); - String toSend = "~" + String(SIGN_ADDRESS, DEC) + "~f01" + (char) method + "\\" + (char) brightness + "\\Y" + String(speed, DEC) + "\\Z" + String(stayTime, DEC) + "\\" + (char) fontType + text + "\r\r\r"; + String translatedText = convertToCP437(text); + + String toSend = "~" + String(SIGN_ADDRESS, DEC) + "~f01" + (char) method + "\\" + (char) brightness + "\\Y" + String(speed, DEC) + "\\Z" + String(stayTime, DEC) + "\\" + (char) fontType + translatedText + "\r\r\r"; Serial1.print(toSend);