commit 961d4ac5f598eb73af4bd26e24129717fcf50396 Author: Kosma Moczek Date: Fri Nov 25 13:57:00 2022 +0100 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..98e1f4a --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# VF60 WiFi Driver + +Minimalistic WiFi driver software for VF60. + +## Connection + +Use the RS-232 port, as documented [here](https://github.com/ggajoch/vf60-vfd-display). +Note that the connector on the display is RS232 voltage levels - to connect an ESP8266 +you have two options: + +1. Use a level shifter like MAX3232. +2. Disassemble the display and remove the internal level shifter, + then connect the ESP8266 directly to the level shifter pads + on the PCB. + +## Configuration + +Change the SSID and password at the beginning of the file. Flash using Arduino IDE. + +## Usage + +* `http:///display?line1=...&line2=...` - sets display content +* `http:///brightness?brightness=0..5` - sets display brightness + +## Language support + +On the HTTP side, use UTF-8. + +On the display side, the text is converted to CP-852 (Polish codepage) +as that's the author's native language. To add support for more languages: + +1. Add and use a function like `UTF8toCP852()` but supporting a different codepage. +2. Add and use a function line `codepage_852()` but switching the display to a different codepage. + To find the correct invocation, use trial and error, trying different values instead of `\x07`. + +Pull requests are welcome to add more language support; I won't do it because I'm lazy. + +## TODO + +- Show the display's IP address upon startup. +- Add more languages. diff --git a/VF60-ESP8266.ino b/VF60-ESP8266.ino new file mode 100644 index 0000000..eaa83e7 --- /dev/null +++ b/VF60-ESP8266.ino @@ -0,0 +1,292 @@ +/* + * VF60 ESP8266 WiFi Driver + */ + +#include +#include +#include + +const char* ssid = "Internet of Shit"; +const char* password = "The S in IoT stands for Security"; + + +// NOTE: The value is not a Unicode codepoint but a byte sequence. +// Generated using https://www.acc.umu.se/~saasha/charsets/?charset=cp852&charset=cp852 +unsigned char UTF8toCP852(uint32_t value) +{ + switch (value) { + case 0xc387: return 0x80; + case 0xc3bc: return 0x81; + case 0xc3a9: return 0x82; + case 0xc3a2: return 0x83; + case 0xc3a4: return 0x84; + case 0xc5af: return 0x85; + case 0xc487: return 0x86; + case 0xc3a7: return 0x87; + case 0xc582: return 0x88; + case 0xc3ab: return 0x89; + case 0xc590: return 0x8a; + case 0xc591: return 0x8b; + case 0xc3ae: return 0x8c; + case 0xc5b9: return 0x8d; + case 0xc384: return 0x8e; + case 0xc486: return 0x8f; + case 0xc389: return 0x90; + case 0xc4b9: return 0x91; + case 0xc4ba: return 0x92; + case 0xc3b4: return 0x93; + case 0xc3b6: return 0x94; + case 0xc4bd: return 0x95; + case 0xc4be: return 0x96; + case 0xc59a: return 0x97; + case 0xc59b: return 0x98; + case 0xc396: return 0x99; + case 0xc39c: return 0x9a; + case 0xc5a4: return 0x9b; + case 0xc5a5: return 0x9c; + case 0xc581: return 0x9d; + case 0xc397: return 0x9e; + case 0xc48d: return 0x9f; + case 0xc3a1: return 0xa0; + case 0xc3ad: return 0xa1; + case 0xc3b3: return 0xa2; + case 0xc3ba: return 0xa3; + case 0xc484: return 0xa4; + case 0xc485: return 0xa5; + case 0xc5bd: return 0xa6; + case 0xc5be: return 0xa7; + case 0xc498: return 0xa8; + case 0xc499: return 0xa9; + case 0xc2ac: return 0xaa; + case 0xc5ba: return 0xab; + case 0xc48c: return 0xac; + case 0xc59f: return 0xad; + case 0xc2ab: return 0xae; + case 0xc2bb: return 0xaf; + case 0xe29691: return 0xb0; + case 0xe29692: return 0xb1; + case 0xe29693: return 0xb2; + case 0xe29482: return 0xb3; + case 0xe294a4: return 0xb4; + case 0xc381: return 0xb5; + case 0xc382: return 0xb6; + case 0xc49a: return 0xb7; + case 0xc59e: return 0xb8; + case 0xe295a3: return 0xb9; + case 0xe29591: return 0xba; + case 0xe29597: return 0xbb; + case 0xe2959d: return 0xbc; + case 0xc5bb: return 0xbd; + case 0xc5bc: return 0xbe; + case 0xe29490: return 0xbf; + case 0xe29494: return 0xc0; + case 0xe294b4: return 0xc1; + case 0xe294ac: return 0xc2; + case 0xe2949c: return 0xc3; + case 0xe29480: return 0xc4; + case 0xe294bc: return 0xc5; + case 0xc482: return 0xc6; + case 0xc483: return 0xc7; + case 0xe2959a: return 0xc8; + case 0xe29594: return 0xc9; + case 0xe295a9: return 0xca; + case 0xe295a6: return 0xcb; + case 0xe295a0: return 0xcc; + case 0xe29590: return 0xcd; + case 0xe295ac: return 0xce; + case 0xc2a4: return 0xcf; + case 0xc491: return 0xd0; + case 0xc490: return 0xd1; + case 0xc48e: return 0xd2; + case 0xc38b: return 0xd3; + case 0xc48f: return 0xd4; + case 0xc587: return 0xd5; + case 0xc38d: return 0xd6; + case 0xc38e: return 0xd7; + case 0xc49b: return 0xd8; + case 0xe29498: return 0xd9; + case 0xe2948c: return 0xda; + case 0xe29688: return 0xdb; + case 0xe29684: return 0xdc; + case 0xc5a2: return 0xdd; + case 0xc5ae: return 0xde; + case 0xe29680: return 0xdf; + case 0xc393: return 0xe0; + case 0xc39f: return 0xe1; + case 0xc394: return 0xe2; + case 0xc583: return 0xe3; + case 0xc584: return 0xe4; + case 0xc588: return 0xe5; + case 0xc5a0: return 0xe6; + case 0xc5a1: return 0xe7; + case 0xc594: return 0xe8; + case 0xc39a: return 0xe9; + case 0xc595: return 0xea; + case 0xc5b0: return 0xeb; + case 0xc3bd: return 0xec; + case 0xc39d: return 0xed; + case 0xc5a3: return 0xee; + case 0xc2b4: return 0xef; + case 0xc2ad: return 0xf0; + case 0xcb9d: return 0xf1; + case 0xcb9b: return 0xf2; + case 0xcb87: return 0xf3; + case 0xcb98: return 0xf4; + case 0xc2a7: return 0xf5; + case 0xc3b7: return 0xf6; + case 0xc2b8: return 0xf7; + case 0xc2b0: return 0xf8; + case 0xc2a8: return 0xf9; + case 0xcb99: return 0xfa; + case 0xc5b1: return 0xfb; + case 0xc598: return 0xfc; + case 0xc599: return 0xfd; + case 0xe296a0: return 0xfe; + case 0xc2a0: return 0xff; + default: return '?'; + } +} + +// Naive UTF8 parser based on: https://www.omarpolo.com/post/parsing-utf8.html +String UTF8toCP852(String s) +{ + unsigned char result[20+1]; + size_t len = 0; + + for (int i=0; i