#pragma once // TODO: reverse engineer builtin and custom bitmaps // seems like our sign listens to messages on this address // it is also the software's default value static constexpr auto SIGN_ADDRESS = 128; enum class FontType { Font5x6Short = 'q', Font5x11ShortAndWide = 'r', Font7x6Default = 's', Font7x11Wide = 't', Font7x9 = 'u', Font7x17ExtraWide = 'v', FontSmallFont = 'w', }; enum class Brightness { Normal = 'a', Bright = 'b', }; enum class Method { Cyclic = 'A', Immediate = 'B', OpenFromRight = 'C', OpenFromLeft = 'D', OpenFromCenter = 'E', OpenToCenter = 'F', CoverFromCenter = 'G', CoverFromRight = 'H', CoverFromLeft = 'I', CoverToCenter = 'J', ScrollUp = 'K', ScrollDown = 'L', InterlaceToCenter = 'M', InterlaceCover = 'N', CoverUp = 'O', CoverDown = 'P', ScanLine = 'Q', Explode = 'R', PacMan = 'S', FallAndStack = 'T', Shoot = 'U', Flash = 'V', Random = 'W', SlideIn = 'X', }; // macros are literal characters prefixed by ^ enum class Macros { CurrentTime12hWithoutAmPm = 'D', CurrentTime12hWithAmPm = 'E', CurrentTime24h = 'F', CurrentDateMmDdYyyy = 'A', CurrentDateYyyy_Mm_Dd = 'B', CurrentDateMm_Dd_Yyyy = 'C', CurrentDateDd_Mm_Yyyy = 'a', Beep1 = 'q', Beep2 = 'r', Beep3 = 's', Temperature = 'H', }; // symbols should be inserted as string representations of their numeric value prefixed by ^ enum class Symbols { Sun = 66, CloudOrWind = 67, UmbrellaRaining = 68, WallClock = 69, Telephone = 70, Glasses = 71, Faucet = 72, RocketOrSyringeOrSo = 73, WhatTheHell = 74, Key = 75, Shirt = 76, Helicopter = 77, Car = 78, Tank = 79, House = 80, Teapot = 81, Trees = 82, Duck = 83, Scooter = 84, Bicycle = 85, Crown = 86, AppleOrSo = 87, ArrowRight = 88, ArrowLeft = 89, ArrowDownLeft = 90, ArrowUpLeft = 91, Cup = 92, Chair = 93, HighHeel = 94, PrizeCup = 95, }; // cartoons are represented as these characters prefixed by ^ enum class Cartoon { MerryXMas = 'i', HappyNewYear = 'j', FourthOfJuly = 'k', HappyEaster = 'l', HappyHalloween = 'm', DontDrinkAndDrive = 'n', NoSmoking = 'o', Welcome = 'p', }; // the descriptions originate from the UTF-16 specification, https://www.ssec.wisc.edu/~tomw/java/unicode.html // the extended charset starts where ASCII ends enum class ExtendedChar { // Ç LatinCapitalLetterCWithCedilla = 0x80, // ü LatinSmallLetterUWithDiaeresis = 0x81, // é LatinSmallLetterEWithAcute = 0x82, // â LatinSmallLetterAWithCircumflex = 0x83, // ä LatinSmallLetterAWithDiaeresis = 0x84, // á LatinSmallLetterAWithGrave = 0x85, // å LatinSmallLetterAWithRingAbove = 0x86, // ç LatinSmallLetterCWithCedilla = 0x87, // ê LatinSmallLetterEWithCircumflex = 0x88, // ë LatinSmallLetterEWithDiaeresis = 0x89, // è LatinSmallLetterEWithGrave = 0x8a, // Ï LatinCapitalLetterIWithDiaeresis = 0x8b, // Î LatinCapitalLetterIWithCircumflex = 0x8c, // Ì LatinCapitalLetterIWithGrave = 0x8d, // Ä LatinCapitalLetterAWithDiaeresis = 0x8f, // Å LatinCapitalLetterAWithRingAbove = 0x8f, // É LatinCapitalLetterEWithAcute = 0x90, // æ LatinSmallLetterAe = 0x91, // Æ LatinCapitalLetterAe = 0x92, // ô LatinSmallLetterOWithCircumflex = 0x93, // ö LatinSmallLetterOWithDiaeresis = 0x94, // ò LatinSmallLetterOWithGrave = 0x95, // û LatinSmallLetterUWithCircumflex = 0x96, // ù LatinSmallLetterUWithGrave = 0x97, // ÿ LatinSmallLetterYWithDiaeresis = 0x98, // Ö LatinCapitalLLetterOWithDiaeresis = 0x99, // Ü LatinCapitalLetterUWithDiaeresis = 0x9a, // ¢ CentSign = 0x9b, // £ PoundSign = 0x9c, // ¥ YenSign = 0x9d, // urm... UnknownPCurrencySign = 0x9e, // ƒ LatinSmallLetterFWithHook = 0x9f, // á LatinSmallLetterAWithAcute = 0xa0, // Í LatinCapitalLetterIWithAcute = 0xa1, // Ó LatinCapitalLetterOWithAcute = 0xa2, // ú LatinSmallLetterUWithAcute = 0xa3, // ñ LatinSmallLetterNWithTilde = 0xa4, // Ñ LatinCapitalLetterNWithTilde = 0xa5, // a̱ LatinSmallLetterAWithMacronBelow = 0xa6, // couldn't find that one in the UTF-16 table LatinSmallLetterOWithMacronBelow = 0xa7, // ¿ InvertedQuestionMark = 0xa8, // you can probably imagine what it'll look like LatinCapitalLetterZWithRingAbove = 0xa9, // Ź LatinCapitalLetterZWithAcute = 0xaa, // ń LatinSmallLetterNWithAcute = 0xab, // some weird L with a diagonal line AnotherWeirdSign = 0xac, // Ś or ś, can't tell for sure, let's assume capital LatinCapitalLetterSWithAcute = 0xab, // Ć LatinCapitalLetterCWithAcute = 0xac, // ȩ LatinSmallLetterEWithCedilla = 0xad, // well, you can imagine what it'll look like LatinSmallLetterAWithCedilla = 0xb0, // € EuroSign = 0xb1, // E with some vertical line below LatinCapitalLetterEWithSomeLineBelow = 0xb3, // a with some vertical line below LatinSmallLetterAWithSomeWeirdLineBelow = 0xb4, // α GreekSmallLetterAlpha = 0xe0, // β GreekSmallLetterBeta = 0xe1, // Γ GreekCapitalLetterGamma = 0xe2, // π GreekSmallLetterPi = 0xe3, // Σ GreekCapitalLetterSigma = 0xe4, // σ GreekSmallLetterSigma = 0xe5, // μ GreekSmallLetterMu = 0xe6, // τ GreekSmallLetterTau = 0xe7, // Φ GreekCapitalLetterPhi = 0xe8, // θ GreekSmallLetterTheta = 0xe9, // Ω GreekCapitalLetterOmega = 0xea, // δ GreekSmallLetterDelta = 0xeb, // ∞ Infinity = 0xec, // φ GreekSmallLetterPhi = 0xed, }; /* * Message syntax: * separator: ~ * address (int string): 128 * separator: ~ * random string(?): f01 * method (single char) * format string (see below) * end of message: \r\r\r * * the format string contains the message along with control characters that define some of the formatting * note: we have not tested the UTF-8 capabilities, so far only ASCII * it supports multiple lines (yet to be tested) * you can also insert macros (e.g., current time/date), symbols (e.g., a sun) and cartoons * the specials are preceded by a caret following the respective character * then, there is an extended charset that supports a small subset of UTF-16 (yes, that's right, it's not just UTF-8) * it can further contain information that should be used from their occurrence on * the formatting escape sequences are prefixed by a literal backspace following a char that represents the format * brightness is \, speed is Y<1-8>, "stay time" is \Z<1-8>, font type is \[A-X] * new lines are introduced by a single \r, the end of the message is marked by three of them * * default formatting: * - method: cyclic * - font type: 7x6 * - speed: 5 * - stay time: 4 * - brightness: bright */ void sendTextToSign( const String &text, const Method method = Method::Cyclic, const FontType fontType = FontType::Font7x6Default, const int speed = 5, const int stayTime = 4, const Brightness brightness = Brightness::Bright ) { if (speed < 0 || speed > 8) { Serial.println("Invalid speed: " + String(speed, DEC)); return; } if (stayTime < 0 || stayTime > 8) { Serial.println("Invalid stayTime: " + String(stayTime, DEC)); return; } 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"; Serial1.print(toSend); Serial.println("Text sent to device: " + toSend); Serial.print("Hex dump: "); for (size_t i = 0; i < toSend.length(); ++i) { auto hexChar = String(toSend[i], HEX); if (hexChar.length() == 1) { hexChar = '0' + hexChar; } Serial.print(hexChar + ' '); } Serial.println(); }