├── ESP8266_little_game_engine.ino ├── ESP8266_little_game_engine.ino.d1_mini.bin ├── ESPboyLogo.h ├── ESPboyOTA.cpp ├── ESPboyOTA.h ├── LICENSE ├── README.md ├── TFT_eSPI └── User_Setups │ └── Setup24_ESPboy.h ├── WiFiFileUploader.ino ├── acoos.h ├── connect.ino ├── cpu.ino ├── data ├── 0_ButtonsTest.lge ├── 0_LineBenchTest.bin ├── 0_SoundTest.lge ├── 1916.lge ├── Battleships.lge ├── BombChase.lge ├── CommTest.lge ├── ESPtris.lge ├── FourInNarow.lge ├── Highway.lge ├── Microrace.lge ├── SpaceInvad.lge ├── asteroids.lge ├── bash.lge ├── blackjack.lge ├── brainf+ck.lge ├── breackout.bin ├── calculator.lge ├── capman.lge ├── cityrunner.lge ├── columns.lge ├── dwarfsclicker.lge ├── esprogue.lge ├── fishlife.lge ├── flappybird.lge ├── frozenworld.lge ├── galaxies.lge ├── gameoflife.bin ├── hangman.lge ├── marsattack.bin ├── memories.lge ├── microbasic.lge ├── mines.lge ├── minifisherman.lge ├── ninjaescape.lge ├── oldtower.lge ├── olympusmons.lge ├── plagueoutbreak.lge ├── snake.bin ├── spacefighter.lge ├── sudoku.lge ├── tankcity.lge ├── towerdefence.lge ├── twosnakes.lge ├── wormblast.lge └── zombiedefence.lge ├── display.ino ├── esp_little_game_engine_description.pdf ├── esp_little_game_engine_user_guide-2.pdf ├── esp_little_game_engine_user_guide.pdf ├── fileUpload.html ├── file_manager.ino ├── font_a.c ├── keyboard.ino ├── lge_memory.ino ├── lib ├── ESPboyLED.cpp ├── ESPboyLED.h ├── ESPboy_keyboard.cpp └── ESPboy_keyboard.h ├── libraries.7z ├── logo.png ├── rom.h ├── rom.ino ├── settings.h └── sound.ino /ESP8266_little_game_engine.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "ESP8266WiFi.h" 9 | #include "user_interface.h" 10 | #include "settings.h" 11 | #include "acoos.h" 12 | 13 | #ifdef ESPBOY 14 | #include 15 | #include 16 | #include 17 | #include "ESPboyOTA.h" 18 | #include "ESPboyLogo.h" 19 | #include "lib/ESPboy_keyboard.h" 20 | #include "lib/ESPboy_keyboard.cpp" 21 | #include "lib/ESPboyLED.h" 22 | #include "lib/ESPboyLED.cpp" 23 | 24 | keyboardModule keybModule(1,1,7000); 25 | Adafruit_MCP23017 mcp; 26 | Adafruit_MCP4725 dac; 27 | ESPboyLED myled; 28 | ESPboyOTA* OTAobj = NULL; 29 | #endif 30 | 31 | Coos <4, 0> coos; 32 | 33 | // Use hardware SPI 34 | TFT_eSPI tft = TFT_eSPI(); 35 | 36 | uint8_t i2c_adress; 37 | uint8_t thiskey; 38 | uint8_t serial_used = 0; 39 | char c; 40 | Ticker timer; 41 | int delay_rtttl = 50; 42 | uint16_t cadr_count = 0; 43 | unsigned long timeF,timeR; 44 | uint16_t timeCpu = 0,timeGpu = 0,timeSpr = 0,cpuOPS = 0,cpuOPSD = 0; 45 | uint8_t fps, fileIsLoad; 46 | uint8_t timeForRedraw = 48; 47 | uint8_t fixed_res_bit = 8; 48 | volatile uint16_t timers[8]; 49 | 50 | static const uint16_t bpalette[] = { 51 | 0x0020, 0xE718, 0xB9A8, 0x7DB6, 0x61EB, 0x6D2D, 0x21EC, 0xD5CA, 52 | 0xAC4D, 0x42CB, 0xBB09, 0x3186, 0x73AE, 0x8D4B, 0x3DF9, 0xBDD7 53 | }; 54 | uint16_t palette[16] __attribute__ ((aligned)); 55 | uint16_t sprtpalette[16] __attribute__ ((aligned)); 56 | 57 | uint16_t bgr_to_rgb(uint16_t c){ 58 | return ((c & 0x001f) << 11) + ((c & 0xf800) >> 11) + (c & 0x07e0); 59 | } 60 | 61 | void WiFiOff() { 62 | wifi_station_disconnect(); 63 | wifi_set_opmode(NULL_MODE); 64 | wifi_set_sleep_type(MODEM_SLEEP_T); 65 | wifi_fpm_open(); 66 | wifi_fpm_do_sleep(0xFFFFFFF); 67 | WiFi.forceSleepBegin(); 68 | } 69 | 70 | unsigned char hexToByte(char h){ 71 | if(h < 48) 72 | return 48; 73 | if (h >= 48 && h <= 57) 74 | h = map(h, 48, 57, 0, 9); 75 | else if (h >= 65 && h <= 70) 76 | h = map(h, 65, 70, 10, 15); 77 | else if (h >= 97 && h <= 102) 78 | h = map(h, 97, 102, 10, 15); 79 | return h; 80 | } 81 | 82 | void loadFromSerial(){ 83 | char c; 84 | unsigned char n; 85 | int16_t j = 0; 86 | for(int16_t i = 0; i < RAM_SIZE; i++) 87 | writeMem(i, 0); 88 | while(c != '.'){ 89 | if(Serial.available()){ 90 | c = Serial.read(); 91 | Serial.print(c); 92 | if(c == '$'){ 93 | n = 48; 94 | while(n > 15){ 95 | c = Serial.read(); 96 | n = hexToByte(c); 97 | } 98 | Serial.print(c); 99 | writeMem(j, n << 4); 100 | n = 48; 101 | while(n > 15){ 102 | c = Serial.read(); 103 | n = hexToByte(c); 104 | } 105 | Serial.print(c); 106 | writeMem(j, readMem(j) + n); 107 | j++; 108 | } 109 | } 110 | } 111 | Serial.println(F("load ")); 112 | Serial.print(j); 113 | Serial.println(F(" byte")); 114 | Serial.print(F("free heap ")); 115 | Serial.println(system_get_free_heap_size()); 116 | cpuInit(); 117 | } 118 | 119 | void viewEEPROM(){ 120 | for(int16_t i = 0; i < EEPROM_SIZE; i++){ 121 | if(i % 32 == 0) 122 | Serial.println(); 123 | if(EEPROM.read(i) < 0x10) 124 | Serial.print('0'); 125 | Serial.print(EEPROM.read(i), HEX); 126 | Serial.print(' '); 127 | } 128 | } 129 | 130 | void changeSettings(){ 131 | fileIsLoad = false; 132 | if(Serial.available()){ 133 | c = Serial.read(); 134 | Serial.print(c); 135 | if(c == 'm'){ 136 | loadFromSerial(); 137 | fileIsLoad = true; 138 | cpuInit(); 139 | return; 140 | } 141 | else if(c == 'r'){ 142 | ESP.reset(); 143 | return; 144 | } 145 | else if(c == 'd'){ 146 | debug(); 147 | Serial.print(F("kIPS")); 148 | Serial.println(cpuOPSD, DEC); 149 | return; 150 | } 151 | else if(c == 'e'){ 152 | viewEEPROM(); 153 | } 154 | else if(c == 'v'){ 155 | Serial.println(); 156 | Serial.println(F("input new resolution")); 157 | int w = 0; 158 | int h = 0; 159 | while(Serial.available() == 0){} 160 | c = Serial.read(); 161 | if(c <= 47 || c > 57){ 162 | while(Serial.available() == 0){} 163 | c = Serial.read(); 164 | } 165 | while(c > 47 && c <= 57){ 166 | w = w * 10 + (c - 48); 167 | while(Serial.available() == 0){} 168 | c = Serial.read(); 169 | } 170 | Serial.print(w); 171 | Serial.print(' '); 172 | while(Serial.available() == 0){} 173 | c = Serial.read(); 174 | while(c > 47 && c <= 57){ 175 | h = h * 10 + (c - 48); 176 | while(Serial.available() == 0){} 177 | c = Serial.read(); 178 | } 179 | Serial.println(h); 180 | setScreenResolution(w, h); 181 | return; 182 | } 183 | } 184 | } 185 | 186 | void coos_cpu(void){ 187 | while(1){ 188 | COOS_DELAY(0); // 1 ms 189 | timeR = millis(); 190 | cpuOPS += 1; 191 | cpuRun(1000); 192 | timeCpu += millis() - timeR; 193 | if(delay_rtttl <= 0) 194 | delay_rtttl = playRtttl(); 195 | } 196 | } 197 | 198 | void coos_screen(void){ 199 | while(1){ 200 | yield(); 201 | COOS_DELAY(timeForRedraw); 202 | timeR = millis(); 203 | clearSpriteScr(); 204 | redrawSprites(); 205 | moveSprites(); 206 | testSpriteCollision(); 207 | redrawParticles(); 208 | timeSpr += millis() - timeR; 209 | timeR = millis(); 210 | redrawScreen(); 211 | setRedraw(); 212 | timeGpu += millis() - timeR; 213 | cadr_count++; 214 | if(millis() - timeF > 1000){ 215 | timeF = millis(); 216 | fps = cadr_count; 217 | cadr_count = cadr_count % 2; 218 | } 219 | } 220 | } 221 | 222 | void ICACHE_RAM_ATTR timer_tick(void){ 223 | for(int16_t i = 0; i < 8; i++){ 224 | if(timers[i] >= 1) 225 | timers[i] --; 226 | } 227 | delay_rtttl--; 228 | updateRtttl(); 229 | } 230 | 231 | void coos_key(void){ 232 | while(1){ 233 | COOS_DELAY(100); // 100 ms 234 | getKey(); 235 | if(thiskey == 192) //key select + start 236 | pause(); 237 | if(!serial_used) 238 | changeSettings(); 239 | } 240 | } 241 | 242 | void coos_info(void){ 243 | while(1){ 244 | COOS_DELAY(1000); // 1000 ms 245 | #ifdef DEBUG_ON_SCREEN 246 | if(getDisplayXOffset() > 30){ 247 | tft.fillRect(0, 0, 30, 92, 0x0000); 248 | tft.setCursor(1, 0); 249 | tft.println("fps"); 250 | tft.println(fps); 251 | tft.println("cpu"); 252 | tft.println(timeCpu, DEC); 253 | tft.println("gpu"); 254 | tft.println(timeGpu, DEC); 255 | tft.println("spr"); 256 | tft.println(timeSpr, DEC); 257 | tft.println("kIPS"); 258 | tft.println(cpuOPS, DEC); 259 | } 260 | #endif 261 | timeCpu = 0; 262 | timeGpu = 0; 263 | timeSpr = 0; 264 | cpuOPSD = cpuOPS; 265 | cpuOPS = 0; 266 | } 267 | } 268 | 269 | void setup() { 270 | delay(1); 271 | system_update_cpu_freq(FREQUENCY); 272 | Serial.begin(115200); 273 | EEPROM.begin(EEPROM_SIZE); 274 | Serial.println(); 275 | Serial.print(F("version ")); 276 | Serial.print(F(BUILD_VERSION_MAJOR)); 277 | Serial.print('.'); 278 | Serial.print(F(BUILD_VERSION_MINOR)); 279 | Serial.print(F(" build ")); 280 | Serial.print(F(__DATE__)); 281 | randomSeed(RANDOM_REG32); 282 | #ifdef ESPBOY 283 | Serial.println(); 284 | Serial.println(F("ESPboy")); 285 | scani2c(); 286 | //DAC init 287 | dac.begin(MCP4725address); 288 | delay(100); 289 | dac.setVoltage(0, true); 290 | //buttons on mcp23017 init 291 | mcp.begin(MCP23017address); 292 | delay (100); 293 | for(int i = 0; i < 8; i++){ 294 | mcp.pinMode(i, INPUT); 295 | mcp.pullUp(i, HIGH); 296 | } 297 | myled.begin(&mcp); 298 | myled.setRGB(0, 0, 0); 299 | delay(50); 300 | if (keybModule.begin()) 301 | Serial.println(F("\nESPboy keyboard module found")); 302 | //initialize LCD 303 | mcp.pinMode(csTFTMCP23017pin, OUTPUT); 304 | mcp.digitalWrite(csTFTMCP23017pin, LOW); 305 | tft.begin(); 306 | delay(100); 307 | tft.setRotation(0); 308 | tft.fillScreen(0x0000); 309 | tft.setTextSize(1); 310 | tft.drawXBitmap(30, 24, ESPboyLogo, 68, 64, 0xFFE0); 311 | tft.setTextColor(0xFFE0); 312 | tft.setCursor(10,102); 313 | tft.print(F("Little game engine")); 314 | tft.setTextColor(TFT_DARKGREY); 315 | tft.setCursor(10,120); 316 | tft.print(F(BUILD_VERSION_MAJOR)); 317 | tft.print('.'); 318 | tft.print(F(BUILD_VERSION_MINOR)); 319 | tft.print(' '); 320 | tft.print(F(__DATE__)); 321 | //sound init and test 322 | pinMode(SOUNDPIN, OUTPUT); 323 | tone(SOUNDPIN, 200, 100); 324 | delay(100); 325 | tone(SOUNDPIN, 100, 100); 326 | delay(100); 327 | noTone(SOUNDPIN); 328 | //LCD backlit on 329 | for (int count = 0; count < 1000; count += 50){ 330 | dac.setVoltage(count, false); 331 | delay(50); 332 | } 333 | dac.setVoltage(4095, true); 334 | delay(1000); 335 | getKey(); 336 | //go to OTA 337 | if(thiskey & 32 || thiskey & 16){//key AB 338 | OTAobj = new ESPboyOTA(&tft, &mcp); 339 | } 340 | #else 341 | Wire.begin(D2, D1); 342 | geti2cAdress(); 343 | tft.init(); // initialize LCD 344 | tft.setRotation(1); 345 | #endif 346 | tft.fillScreen(0x0000); 347 | 348 | //Initialize File System 349 | LittleFSConfig cfg; 350 | cfg.setAutoFormat(false); 351 | LittleFS.setConfig(cfg); 352 | tft.setTextColor(TFT_GREEN); 353 | if(LittleFS.begin()){ 354 | Serial.println(F("LittleFS Initialize....ok")); 355 | } 356 | else{ 357 | tft.print(F("LittleFS init FAILED")); 358 | tft.setCursor(2, 10); 359 | tft.print(F("LittleFS FORMATING...")); 360 | Serial.println(F("LittleFS init FAILED. Formatting...")); 361 | if(LittleFS.format()){ 362 | Serial.println(F("Formatting DONE")); 363 | tft.setCursor(2, 18); 364 | tft.print(F("Formatting DONE!")); 365 | LittleFS.begin(); 366 | delay(2000); 367 | } 368 | else { 369 | Serial.println(F("Formatting FAILED")); 370 | tft.setCursor(2, 18); 371 | tft.print(F("Formatting FAILED")); 372 | delay(2000); 373 | } 374 | } 375 | // turn off ESP8266 RF 376 | WiFiOff(); 377 | delay(1); 378 | memoryAlloc(); 379 | loadSplashscreen(); 380 | cpuInit(); 381 | Serial.print(F("FreeHeap:")); 382 | Serial.println(ESP.getFreeHeap()); 383 | Serial.println(F("print \"vW H\" for change viewport, \"d name\" for delite file,")); 384 | Serial.println(F("\"s name\" for save file and \"m\" for load to memory")); 385 | #ifdef ESPBOY 386 | setScreenResolution(128, 128); 387 | #else 388 | setScreenResolution(min(SCREEN_REAL_WIDTH, SCREEN_REAL_HEIGHT) - 1, min(SCREEN_REAL_WIDTH, SCREEN_REAL_HEIGHT) - 1); 389 | #endif 390 | clearScr(0); 391 | setColor(1); 392 | randomSeed(analogRead(0)); 393 | timer.attach(0.001, timer_tick); 394 | coos.register_task(coos_cpu); 395 | coos.register_task(coos_screen); 396 | coos.register_task(coos_key); 397 | coos.register_task(coos_info); 398 | coos.start(); // init registered tasks 399 | } 400 | 401 | void loop() { 402 | coos.run(); // Coos scheduler 403 | } 404 | -------------------------------------------------------------------------------- /ESP8266_little_game_engine.ino.d1_mini.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/ESP8266_little_game_engine.ino.d1_mini.bin -------------------------------------------------------------------------------- /ESPboyLogo.h: -------------------------------------------------------------------------------- 1 | const uint8_t ESPboyLogo[] PROGMEM = { 2 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 3 | 0x01, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0xFC, 4 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x83, 0x1F, 0xFC, 0x00, 0x00, 0x00, 5 | 0x00, 0x00, 0xD0, 0xC3, 0x3F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 6 | 0xE3, 0x7F, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE1, 0x7F, 0x78, 7 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x00, 0x00, 8 | 0x00, 0x00, 0x00, 0xA0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 9 | 0xA0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7F, 0x00, 10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x41, 0x3E, 0x78, 0x00, 0x00, 0x00, 11 | 0x00, 0x00, 0xF0, 0x83, 0x1F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 12 | 0x03, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x03, 0x00, 0xF4, 13 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x03, 0x0F, 0xEC, 0x00, 0x00, 0x00, 14 | 0x00, 0x00, 0xE0, 0x81, 0x1F, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 15 | 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x00, 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1D, 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0xE0, 0x01, 0x0F, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 18 | 0x03, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0xFC, 19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x03, 0x0F, 0xF4, 0x00, 0x00, 0x00, 20 | 0x00, 0x00, 0xB0, 0x83, 0x1F, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 21 | 0x81, 0x1F, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1D, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0x1E, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x0F, 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x0F, 0x00, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x3D, 0x40, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x3B, 0xC0, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x80, 0x07, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x00, 0x00, 0x80, 0x07, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 33 | 0x0F, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x7E, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0F, 0x00, 0x7A, 0x00, 0x00, 0x00, 35 | 0x00, 0x00, 0xC0, 0x0E, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 36 | 0x07, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 38 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFF, 0xFF, 39 | 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0xE0, 0xE7, 0xF7, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF7, 42 | 0xF7, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x30, 0x30, 0xF6, 0xF1, 43 | 0xCC, 0x00, 0x00, 0x00, 0xE0, 0xF3, 0x31, 0xF6, 0xFB, 0xCD, 0x00, 0x00, 44 | 0x00, 0xE0, 0xE3, 0xF3, 0x37, 0x9B, 0xCD, 0x00, 0x00, 0x00, 0xE0, 0xC0, 45 | 0xF7, 0x33, 0x9B, 0xCD, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x36, 0x30, 0x9B, 46 | 0xCD, 0x00, 0x00, 0x00, 0xE0, 0xF7, 0x37, 0xF0, 0xFB, 0xFD, 0x00, 0x00, 47 | 0x00, 0xE0, 0xF7, 0x33, 0xF0, 0xF1, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 50 | }; 51 | -------------------------------------------------------------------------------- /ESPboyOTA.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ESPboyOTA class -- ESPboy App Store client core 3 | for www.ESPboy.com project by RomanS 4 | https://hackaday.io/project/164830-espboy-games-iot-stem-for-education-fun 5 | thanks to DmitryL (Plague) for help, tests and advices 6 | */ 7 | 8 | #include "ESPboyOTA.h" 9 | #define SOUNDPIN D3 10 | 11 | const uint8_t ESPboyOTA::keybOnscr[2][3][21] PROGMEM = { 12 | {"+1234567890abcdefghi", "jklmnopqrstuvwxyz -=", "?!@$%&*()_[]\":;.,^ -1) keybParam.selX--; 56 | if ((keyState & OTA_PAD_DOWN) && keybParam.selY < 3) keybParam.selY++; 57 | if ((keyState & OTA_PAD_UP) && keybParam.selY > -1) keybParam.selY--; 58 | if ((keyState & OTA_PAD_LEFT) && keybParam.selX == -1) keybParam.selX = 19; 59 | if ((keyState & OTA_PAD_RIGHT) && keybParam.selX == 20) keybParam.selX = 0; 60 | if ((keyState & OTA_PAD_UP) && keybParam.selY == -1) keybParam.selY = 2; 61 | if ((keyState & OTA_PAD_DOWN) && keybParam.selY == 3) keybParam.selY = 0; 62 | } 63 | 64 | if ((keyState & OTA_PAD_ACT && keyState & OTA_PAD_ESC) || 65 | (keyState & OTA_PAD_RGT && keyState & OTA_PAD_LFT)) { 66 | if (keybParam.renderLine > OTA_MAX_CONSOLE_STRINGS - OTA_MAX_STRINGS_ONSCREEN_FULL) 67 | keybParam.renderLine = OTA_MAX_CONSOLE_STRINGS - OTA_MAX_STRINGS_ONSCREEN_FULL; 68 | toggleDisplayMode(1); 69 | waitKeyUnpressed(); 70 | } else if (keyState & OTA_PAD_RGT && keybParam.renderLine) { 71 | keybParam.renderLine--; 72 | drawConsole(0); 73 | } else if (keyState & OTA_PAD_LFT && 74 | keybParam.renderLine < 75 | OTA_MAX_CONSOLE_STRINGS - OTA_MAX_STRINGS_ONSCREEN_SMALL) { 76 | keybParam.renderLine++; 77 | drawConsole(0); 78 | } 79 | 80 | if ((((keyState & OTA_PAD_ACT) && (keybParam.selX == 19 && keybParam.selY == 2)) || (keyState & OTA_PAD_RGT && keyState & OTA_PAD_LFT))) { // enter 81 | if (keybParam.typing.length() > 0) longActPress = 1; 82 | } else if ((keyState & OTA_PAD_ACT) && (keybParam.selX == 18 && keybParam.selY == 2)) { // back space 83 | if (keybParam.typing.length() > 0) keybParam.typing.remove(keybParam.typing.length() - 1); 84 | } else if ((keyState & OTA_PAD_ACT) && (keybParam.selX == 17 && keybParam.selY == 1)) { // SPACE 85 | if (keybParam.typing.length() < OTA_MAX_TYPING_CHARS) keybParam.typing += " "; 86 | } else if ((keyState & OTA_PAD_ACT) && (keybParam.selX == 17 && keybParam.selY == 2)) { 87 | keybParam.shiftOn = !keybParam.shiftOn; 88 | drawKeyboard(keybParam.selX, keybParam.selY, 0); 89 | waitKeyUnpressed(); 90 | } else if (keyState & OTA_PAD_ACT){ 91 | if (waitKeyUnpressed() > OTA_KEY_PRESSED_DELAY_TO_SEND) 92 | longActPress = 1; 93 | else if (keybParam.typing.length() < OTA_MAX_TYPING_CHARS) 94 | keybParam.typing += (char)pgm_read_byte(&keybOnscr[keybParam.shiftOn][keybParam.selY][keybParam.selX]); 95 | } 96 | 97 | if (keyState & OTA_PAD_ESC) { 98 | if (waitKeyUnpressed() > OTA_KEY_PRESSED_DELAY_TO_SEND) 99 | keybParam.typing = ""; 100 | else if (keybParam.typing.length() > 0) 101 | keybParam.typing.remove(keybParam.typing.length() - 1); 102 | } 103 | } 104 | 105 | else { 106 | if ((keyState & OTA_PAD_ACT && keyState & OTA_PAD_ESC) || 107 | (keyState & OTA_PAD_RGT && keyState & OTA_PAD_LFT)) { 108 | toggleDisplayMode(0); 109 | waitKeyUnpressed(); 110 | } else 111 | 112 | if (((keyState & OTA_PAD_RGT || keyState & OTA_PAD_RIGHT || 113 | keyState & OTA_PAD_DOWN)) && 114 | keybParam.renderLine > 0) { 115 | keybParam.renderLine--; 116 | drawConsole(0); 117 | } else 118 | 119 | if (((keyState & OTA_PAD_LFT || keyState & OTA_PAD_LEFT || 120 | keyState & OTA_PAD_UP)) && 121 | keybParam.renderLine < OTA_MAX_CONSOLE_STRINGS - OTA_MAX_STRINGS_ONSCREEN_FULL) { 122 | keybParam.renderLine++; 123 | drawConsole(0); 124 | } else 125 | 126 | if (keyState & OTA_PAD_ESC) 127 | toggleDisplayMode(0); 128 | } 129 | if (!keybParam.displayMode) drawKeyboard(keybParam.selX, keybParam.selY, 1); 130 | } 131 | 132 | if (!keybParam.displayMode) drawBlinkingCursor(); 133 | return (longActPress); 134 | } 135 | 136 | void ESPboyOTA::toggleDisplayMode(uint8_t mode) { 137 | keybParam.displayMode = mode; 138 | tft->fillScreen(TFT_BLACK); 139 | tft->drawRect(0, 0, 128, 128, TFT_NAVY); 140 | if (!keybParam.displayMode) { 141 | tft->drawRect(0, 128 - 3 * 8 - 5, 128, 3 * 8 + 5, TFT_NAVY); 142 | tft->drawRect(0, 0, 128, 10 * 8 + 5, TFT_NAVY); 143 | } 144 | if (!keybParam.displayMode) { 145 | drawKeyboard(keybParam.selX, keybParam.selY, 0); 146 | } 147 | drawConsole(0); 148 | } 149 | 150 | String ESPboyOTA::getUserInput() { 151 | String userInput; 152 | toggleDisplayMode(0); 153 | while (1) { 154 | while (!keysAction()) delay(OTA_KEYB_CALL_DELAY); 155 | if (keybParam.typing != "") break; 156 | } 157 | toggleDisplayMode(1); 158 | userInput = keybParam.typing; 159 | keybParam.typing = ""; 160 | return (userInput); 161 | } 162 | 163 | void ESPboyOTA::printConsole(String bfrstr, uint16_t color, uint8_t ln, uint8_t noAddLine) { 164 | String toprint; 165 | 166 | keybParam.renderLine = 0; 167 | 168 | if (!ln) 169 | if (bfrstr.length() > 20) { 170 | bfrstr = bfrstr.substring(0, 20); 171 | toprint = bfrstr; 172 | } 173 | 174 | for (uint8_t i = 0; i <= (bfrstr.length() / 21); i++) { 175 | toprint = bfrstr.substring(i * 20); 176 | toprint = toprint.substring(0, 20); 177 | 178 | if (!noAddLine) { 179 | for (uint8_t j = 0; j < OTA_MAX_CONSOLE_STRINGS; j++) { 180 | consoleStrings[j] = consoleStrings[j + 1]; 181 | consoleStringsColor[j] = consoleStringsColor[j + 1]; 182 | } 183 | } 184 | 185 | consoleStrings[OTA_MAX_CONSOLE_STRINGS] = toprint; 186 | consoleStringsColor[OTA_MAX_CONSOLE_STRINGS] = color; 187 | } 188 | drawConsole(noAddLine); 189 | } 190 | 191 | void ESPboyOTA::drawConsole(uint8_t onlyLastLine) { 192 | uint8_t lines; 193 | 194 | if (keybParam.displayMode) 195 | lines = OTA_MAX_STRINGS_ONSCREEN_FULL; 196 | else 197 | lines = OTA_MAX_STRINGS_ONSCREEN_SMALL; 198 | 199 | if (!onlyLastLine) 200 | tft->fillRect(1, 1, 126, lines * 8 + 3, TFT_BLACK); 201 | else 202 | tft->fillRect(1, (lines - 1) * 8 + 3, 126, 8, TFT_BLACK); 203 | 204 | uint8_t offsetY = 3; 205 | if (!onlyLastLine) { 206 | for (uint8_t i = OTA_MAX_CONSOLE_STRINGS - lines - keybParam.renderLine + 1; 207 | i < OTA_MAX_CONSOLE_STRINGS - keybParam.renderLine + 1; i++) { 208 | tft->setTextColor(consoleStringsColor[i], TFT_BLACK); 209 | tft->drawString(consoleStrings[i], 4, offsetY); 210 | offsetY += 8; 211 | } 212 | } else { 213 | tft->setTextColor(consoleStringsColor[OTA_MAX_CONSOLE_STRINGS], TFT_BLACK); 214 | tft->drawString(consoleStrings[OTA_MAX_CONSOLE_STRINGS], 4, 8 * (lines - 1) + 3); 215 | } 216 | } 217 | 218 | uint8_t ESPboyOTA::getKeys() { return (~mcp->readGPIOAB() & 255); } 219 | 220 | uint32_t ESPboyOTA::waitKeyUnpressed() { 221 | uint32_t timerStamp = millis(); 222 | while (getKeys() && (millis() - timerStamp) < OTA_KEY_UNPRESSED_TIMEOUT) delay(1); 223 | return (millis() - timerStamp); 224 | } 225 | 226 | void ESPboyOTA::drawKeyboard(uint8_t slX, uint8_t slY, uint8_t onlySelected) { 227 | static char chr[2]={0,0}; 228 | static uint8_t prevX = 0, prevY = 0; 229 | 230 | if (!onlySelected) { 231 | tft->fillRect(1, 128 - 24, 126, 23, TFT_BLACK); 232 | tft->setTextColor(TFT_YELLOW, TFT_BLACK); 233 | for (uint8_t j = 0; j < 3; j++) 234 | for (uint8_t i = 0; i < 20; i++) { 235 | chr[0] = pgm_read_byte(&keybOnscr[keybParam.shiftOn][j][i]); 236 | tft->drawString(&chr[0], i * 6 + 4, 128 - 2 - 8 * (3 - j)); 237 | } 238 | } 239 | 240 | tft->setTextColor(TFT_YELLOW, TFT_BLACK); 241 | chr[0] = pgm_read_byte(&keybOnscr[keybParam.shiftOn][prevY][prevX]); 242 | tft->drawString(&chr[0], prevX * 6 + 4, 128 - 24 + prevY * 8 - 2); 243 | 244 | tft->setTextColor(TFT_WHITE, TFT_BLACK); 245 | tft->drawString("^setTextColor(TFT_YELLOW, TFT_RED); 248 | chr[0] = pgm_read_byte(&keybOnscr[keybParam.shiftOn][slY][slX]); 249 | tft->drawString(&chr[0], slX * 6 + 4, 128 - 24 + slY * 8 - 2); 250 | 251 | prevX = slX; 252 | prevY = slY; 253 | 254 | drawTyping(0); 255 | } 256 | 257 | void ESPboyOTA::drawTyping(uint8_t changeCursor) { 258 | static char cursorType[2] = {220, '_'}; 259 | static uint8_t cursorTypeFlag=0; 260 | 261 | if(changeCursor) cursorTypeFlag=!cursorTypeFlag; 262 | tft->fillRect(1, 128 - 5 * 8, 126, 10, TFT_BLACK); 263 | if (keybParam.typing.length() < 20) { 264 | tft->setTextColor(TFT_WHITE, TFT_BLACK); 265 | tft->drawString(keybParam.typing + cursorType[cursorTypeFlag], 4, 128 - 5 * 8 + 1); 266 | } else { 267 | tft->setTextColor(TFT_WHITE, TFT_BLACK); 268 | tft->drawString("<" + keybParam.typing.substring(keybParam.typing.length() - 18) +cursorType[cursorTypeFlag], 4, 128 - 5 * 8 + 1); 269 | } 270 | } 271 | 272 | void ESPboyOTA::drawBlinkingCursor() { 273 | static uint32_t cursorBlinkMillis = 0; 274 | if (millis() > (cursorBlinkMillis + OTA_CURSOR_BLINKING_PERIOD)) { 275 | cursorBlinkMillis = millis(); 276 | drawTyping(1); 277 | } 278 | } 279 | 280 | uint16_t ESPboyOTA::scanWiFi() { 281 | printConsole(F("Scaning WiFi...\n"), TFT_MAGENTA, 1, 0); 282 | int16_t WifiQuantity = WiFi.scanNetworks(); 283 | if (WifiQuantity != -1 && WifiQuantity != -2 && WifiQuantity != 0) { 284 | for (uint8_t i = 0; i < WifiQuantity; i++) wfList.push_back(wf()); 285 | if (!WifiQuantity) { 286 | printConsole(F("WiFi not found"), TFT_RED, 1, 0); 287 | delay(3000); 288 | ESP.reset(); 289 | } else 290 | for (uint8_t i = 0; i < wfList.size(); i++) { 291 | wfList[i].ssid = WiFi.SSID(i); 292 | wfList[i].rssi = WiFi.RSSI(i); 293 | wfList[i].encription = WiFi.encryptionType(i); 294 | } 295 | sort(wfList.begin(), wfList.end(), lessRssi()); 296 | return (WifiQuantity); 297 | } else 298 | return (0); 299 | } 300 | 301 | String ESPboyOTA::getWiFiStatusName() { 302 | String stat; 303 | switch (WiFi.status()) { 304 | case WL_IDLE_STATUS: 305 | stat = (F("Idle")); 306 | break; 307 | case WL_NO_SSID_AVAIL: 308 | stat = (F("No SSID available")); 309 | break; 310 | case WL_SCAN_COMPLETED: 311 | stat = (F("Scan completed")); 312 | break; 313 | case WL_CONNECTED: 314 | stat = (F("WiFi connected")); 315 | break; 316 | case WL_CONNECT_FAILED: 317 | stat = (F("Wrong passphrase")); 318 | break; 319 | case WL_CONNECTION_LOST: 320 | stat = (F("Connection lost")); 321 | break; 322 | case WL_DISCONNECTED: 323 | stat = (F("Wrong password")); 324 | break; 325 | default: 326 | stat = (F("Unknown")); 327 | break; 328 | }; 329 | return stat; 330 | } 331 | 332 | boolean ESPboyOTA::connectWifi() { 333 | uint16_t wifiNo = 0; 334 | uint32_t timeOutTimer; 335 | 336 | if (wificl.ssid == "1" && wificl.pass == "1" && !(getKeys()&OTA_PAD_ESC)) { 337 | wificl.ssid = WiFi.SSID(); 338 | wificl.pass = WiFi.psk(); 339 | printConsole(F("Last network:"), TFT_MAGENTA, 0, 0); 340 | printConsole(wificl.ssid, TFT_MAGENTA, 0, 0); 341 | } else { 342 | if (scanWiFi()) 343 | for (uint8_t i = wfList.size(); i > 0; i--) { 344 | String toPrint = 345 | (String)(i) + " " + wfList[i - 1].ssid + " [" + wfList[i - 1].rssi + 346 | "]" + ((wfList[i - 1].encription == ENC_TYPE_NONE) ? "" : "*"); 347 | printConsole(toPrint, TFT_GREEN, 0, 0); 348 | } 349 | 350 | while (!wifiNo) { 351 | printConsole(F("Choose WiFi No:"), TFT_MAGENTA, 0, 0); 352 | wifiNo = getUserInput().toInt(); 353 | if (wifiNo < 1 || wifiNo > wfList.size()) wifiNo = 0; 354 | } 355 | 356 | wificl.ssid = wfList[wifiNo - 1].ssid; 357 | printConsole(wificl.ssid, TFT_YELLOW, 1, 0); 358 | 359 | while (!wificl.pass.length()) { 360 | printConsole(F("Password:"), TFT_MAGENTA, 0, 0); 361 | wificl.pass = getUserInput(); 362 | } 363 | printConsole(/*pass*/F("******"), TFT_YELLOW, 0, 0); 364 | } 365 | 366 | wfList.clear(); 367 | 368 | WiFi.mode(WIFI_STA); 369 | WiFi.begin(wificl.ssid, wificl.pass); 370 | 371 | printConsole(F("Connection..."), TFT_MAGENTA, 0, 0); 372 | timeOutTimer = millis(); 373 | String dots = ""; 374 | while (WiFi.status() != WL_CONNECTED && 375 | (millis() - timeOutTimer < OTA_TIMEOUT_CONNECTION)) { 376 | delay(700); 377 | printConsole(dots, TFT_MAGENTA, 0, 1); 378 | dots += "."; 379 | } 380 | 381 | if (WiFi.status() != WL_CONNECTED) { 382 | wificl.ssid = ""; 383 | wificl.pass = ""; 384 | printConsole(getWiFiStatusName(), TFT_RED, 0, 1); 385 | return (false); 386 | } else { 387 | // Serial.println(WiFi.localIP()); 388 | printConsole(getWiFiStatusName(), TFT_MAGENTA, 0, 1); 389 | return (true); 390 | } 391 | } 392 | 393 | void ESPboyOTA::OTAstarted() { 394 | printConsole(F("Starting download..."), TFT_MAGENTA, 0, 0); 395 | printConsole("", TFT_MAGENTA, 0, 0); 396 | } 397 | 398 | void ESPboyOTA::OTAfinished() { 399 | printConsole(F("Downloading OK"), TFT_GREEN, 0, 0); 400 | printConsole(F("Restarting..."), TFT_MAGENTA, 0, 0); 401 | printConsole(F("And then reset it again by yourself"), TFT_MAGENTA, 1, 0); 402 | ESP.reset(); 403 | } 404 | 405 | void ESPboyOTA::OTAprogress(int cur, int total) { 406 | printConsole((String)(cur * 100 / total) + "%", TFT_GREEN, 0, 1); 407 | } 408 | 409 | void ESPboyOTA::OTAerror(int err) { 410 | // Serial.print(F("Error: ")); Serial.print(err); 411 | printConsole("Error: "+String(err), TFT_RED, 1, 0); 412 | printConsole(ESPhttpUpdate.getLastErrorString(), TFT_RED, 1, 0); 413 | delay(3000); 414 | ESP.reset(); 415 | } 416 | 417 | void ESPboyOTA::updateOTA(String otaLink) { 418 | BearSSL::WiFiClientSecure updateClient; 419 | updateClient.setInsecure(); 420 | // ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW); 421 | ESPhttpUpdate.onStart([this](){this->OTAstarted();}); 422 | ESPhttpUpdate.onEnd([this](){this->OTAfinished();}); 423 | ESPhttpUpdate.onProgress([this](int a, int b){this->OTAprogress(a,b);}); 424 | ESPhttpUpdate.onError([this](int a){this->OTAerror(a);}); 425 | ESPhttpUpdate.update(updateClient, otaLink); 426 | } 427 | 428 | String ESPboyOTA::fillPayload(String downloadID, String downloadName) { 429 | String payload = "{\"values\": \""; 430 | payload += "0"; // session 431 | payload += ", "; // date/time 432 | payload += ", " + WiFi.localIP().toString(); 433 | payload += ", " + downloadID; // download ID 434 | payload += ", " + downloadName; // download name 435 | payload += ", " + (String)ESP.getFreeHeap(); 436 | payload += ", " + (String)ESP.getFreeContStack(); 437 | payload += ", " + (String)ESP.getChipId(); 438 | payload += ", " + (String)ESP.getFlashChipId(); 439 | payload += ", " + (String)ESP.getCoreVersion(); 440 | payload += ", " + (String)ESP.getSdkVersion(); 441 | payload += ", " + (String)ESP.getCpuFreqMHz(); 442 | payload += ", " + (String)ESP.getSketchSize(); 443 | payload += ", " + (String)ESP.getFreeSketchSpace(); 444 | payload += ", " + (String)ESP.getSketchMD5(); 445 | payload += ", " + (String)ESP.getFlashChipSize(); 446 | payload += ", " + (String)ESP.getFlashChipRealSize(); 447 | payload += ", " + (String)ESP.getFlashChipSpeed(); 448 | payload += ", " + (String)ESP.getCycleCount(); 449 | payload += ", " + WiFi.SSID(); 450 | payload += "\"}"; 451 | 452 | return (payload); 453 | } 454 | 455 | void ESPboyOTA::postLog(String downloadID, String downloadName) { 456 | wificl.clientD = new HTTPSRedirect(httpsPort); 457 | wificl.clientD->setInsecure(); 458 | wificl.clientD->setPrintResponseBody(false); 459 | wificl.clientD->setContentTypeHeader("application/json"); 460 | wificl.clientD->setPrintResponseBody(true); 461 | 462 | int connectionAttempts = 0; 463 | while (wificl.clientD->connect(hostD, httpsPort) != 1 && connectionAttempts++ < 5) 464 | ; 465 | if (connectionAttempts > 4) { 466 | printConsole(F("Server failed"), TFT_RED, 0, 0); 467 | delay(5000); 468 | ESP.reset(); 469 | } 470 | 471 | printConsole(F("Server OK"), TFT_MAGENTA, 0, 0); 472 | String payload = fillPayload(downloadID, downloadName); 473 | // Serial.println(payload); 474 | wificl.clientD->POST(urlPost, hostD, payload, false); 475 | // Serial.println(wificl.clientD->getResponseBody()); 476 | 477 | wificl.clientD->stop(); 478 | delete wificl.clientD; 479 | } 480 | 481 | firmware ESPboyOTA::getFirmware() { 482 | uint16_t firmwareNo; 483 | String readedData = ""; 484 | firmware fmw; 485 | 486 | wificl.clientD = new HTTPSRedirect(httpsPort); 487 | wificl.clientD->setInsecure(); 488 | wificl.clientD->setPrintResponseBody(false); 489 | 490 | int connectionAttempts = 0; 491 | while (wificl.clientD->connect(hostD, httpsPort) != 1 && connectionAttempts++ < 5) 492 | ; 493 | if (connectionAttempts > 4) { 494 | printConsole(F("Server faild"), TFT_RED, 0, 0); 495 | delay(5000); 496 | ESP.reset(); 497 | } 498 | 499 | printConsole(F("Loading Apps..."), TFT_MAGENTA, 0, 0); 500 | 501 | if (wificl.clientD->GET((String)urlPost + F("?read"), hostD)) { 502 | readedData = wificl.clientD->getResponseBody(); 503 | 504 | uint16_t countVector = 0; 505 | char* prs = strtok((char*)readedData.c_str(), ";\n"); 506 | while (prs != NULL) { 507 | fwList.push_back(fw()); 508 | fwList[countVector].fwName = prs; 509 | prs = strtok(NULL, ";\n"); 510 | fwList[countVector].fwLink = prs; 511 | prs = strtok(NULL, ";\n"); 512 | countVector++; 513 | } 514 | } else 515 | printConsole(F("Loading failed"), TFT_RED, 0, 0); 516 | 517 | for (uint8_t i = 0; i < fwList.size(); i++) { 518 | String toprint = (String)(i + 1) + " " + fwList[i].fwName; 519 | printConsole(toprint, TFT_GREEN, 0, 0); 520 | } 521 | 522 | firmwareNo = 0; 523 | while (!firmwareNo) { 524 | printConsole(F("Choose App:"), TFT_MAGENTA, 0, 0); 525 | firmwareNo = getUserInput().toInt(); 526 | if (firmwareNo < 1 || firmwareNo > fwList.size()) firmwareNo = 0; 527 | } 528 | 529 | fmw.firmwareName = fwList[firmwareNo - 1].fwName; 530 | fmw.firmwareLink = fwList[firmwareNo - 1].fwLink; 531 | 532 | printConsole(fmw.firmwareName, TFT_YELLOW, 0, 0); 533 | printConsole(F("Loading info..."), TFT_MAGENTA, 0, 0); 534 | 535 | if (wificl.clientD->GET((String)urlPost + F("?info=") + String(firmwareNo + 1), 536 | hostD)) { 537 | readedData = wificl.clientD->getResponseBody(); 538 | char* prs = strtok((char*)readedData.c_str(), ";\n"); 539 | printConsole(F("App name:"), TFT_MAGENTA, 0, 0); 540 | printConsole((String)prs, TFT_GREEN, 1, 0); 541 | prs = strtok(NULL, ";\n"); 542 | printConsole(F("Type:"), TFT_MAGENTA, 0, 0); 543 | printConsole((String)prs, TFT_GREEN, 1, 0); 544 | prs = strtok(NULL, ";\n"); 545 | printConsole(F("Genre:"), TFT_MAGENTA, 0, 0); 546 | printConsole((String)prs, TFT_GREEN, 1, 0); 547 | prs = strtok(NULL, ";\n"); 548 | printConsole(F("Author:"), TFT_MAGENTA, 0, 0); 549 | printConsole((String)prs, TFT_GREEN, 1, 0); 550 | prs = strtok(NULL, ";\n"); 551 | printConsole(F("License:"), TFT_MAGENTA, 0, 0); 552 | printConsole((String)prs, TFT_GREEN, 1, 0); 553 | prs = strtok(NULL, ";\n"); 554 | printConsole(F("Info:"), TFT_MAGENTA, 0, 0); 555 | printConsole((String)prs, TFT_GREEN, 1, 0); 556 | } else 557 | printConsole(F("Failed"), TFT_RED, 0, 0); 558 | 559 | char approve = 0; 560 | while (approve == 0) { 561 | printConsole(F("Download App? [y/n]"), TFT_MAGENTA, 0, 0); 562 | keybParam.typing="y"; 563 | approve = getUserInput()[0]; 564 | } 565 | 566 | 567 | if (approve == 'y' || approve == 'Y') { 568 | printConsole(F("YES"), TFT_YELLOW, 0, 0); 569 | } else { 570 | printConsole(F("NO"), TFT_YELLOW, 0, 0); 571 | fmw.firmwareName=""; 572 | } 573 | 574 | fwList.clear(); 575 | wificl.clientD->stop(); 576 | delete wificl.clientD; 577 | return (fmw); 578 | } 579 | 580 | void ESPboyOTA::checkOTA() { 581 | firmware fmw; 582 | fmw.firmwareName=""; 583 | WiFi.setAutoConnect(true); 584 | WiFi.mode(WIFI_STA); 585 | wifi_station_disconnect(); 586 | printConsole(F("ESPboy App store"), TFT_YELLOW, 1, 0); 587 | // Serial.println(F("\n\nWiFi init OK")); 588 | while (!connectWifi()) delay(1500); 589 | postLog("no", "no"); 590 | while (fmw.firmwareName == "") { 591 | fmw = getFirmware(); 592 | delay(500); 593 | } 594 | postLog("no", fmw.firmwareName); 595 | updateOTA(fmw.firmwareLink); 596 | wifi_station_disconnect(); 597 | delay(5000); 598 | } 599 | -------------------------------------------------------------------------------- /ESPboyOTA.h: -------------------------------------------------------------------------------- 1 | /* 2 | ESPboyOTA class -- ESPboy App Store client core 3 | for www.ESPboy.com project by RomanS 4 | https://hackaday.io/project/164830-espboy-games-iot-stem-for-education-fun 5 | thanks to DmitryL (Plague) for help, tests and advices 6 | */ 7 | 8 | #ifndef ESPboy_OTA 9 | #define ESPboy_OTA 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define OTA_TIMEOUT_CONNECTION 10000 18 | #define OTA_MAX_CONSOLE_STRINGS 50 19 | #define OTA_MAX_STRINGS_ONSCREEN_FULL 15 20 | #define OTA_MAX_STRINGS_ONSCREEN_SMALL 10 21 | #define OTA_MAX_TYPING_CHARS 60 22 | #define OTA_KEY_UNPRESSED_TIMEOUT 700 23 | #define OTA_KEY_PRESSED_DELAY_TO_SEND 500 24 | #define OTA_CURSOR_BLINKING_PERIOD 500 25 | #define OTA_KEYB_CALL_DELAY 150 //auto repeat 26 | 27 | #define OTA_PAD_LEFT 0x01 28 | #define OTA_PAD_UP 0x02 29 | #define OTA_PAD_DOWN 0x04 30 | #define OTA_PAD_RIGHT 0x08 31 | #define OTA_PAD_ACT 0x10 32 | #define OTA_PAD_ESC 0x20 33 | #define OTA_PAD_LFT 0x40 34 | #define OTA_PAD_RGT 0x80 35 | #define OTA_PAD_ANY 0xff 36 | 37 | struct firmware{ 38 | String firmwareName; 39 | String firmwareLink; 40 | }; 41 | 42 | struct wf { 43 | String ssid; 44 | uint8_t rssi; 45 | uint8_t encription; 46 | }; 47 | 48 | struct fw { 49 | String fwName; 50 | String fwLink; 51 | }; 52 | 53 | struct lessRssi{ 54 | inline bool operator() (const wf& str1, const wf& str2) {return (str1.rssi > str2.rssi);} 55 | }; 56 | 57 | 58 | class ESPboyOTA{ 59 | 60 | private: 61 | Adafruit_MCP23017 *mcp; 62 | TFT_eSPI *tft; 63 | 64 | std::vector wfList; // WiFi list 65 | std::vector fwList; // Firmware list 66 | 67 | struct keyboardParameters{ 68 | uint8_t renderLine; 69 | uint8_t displayMode; 70 | uint8_t shiftOn; 71 | int8_t selX; 72 | int8_t selY; 73 | String typing; 74 | }keybParam; 75 | 76 | 77 | struct wificlient{ 78 | String ssid; 79 | String pass; 80 | HTTPSRedirect *clientD; 81 | }wificl; 82 | 83 | const static uint8_t keybOnscr[2][3][21] PROGMEM; 84 | const static char PROGMEM *hostD; 85 | const static char PROGMEM *urlPost; 86 | const static uint16_t PROGMEM httpsPort; 87 | 88 | static String *consoleStrings; 89 | static uint16_t *consoleStringsColor; 90 | 91 | 92 | uint8_t keysAction(); 93 | void toggleDisplayMode(uint8_t mode); 94 | void drawConsole(uint8_t onlyLastLine); 95 | uint8_t getKeys(); 96 | uint32_t waitKeyUnpressed(); 97 | void drawKeyboard(uint8_t slX, uint8_t slY, uint8_t onlySelected); 98 | void drawTyping(uint8_t); 99 | void drawBlinkingCursor(); 100 | 101 | uint16_t scanWiFi(); 102 | String getWiFiStatusName(); 103 | boolean connectWifi(); 104 | void OTAstarted(); 105 | void OTAfinished(); 106 | void OTAprogress(int cur, int total); 107 | void OTAerror(int err); 108 | void updateOTA(String otaLink); 109 | String fillPayload(String downloadID, String downloadName); 110 | void postLog(String downloadID, String downloadName); 111 | firmware getFirmware(); 112 | void checkOTA(); 113 | void printConsole(String bfrstr, uint16_t color, uint8_t ln, uint8_t noAddLine); 114 | String getUserInput(); 115 | 116 | public: 117 | ESPboyOTA(TFT_eSPI *tftOTA, Adafruit_MCP23017 *mcpOTA); 118 | }; 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPboy_little_game_engine 2 | 3 | LGE is a fantasy console for making, sharing and playing tiny games and other computer programs. 4 | You can make you game or program using online compiler and run compiled binary on portable ESPboy console thouse feels like a regular console. Check few, colored, nostalgic LGE games from the package, by uploading them to SPIFFS. 5 | 6 | Games sources: 7 | https://github.com/corax89/game_engine_for_esp8266_with_compiler/tree/master/example 8 | 9 | Hackaday: 10 | https://hackaday.io/project/164205-esp-little-game-engine 11 | 12 | Article: 13 | https://hackaday.com/2019/03/11/esp8266-gets-its-game-on-with-open-source-engine/ 14 | 15 | User Guide: 16 | https://corax89.github.io/esp8266Game/user_guide/index.html 17 | 18 | Online ESP-LGE SDK, compiler, emulator: 19 | https://corax89.github.io/esp8266Game/index.html 20 | 21 | How to compile for ESPboy: 22 | 1. Install Arduino IDE 23 | 2. Clone and download "ESPboy_little_game_engine" and rename the folder "ESPboy_little_game_engine-master" to "ESPboy_little_game_engine" 24 | 3. Unpack two libraries (a_coos and TFT_eSPI) from file "libraries.7z" to the Arduino/Libraries folder 25 | 4. Change settings in file «User_Setup.h» of TFT_eSPI library 26 | - 50 #define TFT_WIDTH 128 27 | - 53 #define TFT_HEIGHT 128 28 | - 67 #define ST7735_GREENTAB3 29 | - 149 #define TFT_CS -1 30 | - 150 #define TFT_DC PIN_D8 31 | - 152 #define TFT_RST -1 32 | - 224 #define LOAD_GLCD 33 | - 255 #define SPI_FREQUENCY 27000000 34 | 5. Open "esp8266_game_engine.ino" in Arduino IDE and compile it for "Lolin/WeMos D1 mini ESP8266" board 35 | 6. Upload the games to your ESPboy SPIFFS 36 | 7. Enjoy ) 37 | 38 | How to upload games to SPIFFS: 39 | https://www.youtube.com/watch?v=25eLIdLKgHs 40 | 41 | 42 | How to recompile CHIP8 games: 43 | 1. Use source file https://github.com/corax89/game_engine_for_esp8266_with_compiler/blob/master/example/chip8.c 44 | 2. Put your CHIP8 bit code to char "Memory[3583] = {};" at string ¹58 45 | 3. Check buttons remap at strings ¹9-20 46 | 4. Compile this .c to .bin with "Online ESP-LGE SDK, compiler, emulator" https://corax89.github.io/esp8266Game/index.html 47 | 5. Upload .bit to your ESPboy SPIFFS 48 | 49 | 50 | Games in package: 51 | 52 | 1. Original ESP-LGE by Igor: FourInaRow, NinjaEscape, 1916, WormBlast, ESProgue, Galaxies, CityRunner, Memories, MarsAttack, Columns, Mines, Breackout, TowerDefense, 53 | ... 54 | 55 | 56 | 57 | 58 | ![logo](/logo.png) 59 | # esp8266_little_game_engine 60 | Used ili9341. Contains a virtual machine running games from RAM. 61 | 62 | Used library: 63 | 64 | [https://github.com/akouz/a_coos](https://github.com/akouz/a_coos) 65 | 66 | [https://github.com/Bodmer/TFT_eSPI](https://github.com/Bodmer/TFT_eSPI) 67 | 68 | Online emulator with compiler: 69 | 70 | [https://corax89.github.io/esp8266Game/index.html](https://corax89.github.io/esp8266Game/index.html) 71 | 72 | Video: 73 | 74 | [![video](http://img.youtube.com/vi/roOQHuXNVoI/0.jpg)](https://www.youtube.com/watch?v=roOQHuXNVoI "ESP8266 game engine") 75 | -------------------------------------------------------------------------------- /TFT_eSPI/User_Setups/Setup24_ESPboy.h: -------------------------------------------------------------------------------- 1 | #define ST7735_DRIVER 2 | #define TFT_WIDTH 128 3 | #define TFT_HEIGHT 128 4 | //#define ST7735_INITB 5 | //#define ST7735_GREENTAB 6 | //#define ST7735_GREENTAB2 7 | #define ST7735_GREENTAB3 8 | //#define ST7735_GREENTAB128 9 | //#define ST7735_REDTAB 10 | //#define ST7735_BLACKTAB 11 | #define TFT_CS -1 12 | #define TFT_DC PIN_D8 13 | #define TFT_RST -1 14 | #define LOAD_GLCD 15 | #define SPI_FREQUENCY 39000000 -------------------------------------------------------------------------------- /WiFiFileUploader.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "settings.h" 7 | 8 | const char *ssid = APSSID; 9 | const char *password = APPSK; 10 | const char* host = APHOST; 11 | 12 | ESP8266WebServer server(80); 13 | ESP8266HTTPUpdateServer httpUpdater; 14 | File fsUploadFile; 15 | 16 | const char index_html[] PROGMEM = R"=====( 17 | SD Editor
The operation was successful
67 | )====="; 68 | 69 | void startServer(){ 70 | WiFi.forceSleepWake(); 71 | serverSetup(); 72 | tft.fillScreen(0x0000); 73 | tft.setTextSize(1); 74 | tft.setTextColor(0xffff); 75 | tft.setCursor(0,10); 76 | tft.print(F("SSID ")); 77 | tft.print(F(APSSID)); 78 | tft.print(F("\nPassword ")); 79 | tft.print(F(APPSK)); 80 | tft.print(F("\nGo to \nhttp://192.168.4.1")); 81 | tft.print(F("\nin a web browser")); 82 | tft.print(F("\nPress button A to\nreboot")); 83 | Serial.print(F("FreeHeap:")); 84 | Serial.println(ESP.getFreeHeap()); 85 | while(1){ 86 | serverLoop(); 87 | getKey(); 88 | if(Serial.read() == 'r' || thiskey & 16) 89 | ESP.reset(); 90 | delay(100); 91 | } 92 | } 93 | 94 | void handleFileList() { 95 | Dir dir = LittleFS.openDir("/"); 96 | FSInfo fs_info; 97 | String output; 98 | LittleFS.info(fs_info); 99 | Serial.print(fs_info.usedBytes); 100 | Serial.print('/'); 101 | Serial.println(fs_info.totalBytes); 102 | output += fs_info.usedBytes; 103 | output += ':'; 104 | output += fs_info.totalBytes; 105 | while (dir.next()) { 106 | Serial.print(dir.fileName()); 107 | Serial.print(' '); 108 | Serial.println(dir.fileSize()); 109 | if (dir.fileName()[0] != '/') 110 | output += '/'; 111 | output += String(dir.fileName()); 112 | output += ':'; 113 | output += String(dir.fileSize()); 114 | } 115 | 116 | server.send(200, "text/json", output); 117 | output = String(); 118 | Serial.print(F("Free ")); 119 | Serial.println(ESP.getFreeHeap()); 120 | } 121 | 122 | void handleFileUpload() { 123 | if (server.uri() != "/e") { 124 | return; 125 | } 126 | HTTPUpload& upload = server.upload(); 127 | if (upload.status == UPLOAD_FILE_START) { 128 | String filename = upload.filename; 129 | if (!filename.startsWith("/")) { 130 | filename = "/" + filename; 131 | } 132 | Serial.print(F("handleFileUpload Name: ")); Serial.println(filename); 133 | fsUploadFile = LittleFS.open(filename, "w"); 134 | filename = String(); 135 | } else if (upload.status == UPLOAD_FILE_WRITE) { 136 | if (fsUploadFile) { 137 | fsUploadFile.write(upload.buf, upload.currentSize); 138 | } 139 | } else if (upload.status == UPLOAD_FILE_END) { 140 | if (fsUploadFile) { 141 | fsUploadFile.close(); 142 | } 143 | Serial.print(F("handleFileUpload Size: ")); Serial.println(upload.totalSize); 144 | } 145 | } 146 | 147 | const char send_bad_args[] PROGMEM = "BAD ARGS"; 148 | const char send_bad_path[] PROGMEM = "BAD PATH"; 149 | 150 | void handleFileDelete() { 151 | const char *txtplain = "text/plain"; 152 | if (server.args() == 0) { 153 | return server.send_P(500, txtplain, send_bad_args); 154 | } 155 | String path = server.arg(0); 156 | Serial.print(F("handleFileDelete: ")); Serial.println(path); 157 | if (path == "/") { 158 | return server.send_P(500, txtplain, send_bad_path); 159 | } 160 | if (!LittleFS.exists(path)) { 161 | return server.send(404, txtplain, "404"); 162 | } 163 | LittleFS.remove(path); 164 | server.send(200, txtplain, ""); 165 | path = String(); 166 | } 167 | 168 | void handleRoot() { 169 | server.send_P(200, "text/html", index_html); 170 | } 171 | 172 | void serverSetup() { 173 | Serial.println(); 174 | Serial.print(F("Configuring access point...")); 175 | WiFi.softAP(ssid, password); 176 | IPAddress myIP = WiFi.softAPIP(); 177 | Serial.print(F("AP IP address: ")); 178 | Serial.println(myIP); 179 | server.on("/", handleRoot); 180 | server.on("/l", HTTP_GET, handleFileList); 181 | server.on("/e", HTTP_DELETE, handleFileDelete); 182 | server.on("/e", HTTP_POST, []() { 183 | server.send(200, "text/plain", ""); 184 | }, handleFileUpload); 185 | MDNS.begin(host); 186 | httpUpdater.setup(&server); 187 | server.begin(); 188 | MDNS.addService("http", "tcp", 80); 189 | delay(50); 190 | Serial.println(F("HTTP server started")); 191 | } 192 | 193 | void serverLoop() { 194 | server.handleClient(); 195 | } 196 | -------------------------------------------------------------------------------- /acoos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Library COOS - COoperative Operating System 3 | * Author A.Kouznetsov 4 | * Rev 1.6 dated 13/10/2019 5 | * Target Arduino 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted. 8 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 15 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | #ifndef __COOS_H 21 | #define __COOS_H 22 | 23 | //############################################################################## 24 | // Inc 25 | //############################################################################## 26 | 27 | #include 28 | #include 29 | 30 | //############################################################################## 31 | // Typedef 32 | //############################################################################## 33 | 34 | #ifndef __UCHAR_DEFINED__ 35 | #define __UCHAR_DEFINED__ 36 | typedef unsigned char uchar; 37 | typedef signed char schar; 38 | typedef unsigned int uint; 39 | typedef unsigned long ulong; 40 | typedef signed long slong; 41 | #endif 42 | 43 | //############################################################################## 44 | // Def 45 | //############################################################################## 46 | 47 | #define COOS_STOP -2 // set this value to stop task 48 | #define COOS_DELAY(__delay) if (!setjmp(coos.task_context[coos.task_no])) {longjmp(coos.main_context, __delay);} else{} 49 | 50 | #define COOS_REV_MAJ 1 51 | #define COOS_REV_MIN 6 52 | 53 | //############################################################################## 54 | // Template class 55 | //############################################################################## 56 | 57 | template class Coos{ 58 | public: 59 | Coos(void); // constructor 60 | void register_task(void (*tsk)(void)); // user's tasks must be registered first 61 | void start(void); // init scheduler once 62 | void run(void); // COOS task switcher 63 | jmp_buf main_context; // context of scheduler 64 | jmp_buf task_context[COOS_MAX_TASKS]; // list of task contexts 65 | uchar task_no; // current task No 66 | int task_delay[COOS_MAX_TASKS]; // task delay in msec, task stopped if value is negative 67 | unsigned int msec; // ms of current sec 68 | unsigned long uptime; // seconds since start 69 | 70 | private: 71 | void (*tsk_p[COOS_MAX_TASKS])(void); // list of registered tasks 72 | unsigned int ms; 73 | unsigned char task_cnt; // counts registered coos tasks 74 | void update_time(void); 75 | unsigned char stored_min; 76 | }; 77 | 78 | //############################################################################## 79 | // Implementation 80 | //############################################################################## 81 | 82 | // ================================= 83 | // Constructor 84 | // ================================= 85 | template Coos::Coos(void) 86 | { 87 | uptime = 0; 88 | msec = 0; 89 | ms = 0; 90 | task_cnt = 0; 91 | for (int i=0; i void Coos::register_task(void (*tsk)(void)) 101 | { 102 | if (task_cnt < COOS_MAX_TASKS) 103 | { 104 | tsk_p[task_cnt++] = tsk; 105 | } 106 | } 107 | // ================================= 108 | // Update time 109 | // ================================= 110 | // supposed to happen more often than every millisecond, 111 | // task should not keep control for more than about 900 us 112 | template void Coos::update_time(void) 113 | { 114 | unsigned int millisec = (unsigned int)millis(); 115 | while (ms != millisec) // catch up time 116 | { 117 | ms++; 118 | for (int i=0; i 0) // decrement positive delays 121 | { 122 | task_delay[i]--; 123 | } 124 | } 125 | if (++msec >= 1000) // if 1 sec passed 126 | { 127 | uptime++; // count seconds since start 128 | msec = 0; 129 | } 130 | } 131 | } 132 | // ================================= 133 | // Start scheduler - init registered tasks 134 | // ================================= 135 | template void Coos::start(void) 136 | { 137 | int res; 138 | void (*tsk)(void); 139 | update_time(); 140 | for (task_no=0; task_no void Coos::run(void) 163 | { 164 | int res; 165 | int tmp; 166 | if (task_delay[task_no] == 0) 167 | { 168 | res = setjmp(main_context); // set return point and get delay value from the task 169 | if (res == 0) // after setting return point 170 | { 171 | longjmp(task_context[task_no], 1); // invoke task 172 | } 173 | else // after returning from task 174 | { 175 | tmp = --res; 176 | task_delay[task_no] = tmp; // set task delay (negative delay - task stopped) 177 | } 178 | } 179 | if (++task_no >= task_cnt) // next task 180 | { 181 | task_no = 0; // round-robin 182 | } 183 | update_time(); 184 | } 185 | #endif /* __COOS_H */ 186 | -------------------------------------------------------------------------------- /connect.ino: -------------------------------------------------------------------------------- 1 | int16_t serialBegin(){ 2 | serial_used = 1; 3 | return 1; 4 | } 5 | 6 | int16_t serialAvailable(){ 7 | if(Serial.available() && serial_used) 8 | return 1; 9 | return 0; 10 | } 11 | 12 | int16_t serialRead(){ 13 | if(Serial.available() && serial_used) 14 | return Serial.read(); 15 | return 0; 16 | } 17 | 18 | int16_t serialWrite(int16_t n){ 19 | Serial.write((char) n); 20 | return 1; 21 | } 22 | -------------------------------------------------------------------------------- /data/0_ButtonsTest.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/0_ButtonsTest.lge -------------------------------------------------------------------------------- /data/0_LineBenchTest.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/0_LineBenchTest.bin -------------------------------------------------------------------------------- /data/0_SoundTest.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/0_SoundTest.lge -------------------------------------------------------------------------------- /data/1916.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/1916.lge -------------------------------------------------------------------------------- /data/Battleships.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/Battleships.lge -------------------------------------------------------------------------------- /data/BombChase.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/BombChase.lge -------------------------------------------------------------------------------- /data/CommTest.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/CommTest.lge -------------------------------------------------------------------------------- /data/ESPtris.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/ESPtris.lge -------------------------------------------------------------------------------- /data/FourInNarow.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/FourInNarow.lge -------------------------------------------------------------------------------- /data/Highway.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/Highway.lge -------------------------------------------------------------------------------- /data/Microrace.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/Microrace.lge -------------------------------------------------------------------------------- /data/SpaceInvad.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/SpaceInvad.lge -------------------------------------------------------------------------------- /data/asteroids.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/asteroids.lge -------------------------------------------------------------------------------- /data/bash.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/bash.lge -------------------------------------------------------------------------------- /data/blackjack.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/blackjack.lge -------------------------------------------------------------------------------- /data/brainf+ck.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/brainf+ck.lge -------------------------------------------------------------------------------- /data/breackout.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/breackout.bin -------------------------------------------------------------------------------- /data/calculator.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/calculator.lge -------------------------------------------------------------------------------- /data/capman.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/capman.lge -------------------------------------------------------------------------------- /data/cityrunner.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/cityrunner.lge -------------------------------------------------------------------------------- /data/columns.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/columns.lge -------------------------------------------------------------------------------- /data/dwarfsclicker.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/dwarfsclicker.lge -------------------------------------------------------------------------------- /data/esprogue.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/esprogue.lge -------------------------------------------------------------------------------- /data/fishlife.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/fishlife.lge -------------------------------------------------------------------------------- /data/flappybird.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/flappybird.lge -------------------------------------------------------------------------------- /data/frozenworld.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/frozenworld.lge -------------------------------------------------------------------------------- /data/galaxies.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/galaxies.lge -------------------------------------------------------------------------------- /data/gameoflife.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/gameoflife.bin -------------------------------------------------------------------------------- /data/hangman.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/hangman.lge -------------------------------------------------------------------------------- /data/marsattack.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/marsattack.bin -------------------------------------------------------------------------------- /data/memories.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/memories.lge -------------------------------------------------------------------------------- /data/microbasic.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/microbasic.lge -------------------------------------------------------------------------------- /data/mines.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/mines.lge -------------------------------------------------------------------------------- /data/minifisherman.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/minifisherman.lge -------------------------------------------------------------------------------- /data/ninjaescape.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/ninjaescape.lge -------------------------------------------------------------------------------- /data/oldtower.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/oldtower.lge -------------------------------------------------------------------------------- /data/olympusmons.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/olympusmons.lge -------------------------------------------------------------------------------- /data/plagueoutbreak.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/plagueoutbreak.lge -------------------------------------------------------------------------------- /data/snake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/snake.bin -------------------------------------------------------------------------------- /data/spacefighter.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/spacefighter.lge -------------------------------------------------------------------------------- /data/sudoku.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/sudoku.lge -------------------------------------------------------------------------------- /data/tankcity.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/tankcity.lge -------------------------------------------------------------------------------- /data/towerdefence.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/towerdefence.lge -------------------------------------------------------------------------------- /data/twosnakes.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/twosnakes.lge -------------------------------------------------------------------------------- /data/wormblast.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/wormblast.lge -------------------------------------------------------------------------------- /data/zombiedefence.lge: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/data/zombiedefence.lge -------------------------------------------------------------------------------- /esp_little_game_engine_description.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/esp_little_game_engine_description.pdf -------------------------------------------------------------------------------- /esp_little_game_engine_user_guide-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/esp_little_game_engine_user_guide-2.pdf -------------------------------------------------------------------------------- /esp_little_game_engine_user_guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/esp_little_game_engine_user_guide.pdf -------------------------------------------------------------------------------- /fileUpload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SD Editor 6 | 263 | 360 | 361 | 362 |
363 |
364 | 367 | 369 | 370 | 371 | 372 | 373 |
374 |
375 |
376 |
The operation was successful
377 |
378 |
379 |
380 | 381 | -------------------------------------------------------------------------------- /file_manager.ino: -------------------------------------------------------------------------------- 1 | #ifndef ROM_NAME 2 | #include "rom.h" 3 | #endif 4 | 5 | const uint8_t saveIco[] PROGMEM = { 6 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, 7 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x38, 0x88, 0x88, 0x88, 0xff, 0xf6, 0x60, 0x00, 0x00, 0x00, 8 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xf6, 0x66, 0x60, 0x00, 0x00, 9 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xf6, 0x66, 0x66, 0x00, 0x00, 10 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xf6, 0x66, 0x66, 0x66, 0x00, 11 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xf6, 0x66, 0x66, 0x66, 0x60, 12 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xf6, 0x66, 0x66, 0x66, 0x60, 13 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xf6, 0x66, 0x66, 0x66, 0x60, 14 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xf6, 0x66, 0x66, 0x66, 0x60, 15 | 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x66, 0x66, 0x66, 0x60, 16 | 0x66, 0x66, 0x66, 0x66, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x66, 0x66, 0x66, 0x66, 0x60, 17 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 18 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 19 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 20 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 21 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 22 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 23 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 24 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 25 | 0x66, 0x66, 0x66, 0x66, 0x61, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66, 0x66, 0x66, 0x60, 26 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 27 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 28 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x1d, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 29 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 30 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 31 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 32 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x18, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc8, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 33 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 34 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 35 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 36 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x1c, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 37 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 38 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 39 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 40 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 41 | 0x66, 0x66, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x66, 0x66, 0x66, 0x60, 42 | 0x04, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x0b, 0x00, 0x0b, 0x00, 0xb0, 0xb0, 0x0b, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0x0b, 0x00, 0xb0, 0xb0, 0x0b, 0x00, 0x0b, 0xb0, 0x0b, 0x00, 0xb0, 0xb0, 48 | 0xb0, 0xb0, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0x00, 0xbb, 0xbb, 0xb0, 0x00, 0xb0, 0xbb, 0xb0, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xbb, 0xb0, 49 | 0x0b, 0x00, 0x0b, 0xb0, 0xb0, 0xb0, 0xbb, 0xb0, 0x00, 0xb0, 0xb0, 0xb0, 0x0b, 0xb0, 0xb0, 0xb0, 0x0b, 0xb0, 0xb0, 0xb0, 0xbb, 0xb0, 0xb0, 0x00, 50 | 0x00, 0xb0, 0xb0, 0xb0, 0x0b, 0x00, 0xb0, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0x00, 0xb0, 0x00, 51 | 0xb0, 0xb0, 0xb0, 0xb0, 0x0b, 0x00, 0xb0, 0xb0, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0x00, 52 | 0x0b, 0x00, 0xbb, 0xb0, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xbb, 0xb0, 0xb0, 0xb0, 0xbb, 0xb0, 0x0b, 0xb0, 0x0b, 0x00, 0xb0, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00 54 | }; 55 | 56 | const uint8_t uploadIco[] PROGMEM = { 57 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 61 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 62 | 0xf5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xf0, 63 | 0x59, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x50, 64 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 65 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 66 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x95, 0x11, 0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 67 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x95, 0x51, 0x11, 0x11, 0x11, 0x11, 0x55, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 68 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x59, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 69 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x93, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 70 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x31, 0x11, 0x11, 0x1f, 0xff, 0xff, 0x11, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 71 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x11, 0x11, 0x11, 0x39, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 72 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9f, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 73 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x11, 0x11, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 74 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x11, 0x11, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 75 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x11, 0x11, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 76 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0xff, 0xf9, 0x99, 0x99, 0xff, 0xf1, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 77 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 78 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 79 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x19, 0x99, 0x99, 0x99, 0x99, 0x11, 0x11, 0x1f, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 80 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x93, 0x11, 0x11, 0x11, 0x99, 0x99, 0x99, 0x91, 0x11, 0x11, 0x15, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 81 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 82 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x51, 0x11, 0x11, 0x11, 0x99, 0x91, 0x11, 0x11, 0x11, 0x59, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 83 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x93, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 84 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 85 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xf1, 0x11, 0x11, 0x11, 0x1f, 0xf9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 86 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xf9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 87 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 88 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 89 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 90 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 91 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 92 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 93 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 98 | 0x00, 0x00, 0x00, 0x00, 0x0b, 0xb0, 0x0b, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0xb0, 0x00, 0x00, 0x00, 0x00, 99 | 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xbb, 0xb0, 0xb0, 0xb0, 0xb0, 0x00, 0xb0, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 100 | 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0x0b, 0xb0, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 101 | 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0x0b, 0x0b, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0x0b, 0x0b, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x0b, 0xb0, 0x0b, 0x00, 0x0b, 0x0b, 0x00, 0xb0, 0xb0, 0xb0, 0x0b, 0x00, 0xbb, 0xb0, 0x0b, 0xb0, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 105 | }; 106 | 107 | const uint8_t otaIco[] PROGMEM = { 108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x90, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 114 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x90, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 115 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 116 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 118 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 119 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 120 | 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 121 | 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 122 | 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 123 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 126 | 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 127 | 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 128 | 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 129 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 130 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 131 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 132 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x0b, 133 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 134 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 135 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 136 | 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x90, 0x00, 137 | 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 138 | 0x00, 0x00, 0x09, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 139 | 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 140 | 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xb0, 0x0b, 0xbb, 0xbb, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0xb0, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xb0, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 156 | }; 157 | 158 | static const uint8_t iconBin[] PROGMEM = { 159 | 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x1c,0xcc,0xcc,0xcc,0xcc,0xcc, 160 | 0xcc,0x11,0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11, 161 | 0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11, 162 | 0x11,0x11,0x1c,0x1c,0xc1,0x1c,0x1c,0xc1,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x1c,0x1c,0x11,0x1c,0x1c, 163 | 0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x1c,0xc1,0x1c,0x1c,0x1c,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x1c, 164 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x11,0x11,0x11, 165 | 0x11,0x11,0x1c,0x1c,0xc1,0x1c,0x1c,0x1c,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11, 166 | 0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0x11, 167 | 0x11,0x11,0x11,0x11,0x1c,0x11,0x11,0x11,0x11,0x11,0x1c,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x11,0x11,0x11, 168 | 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11 169 | }; 170 | 171 | struct { 172 | int16_t saveMenuPos; 173 | int16_t saveStartMenuPos; 174 | uint32_t crc32; 175 | } rtcData; 176 | 177 | uint32_t calculateCRC32inRTC(const uint8_t *data) { 178 | size_t length = sizeof(rtcData) - 4; 179 | uint32_t crc = 0xffffffff; 180 | while (length--) { 181 | uint8_t c = *data++; 182 | for (uint32_t i = 0x80; i > 0; i >>= 1) { 183 | bool bit = crc & 0x80000000; 184 | if (c & i) { 185 | bit = !bit; 186 | } 187 | crc <<= 1; 188 | if (bit) { 189 | crc ^= 0x04c11db7; 190 | } 191 | } 192 | } 193 | return crc; 194 | } 195 | 196 | uint8_t drawDialog(){ 197 | char txt[] = "Press leftbutton to delete this save."; 198 | char b1[] = "Yes"; 199 | char b2[] = "No"; 200 | int16_t i,x,y; 201 | setColor(1); 202 | for(i = 30; i < 90; i++) 203 | drwLine(20, i, 108, i); 204 | setColor(8); 205 | drwLine(20, 30, 108, 30); 206 | drwLine(20, 90, 108, 90); 207 | drwLine(20, 30, 20, 90); 208 | drwLine(108, 30, 108, 90); 209 | x = 24; 210 | y = 32; 211 | for(i = 0; i < 37; i++){ 212 | putchar(txt[i], x, y); 213 | x += 6; 214 | if(x > 102){ 215 | x = 24; 216 | y += 8; 217 | } 218 | } 219 | for(i = 0; i < 4; i++){ 220 | putchar(b1[i], 24 + i * 6, 80); 221 | } 222 | for(i = 0; i < 3; i++){ 223 | putchar(b2[i], 80 + i * 6, 80); 224 | } 225 | redrawScreen(); 226 | delay(400); 227 | while(1){ 228 | thiskey = 0; 229 | while(thiskey == 0){ 230 | getKey(); 231 | delay(100); 232 | changeSettings(); 233 | if(fileIsLoad) 234 | return 0; 235 | } 236 | if(thiskey & 4){//left 237 | return 1; 238 | } 239 | else 240 | return 0; 241 | } 242 | } 243 | 244 | void drawMenuBackground(){ 245 | int16_t i; 246 | setColor(1); 247 | for(i = 7; i < 121; i++) 248 | drwLine(13, i, 115, i); 249 | setColor(8); 250 | drwLine(12, 6, 116, 6); 251 | drwLine(12, 121, 116, 121); 252 | drwLine(12, 6, 12, 121); 253 | drwLine(116, 6, 116, 121); 254 | } 255 | 256 | void drawSave(uint8_t startPos, uint8_t selectPos){ 257 | uint16_t pos; 258 | uint8_t c,i,n; 259 | String s_buffer; 260 | pos = 0; 261 | n = 0; 262 | while(pos < EEPROM_SIZE && (n - startPos < 14)){ 263 | if(n == selectPos) 264 | setColor(2); 265 | else 266 | setColor(0); 267 | c = EEPROM.read(pos); 268 | if(c == 0 || c == 0xff) 269 | return; 270 | if(n >= startPos){ 271 | i = 0; 272 | c = EEPROM.read(pos + 1); 273 | while(i < 12 && c != 0){ 274 | putchar(c, 14 + i * 6, 8 + (n - startPos) * 8); 275 | i++; 276 | c = EEPROM.read(pos + 1 + i); 277 | } 278 | c = EEPROM.read(pos); 279 | s_buffer = String(c); 280 | for(i = 0; i < s_buffer.length(); i++){ 281 | putchar(s_buffer[i], 100 + i * 6, 8 + (n - startPos) * 8); 282 | } 283 | } 284 | n++; 285 | pos += c; 286 | } 287 | } 288 | 289 | uint8_t getSaveLength(){ 290 | uint16_t pos = 0; 291 | uint8_t n = 0; 292 | uint8_t c; 293 | while(pos < EEPROM_SIZE){ 294 | c = EEPROM.read(pos); 295 | if(c == 0 || c == 0xff) 296 | return n; 297 | pos += c; 298 | n++; 299 | } 300 | return n; 301 | } 302 | 303 | void deliteSave(uint8_t num, uint16_t end){ 304 | uint16_t i,pos = 0; 305 | uint8_t n = 0; 306 | uint8_t c; 307 | while(pos < EEPROM_SIZE && n != num){ 308 | c = EEPROM.read(pos); 309 | pos += c; 310 | n++; 311 | } 312 | c = EEPROM.read(pos); 313 | for(i = pos + c; i < end; i++){ 314 | EEPROM.write(i - c, EEPROM.read(i)); 315 | EEPROM.write(i, 0); 316 | } 317 | EEPROM.commit(); 318 | } 319 | 320 | void saveManager(){ 321 | uint8_t pos,listLength; 322 | drawMenuBackground(); 323 | drawSave(0,0); 324 | redrawScreen(); 325 | pos = 0; 326 | listLength = getSaveLength(); 327 | delay(400); 328 | while(1){ 329 | thiskey = 0; 330 | while(thiskey == 0){ 331 | getKey(); 332 | delay(100); 333 | changeSettings(); 334 | if(fileIsLoad) 335 | return; 336 | } 337 | if(thiskey & 128 || thiskey & 32){ 338 | return; 339 | } 340 | else if(thiskey & 2){//down 341 | if(pos < listLength - 1){ 342 | pos++; 343 | drawMenuBackground(); 344 | drawSave(pos,pos); 345 | redrawScreen(); 346 | } 347 | } 348 | else if(thiskey & 1){//up 349 | if(pos > 0){ 350 | pos--; 351 | drawMenuBackground(); 352 | drawSave(pos,pos); 353 | redrawScreen(); 354 | } 355 | } 356 | else if(thiskey & 16){//ok 357 | if(drawDialog()){ 358 | deliteSave(pos, findEndData()); 359 | } 360 | drawMenuBackground(); 361 | drawSave(pos,pos); 362 | redrawScreen(); 363 | } 364 | } 365 | } 366 | 367 | void drawIco(const uint8_t *a, int16_t x, int16_t y, int16_t w, int16_t h){ 368 | uint8_t p, color; 369 | int i = 0; 370 | for(int16_t yi = 0; yi < h; yi++) 371 | for(int16_t xi = 0; xi < w; xi++){ 372 | p = pgm_read_byte(a + i); 373 | color = (p & 0xf0) >> 4; 374 | if(color > 0){ 375 | setPix(xi + x, yi + y, color); 376 | } 377 | xi++; 378 | color = p & 0x0f; 379 | if(color > 0){ 380 | setPix(xi + x, yi + y, color); 381 | } 382 | i++; 383 | } 384 | } 385 | 386 | void softwareMenu(){ 387 | uint8_t pos = 0, x, y; 388 | delay(400); 389 | while(1){ 390 | x = (pos % 2) * 50 + 14; 391 | y = (pos / 2) * 58 + 11; 392 | drawMenuBackground(); 393 | setColor(10); 394 | fllRect(x, y, x + 50, y + 50); 395 | drawIco(saveIco, 16, 12, 48, 48); 396 | drawIco(uploadIco, 66, 12, 48, 48); 397 | drawIco(otaIco, 16, 68, 48, 48); 398 | redrawScreen(); 399 | thiskey = 0; 400 | while(thiskey == 0){ 401 | getKey(); 402 | delay(100); 403 | changeSettings(); 404 | } 405 | if(thiskey & 2){//down 406 | if(pos == 0){ 407 | pos = 2; 408 | } 409 | } 410 | else if(thiskey & 1){//up 411 | if(pos == 2){ 412 | pos = 0; 413 | } 414 | } 415 | else if(thiskey & 4){//left 416 | if(pos == 1){ 417 | pos = 0; 418 | } 419 | } 420 | else if(thiskey & 8){//right 421 | if(pos == 0){ 422 | pos = 1; 423 | } 424 | } 425 | if(thiskey & 16){ 426 | if(pos == 0){ 427 | saveManager(); 428 | } 429 | else if(pos == 1){ 430 | memoryFree(); 431 | startServer(); 432 | } 433 | #ifdef ESPBOY 434 | else if(pos == 2){ 435 | memoryFree(); 436 | OTAobj = new ESPboyOTA(&tft, &mcp); 437 | } 438 | #endif 439 | return; 440 | } 441 | if(thiskey & 32){ 442 | return; 443 | } 444 | } 445 | } 446 | 447 | void drawVersionInFileList(){ 448 | tft.setTextColor(TFT_DARKGREY); 449 | tft.setCursor(SCREEN_REAL_WIDTH - 30, SCREEN_REAL_HEIGHT - 7); 450 | tft.print(F(BUILD_VERSION_MAJOR)); 451 | tft.print('.'); 452 | tft.print(F(BUILD_VERSION_MINOR)); 453 | } 454 | 455 | void fileList(String path) { 456 | fs::Dir dir = LittleFS.openDir(path); 457 | char s[32]; 458 | char thisF[32]; 459 | int16_t lst = 0; 460 | int16_t pos; 461 | int16_t startpos = 0; 462 | int16_t fileCount = 1; 463 | int16_t skip = 0; 464 | uint8_t i,b; 465 | ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcData, sizeof(rtcData)); 466 | if (rtcData.crc32 != calculateCRC32inRTC((uint8_t*) &rtcData)) { 467 | rtcData.saveMenuPos = 0; 468 | rtcData.saveStartMenuPos = 0; 469 | rtcData.crc32 = calculateCRC32inRTC((uint8_t*) &rtcData); 470 | ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData)); 471 | } 472 | setClip(0, 0, 128, 128); 473 | pos = rtcData.saveMenuPos; 474 | startpos = rtcData.saveStartMenuPos; 475 | display_init(); 476 | setBgColor(0); 477 | setColor(1); 478 | tft.fillScreen(0x0000); 479 | #ifdef ESPBOY 480 | myled.setRGB(0, 0, 0); 481 | #endif 482 | for(i = 0; i < 192; i++) 483 | writeMem(i + 1024 + 192, pgm_read_byte_near(iconBin + i)); 484 | setImageSize(1); 485 | while (dir.next()) { 486 | fs::File entry = dir.openFile("r"); 487 | entry.close(); 488 | fileCount++; 489 | } 490 | if(startpos > fileCount) 491 | startpos = 0; 492 | Serial.print(F("find ")); 493 | Serial.print(fileCount); 494 | Serial.println(F(" files")); 495 | while(1){ 496 | clearScr(0); 497 | skip = startpos - 1; 498 | if(skip < 0) 499 | skip = 0; 500 | lst = 1; 501 | dir = LittleFS.openDir(path); 502 | setColor(8); 503 | for(i = 1; i < 17; i++) 504 | drwLine(2, (pos - startpos) * 17 + i, 124, (pos - startpos) * 17 + i); 505 | setColor(1); 506 | if(startpos == 0){ 507 | putString(ROM_NAME, lst * 17 - 16); 508 | loadRomIco(); 509 | drawImg(1024, 0, lst * 17 - 16, 24, 16); 510 | lst++; 511 | } 512 | while (dir.next() && lst < 8) { 513 | fs::File entry = dir.openFile("r"); 514 | if(skip > 0){ 515 | skip--; 516 | } 517 | else{ 518 | strcpy(s, entry.name()); 519 | if(lst + startpos - 1 == pos) 520 | strcpy(thisF, entry.name()); 521 | putString(s, lst * 17 - 16); 522 | i = 0; 523 | while(i < 28 && s[i] != '.') 524 | i++; 525 | i++; 526 | if(s[i] == 'l' && s[i + 1] == 'g' && s[i + 2] == 'e'){ 527 | entry.seek(3, SeekSet); 528 | if(entry.available()) 529 | b = (uint8_t)entry.read(); 530 | if(b & 0x2){ 531 | entry.seek(5, SeekSet); 532 | for(i = 0; i < 192; i++) 533 | if(entry.available()) 534 | writeMem(i + 1024, (uint8_t)entry.read()); 535 | drawImg(1024, 0, lst * 17 - 16, 24, 16); 536 | } 537 | else 538 | drawImg(1024 + 192, 0, lst * 17 - 16, 24, 16); 539 | } 540 | else if(s[i] == 'b' && s[i + 1] == 'i' && s[i + 2] == 'n') 541 | drawImg(1024 + 192, 0, lst * 17 - 16, 24, 16); 542 | lst++; 543 | } 544 | entry.close(); 545 | } 546 | if(lst + startpos - 1 < pos){ 547 | if(fileCount > pos) 548 | startpos++; 549 | else 550 | pos--; 551 | } 552 | else if(startpos > pos){ 553 | startpos = pos; 554 | } 555 | redrawScreen(); 556 | drawVersionInFileList(); 557 | delay(200); 558 | getKey(); 559 | while(thiskey == 0){ 560 | getKey(); 561 | delay(100); 562 | changeSettings(); 563 | if(fileIsLoad) 564 | return; 565 | } 566 | if(thiskey & 16){//ok 567 | rtcData.saveMenuPos = pos; 568 | rtcData.saveStartMenuPos = startpos; 569 | rtcData.crc32 = calculateCRC32inRTC((uint8_t*) &rtcData); 570 | ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData)); 571 | cpuInit(); 572 | i = 0; 573 | while(i < 28 && thisF[i] != '.') 574 | i++; 575 | i++; 576 | setLoadedFileName(thisF); 577 | if(startpos == pos && pos == 0) 578 | loadRom(); 579 | else if(thisF[i] == 'b' && thisF[i + 1] == 'i' && thisF[i + 2] == 'n') 580 | loadBinFromSPIFS(thisF); 581 | else if(thisF[i] == 'l' && thisF[i + 1] == 'g' && thisF[i + 2] == 'e') 582 | loadLgeFromSPIFS(thisF); 583 | return; 584 | } 585 | else if(thiskey & 2){//down 586 | if(pos < fileCount - 1){ 587 | pos++; 588 | } 589 | else{ 590 | pos = 0; 591 | startpos = 0; 592 | } 593 | if(pos - startpos > 5){ 594 | startpos++; 595 | setColor(0); 596 | for(int8_t i = 0; i < 8; i++){ 597 | drwLine(0, 0, 127, 0); 598 | drwLine(0, 1, 127, 1); 599 | scrollScreen(0, 1); 600 | scrollScreen(0, 1); 601 | redrawScreen(); 602 | } 603 | } 604 | } 605 | else if(thiskey & 1){//up 606 | if(pos > 0){ 607 | pos--; 608 | } 609 | else{ 610 | pos = fileCount - 1; 611 | startpos = (fileCount - 6 >= 0) ? fileCount - 6 : 0; 612 | } 613 | if(pos - startpos < 0){ 614 | startpos--; 615 | setColor(0); 616 | for(int8_t i = 0; i < 8; i++){ 617 | scrollScreen(0, 3); 618 | scrollScreen(0, 3); 619 | drwLine(0, 0, 127, 0); 620 | drwLine(0, 1, 127, 1); 621 | redrawScreen(); 622 | drawVersionInFileList(); 623 | } 624 | } 625 | } 626 | if(thiskey & 32){//B 627 | softwareMenu(); 628 | delay(400); 629 | } 630 | if(thiskey & 128){//select 631 | saveManager(); 632 | delay(400); 633 | } 634 | } 635 | } 636 | 637 | void loadBinFromSPIFS(char fileName[]){ 638 | int i; 639 | for(i = 0; i < RAM_SIZE; i++) 640 | writeMem(i, 0); 641 | fs::File f = LittleFS.open(fileName, "r"); 642 | if(f.size() < RAM_SIZE) 643 | for(i = 0; i < f.size(); i++){ 644 | writeMem(i, (uint8_t)f.read()); 645 | } 646 | Serial.print(F("loaded ")); 647 | Serial.print(i); 648 | Serial.println(F(" byte")); 649 | Serial.print(F("free heap ")); 650 | Serial.println(system_get_free_heap_size()); 651 | f.close(); //Close file 652 | } 653 | 654 | void loadLgeFromSPIFS(char fileName[]){ 655 | int n,j,i = 0; 656 | uint8_t b,l; 657 | int16_t length, position, point; 658 | for(i = 0; i < RAM_SIZE; i++) 659 | writeMem(i, 0); 660 | fs::File f = LittleFS.open(fileName, "r"); 661 | if((char)f.read() == 'l' && (char)f.read() == 'g' && (char)f.read() == 'e'){ 662 | l = (uint8_t)f.read(); 663 | } 664 | else 665 | return; 666 | n = (uint8_t)f.read(); 667 | //Serial.print(F("offset ")); 668 | //Serial.print(n); 669 | f.seek(n, SeekSet); 670 | n = 0; 671 | while(f.available()){ 672 | b = (uint8_t)f.read(); 673 | if((b & 128) == 0){ 674 | length = ((b & 127) << 8) + (uint8_t)f.read(); 675 | for( j = 0; j < length; j ++){ 676 | if(n < RAM_SIZE) 677 | writeMem(n, (uint8_t)f.read()); 678 | n++; 679 | } 680 | } 681 | else{ 682 | length = (b & 127) >> 1; 683 | position = (((b & 1) << 8) + (uint8_t)f.read()); 684 | point = n - position; 685 | for( j = 0; j < length; j ++){ 686 | if(n < RAM_SIZE && point + j < RAM_SIZE) 687 | writeMem(n, readMem(point + j)); 688 | n++; 689 | } 690 | } 691 | } 692 | Serial.print(F("loaded ")); 693 | Serial.print(n); 694 | Serial.println(F(" byte")); 695 | Serial.print(F("free heap ")); 696 | Serial.println(system_get_free_heap_size()); 697 | f.close(); //Close file 698 | } 699 | -------------------------------------------------------------------------------- /font_a.c: -------------------------------------------------------------------------------- 1 | #ifdef __AVR__ 2 | #include 3 | #include 4 | #elif defined(ESP8266) 5 | #include 6 | #else 7 | #define PROGMEM 8 | #endif 9 | 10 | // Standard ASCII 5x7 font 11 | 12 | static const unsigned char font_a[] PROGMEM = { 13 | 0x00,0x00,0x00,0x00,0x00, // NUL 14 | 0x3E,0x55,0x51,0x55,0x3E, // SOH 15 | 0x3E,0x6B,0x6F,0x6B,0x3E, // STX 16 | 0x0C,0x1E,0x3C,0x1E,0x0C, // ETX 17 | 0x08,0x1C,0x3E,0x1C,0x08, // EOT 18 | 0x1C,0x4A,0x7F,0x4A,0x1C, // ENQ 19 | 0x18,0x5C,0x7F,0x5C,0x18, // ACK 20 | 0x00,0x1C,0x1C,0x1C,0x00, // BEL 21 | 0x7F,0x63,0x63,0x63,0x7F, // BS 22 | 0x00,0x1C,0x14,0x1C,0x00, // TAB 23 | 0x7F,0x63,0x6B,0x63,0x7F, // LF 24 | 0x30,0x48,0x4D,0x33,0x07, // VT 25 | 0x06,0x29,0x79,0x29,0x06, // FF 26 | 0x20,0x50,0x3F,0x02,0x0C, // CR 27 | 0x60,0x7F,0x05,0x35,0x3F, // SO 28 | 0x2A,0x1C,0x77,0x1C,0x2A, // SI 29 | 0x00,0x7F,0x3E,0x1C,0x08, // DLE 30 | 0x08,0x1C,0x3E,0x7F,0x00, // DC1 31 | 0x14,0x22,0x7F,0x22,0x14, // DC2 32 | 0x00,0x5F,0x00,0x5F,0x00, // DC3 33 | 0x06,0x09,0x7F,0x01,0x7F, // DC4 34 | 0x4A,0x55,0x55,0x55,0x29, // NAK 35 | 0x60,0x60,0x60,0x60,0x60, // SYN 36 | 0x54,0x62,0x7F,0x62,0x54, // ETB 37 | 0x08,0x04,0x7E,0x04,0x08, // CAN 38 | 0x08,0x10,0x3F,0x10,0x08, // EM 39 | 0x08,0x08,0x2A,0x1C,0x08, // SUB 40 | 0x08,0x1C,0x2A,0x08,0x08, // ESC 41 | 0x1C,0x10,0x10,0x10,0x10, // FS 42 | 0x1C,0x3E,0x08,0x3E,0x1C, // GS 43 | 0x30,0x3C,0x3F,0x3C,0x30, // RS 44 | 0x06,0x1E,0x7E,0x1E,0x06, // US 45 | 0x00,0x00,0x00,0x00,0x00, // SPC 46 | 0x00,0x00,0x5F,0x00,0x00, // symbol '!' 47 | 0x00,0x07,0x00,0x07,0x00, // symbol 48 | 0x14,0x7F,0x14,0x7F,0x14, // symbol '#' 49 | 0x24,0x2A,0x7F,0x2A,0x12, // symbol '$' 50 | 0x23,0x13,0x08,0x64,0x62, // symbol '%' 51 | 0x36,0x49,0x56,0x20,0x50, // symbol '&' 52 | 0x00,0x00,0x07,0x00,0x00, // symbol ''' 53 | 0x00,0x1C,0x22,0x41,0x00, // symbol '(' 54 | 0x00,0x41,0x22,0x1C,0x00, // symbol ')' 55 | 0x14,0x08,0x3E,0x08,0x14, // symbol '*' 56 | 0x08,0x08,0x3E,0x08,0x08, // symbol '+' 57 | 0x00,0x00,0x00,0xe0,0x00, // symbol ',' 58 | 0x08,0x08,0x08,0x08,0x08, // symbol '-' 59 | 0x00,0x60,0x60,0x00,0x00, // symbol '.' 60 | 0x20,0x10,0x08,0x04,0x02, // symbol '/' 61 | 0x3E,0x51,0x49,0x45,0x3E, // digit '0' 62 | 0x44,0x42,0x7F,0x40,0x40, // digit '1' 63 | 0x42,0x61,0x51,0x49,0x46, // digit '2' 64 | 0x21,0x41,0x45,0x4B,0x31, // digit '3' 65 | 0x18,0x14,0x12,0x7F,0x10, // digit '4' 66 | 0x27,0x45,0x45,0x45,0x39, // digit '5' 67 | 0x3C,0x4A,0x49,0x49,0x30, // digit '6' 68 | 0x01,0x71,0x09,0x05,0x03, // digit '7' 69 | 0x36,0x49,0x49,0x49,0x36, // digit '8' 70 | 0x06,0x49,0x49,0x29,0x1E, // digit '9' 71 | 0x00,0x6C,0x6C,0x00,0x00, // symbol ':' 72 | 0x00,0x2C,0x59,0x01,0x00, // symbol ';' 73 | 0x08,0x14,0x22,0x41,0x00, // symbol '<' 74 | 0x14,0x14,0x14,0x14,0x14, // symbol '=' 75 | 0x00,0x41,0x22,0x14,0x08, // symbol '>' 76 | 0x02,0x01,0x51,0x09,0x06, // symbol '?' 77 | 0x3E,0x41,0x5D,0x55,0x5E, // symbol '@' 78 | 0x7C,0x12,0x11,0x12,0x7C, // eng 'A' 79 | 0x7F,0x49,0x49,0x49,0x36, // eng 'B' 80 | 0x3E,0x41,0x41,0x41,0x22, // eng 'C' 81 | 0x7F,0x41,0x41,0x22,0x1C, // eng 'D' 82 | 0x7F,0x49,0x49,0x49,0x41, // eng 'E' 83 | 0x7F,0x09,0x09,0x09,0x01, // eng 'F' 84 | 0x3E,0x41,0x49,0x49,0x7A, // eng 'G' 85 | 0x7F,0x08,0x08,0x08,0x7F, // eng 'H' 86 | 0x00,0x41,0x7F,0x41,0x00, // eng 'I' 87 | 0x20,0x40,0x41,0x3F,0x01, // eng 'J' 88 | 0x7F,0x08,0x14,0x22,0x41, // eng 'K' 89 | 0x7F,0x40,0x40,0x40,0x60, // eng 'L' 90 | 0x7F,0x02,0x0C,0x02,0x7F, // eng 'M' 91 | 0x7F,0x04,0x08,0x10,0x7F, // eng 'N' 92 | 0x3E,0x41,0x41,0x41,0x3E, // eng 'O' 93 | 0x7F,0x09,0x09,0x09,0x06, // eng 'P' 94 | 0x3E,0x41,0x51,0x21,0x5E, // eng 'Q' 95 | 0x7F,0x09,0x19,0x29,0x46, // eng 'R' 96 | 0x46,0x49,0x49,0x49,0x31, // eng 'S' 97 | 0x03,0x01,0x7F,0x01,0x03, // eng 'T' 98 | 0x3F,0x40,0x40,0x40,0x3F, // eng 'U' 99 | 0x1F,0x20,0x40,0x20,0x1F, // eng 'V' 100 | 0x3F,0x40,0x3C,0x40,0x3F, // eng 'W' 101 | 0x63,0x14,0x08,0x14,0x63, // eng 'X' 102 | 0x07,0x08,0x70,0x08,0x07, // eng 'Y' 103 | 0x61,0x51,0x49,0x45,0x43, // eng 'Z' 104 | 0x00,0x7F,0x41,0x41,0x00, // symbol '[' 105 | 0x02,0x04,0x08,0x10,0x20, // symbol '\' 106 | 0x00,0x41,0x41,0x7F,0x00, // symbol ']' 107 | 0x04,0x02,0x01,0x02,0x04, // symbol '^' 108 | 0x40,0x40,0x40,0x40,0x40, // symbol '_' 109 | 0x00,0x01,0x02,0x04,0x00, // symbol '`' 110 | 0x20,0x54,0x54,0x54,0x78, // eng 'a' 111 | 0x7F,0x48,0x44,0x44,0x38, // eng 'b' 112 | 0x38,0x44,0x44,0x44,0x48, // eng 'c' 113 | 0x38,0x44,0x44,0x48,0x7F, // eng 'd' 114 | 0x38,0x54,0x54,0x54,0x18, // eng 'e' 115 | 0x08,0x7E,0x09,0x01,0x02, // eng 'f' 116 | 0x08,0x54,0x54,0x58,0x3C, // eng 'g' 117 | 0x7F,0x08,0x04,0x04,0x78, // eng 'h' 118 | 0x00,0x44,0x7D,0x40,0x00, // eng 'i' 119 | 0x20,0x40,0x44,0x3D,0x00, // eng 'j' 120 | 0x7F,0x10,0x10,0x28,0x44, // eng 'k' 121 | 0x00,0x41,0x7F,0x40,0x00, // eng 'l' 122 | 0x7C,0x04,0x78,0x04,0x78, // eng 'm' 123 | 0x7C,0x08,0x04,0x04,0x78, // eng 'n' 124 | 0x38,0x44,0x44,0x44,0x38, // eng 'o' 125 | 0x7C,0x14,0x14,0x14,0x08, // eng 'p' 126 | 0x08,0x14,0x14,0x0C,0x7C, // eng 'q' 127 | 0x7C,0x08,0x04,0x04,0x08, // eng 'r' 128 | 0x48,0x54,0x54,0x54,0x24, // eng 's' 129 | 0x04,0x3F,0x44,0x40,0x20, // eng 't' 130 | 0x3C,0x40,0x40,0x20,0x7C, // eng 'u' 131 | 0x1C,0x20,0x40,0x20,0x1C, // eng 'v' 132 | 0x3C,0x40,0x38,0x40,0x3C, // eng 'w' 133 | 0x44,0x28,0x10,0x28,0x44, // eng 'x' 134 | 0x0C,0x50,0x50,0x50,0x3C, // eng 'y' 135 | 0x44,0x64,0x54,0x4C,0x44, // eng 'z' 136 | 0x00,0x08,0x36,0x41,0x00, // symbol '{' 137 | 0x00,0x00,0x7F,0x00,0x00, // symbol '|' 138 | 0x00,0x41,0x36,0x08,0x00, // symbol '}' 139 | 0x02,0x01,0x02,0x04,0x02, // symbol '~' 140 | 0x70,0x48,0x44,0x48,0x70, // DEL 141 | 0x00,0x0E,0x11,0x0E,0x00, // symbol '-' 142 | 0x00,0x12,0x1F,0x10,0x00, // symbol '¦' 143 | 0x00,0x12,0x19,0x16,0x00, // symbol '-' 144 | 0x00,0x11,0x15,0x0B,0x00, // symbol '¬' 145 | 0x00,0x07,0x04,0x1F,0x00, // symbol 'L' 146 | 0x00,0x17,0x15,0x09,0x00, // symbol '-' 147 | 0x00,0x0E,0x15,0x09,0x00, // symbol '+' 148 | 0x00,0x01,0x1D,0x03,0x00, // symbol '+' 149 | 0x00,0x0A,0x15,0x0A,0x00, // symbol 'T' 150 | 0x00,0x12,0x15,0x0E,0x00, // symbol '+' 151 | 0x00,0x04,0x04,0x04,0x00, // symbol '+' 152 | 0x7F,0x7F,0x7F,0x7F,0x7F, // symbol '-' 153 | 0x3E,0x00,0x00,0x00,0x00, // symbol '-' 154 | 0x3E,0x3E,0x00,0x00,0x00, // symbol '-' 155 | 0x3E,0x3E,0x00,0x3E,0x00, // symbol '¦' 156 | 0x3E,0x3E,0x00,0x3E,0x3E, // symbol '¦' 157 | 0x00,0x01,0x02,0x04,0x08, // symbol '-' 158 | 0x40,0x01,0x03,0x06,0x0C, // symbol '-' 159 | 0x50,0x21,0x43,0x06,0x0D, // symbol '-' 160 | 0x58,0x31,0x63,0x46,0x0D, // symbol '¦' 161 | 0x5A,0x35,0x6B,0x56,0x2D, // symbol 162 | 0x5B,0x37,0x6F,0x5E,0x3D, // symbol '•' 163 | 0x40,0x00,0x40,0x00,0x40, // symbol 'v' 164 | 0x60,0x00,0x40,0x00,0x40, // symbol '¦' 165 | 0x60,0x00,0x70,0x00,0x40, // symbol '-' 166 | 0x60,0x00,0x70,0x00,0x78, // symbol 'г' 167 | 0x7C,0x00,0x40,0x00,0x40, // symbol 'L' 168 | 0x7C,0x00,0x7E,0x00,0x40, // symbol '¦' 169 | 0x7C,0x00,0x7E,0x00,0x7F, // symbol 'T' 170 | 0x1C,0x77,0x41,0x41,0x41, // symbol 'T' 171 | 0x41,0x41,0x41,0x41,0x41, // symbol '¦' 172 | 0x41,0x41,0x41,0x7F,0x00, // symbol '¦' 173 | 0x1C,0x77,0x41,0x5D,0x5D, // symbol '=' 174 | 0x41,0x41,0x41,0x5D,0x5D, // symbol 'Ў' 175 | 0x5D,0x5D,0x41,0x5D,0x5D, // symbol 'ў' 176 | 0x5D,0x5D,0x41,0x7F,0x00, // symbol '¬' 177 | 0x22,0x1C,0x14,0x1C,0x22, // symbol '¤' 178 | 0x00,0x08,0x1C,0x08,0x00, // symbol 'г' 179 | 0x00,0x00,0x77,0x00,0x00, // symbol '¬' 180 | 0x46,0x5D,0x55,0x5D,0x31, // symbol '¬' 181 | 0x7C,0x55,0x54,0x55,0x44, // rus 'Ё' 182 | 0x08,0x08,0x2A,0x08,0x08, // symbol 'L' 183 | 0x00,0x14,0x08,0x14,0x00, // symbol 'Є' 184 | 0x08,0x14,0x22,0x08,0x14, // symbol 'L' 185 | 0x7F,0x41,0x71,0x31,0x1F, // symbol '-' 186 | 0x03,0x05,0x7F,0x05,0x03, // symbol '-' 187 | 0x22,0x14,0x7F,0x55,0x22, // symbol '-' 188 | 0x02,0x55,0x7D,0x05,0x02, // symbol 'Ї' 189 | 0x06,0x09,0x09,0x06,0x00, // symbol '°' 190 | 0x44,0x44,0x5F,0x44,0x44, // symbol '¦' 191 | 0x1C,0x14,0x1C,0x22,0x7F, // symbol '¦' 192 | 0x20,0x3E,0x61,0x3E,0x20, // symbol '¦' 193 | 0x20,0x50,0x3F,0x02,0x0C, // symbol '¦' 194 | 0x00,0x79,0x41,0x78,0x00, // symbol '¦' 195 | 0x44,0x3C,0x04,0x7C,0x44, // symbol 'T' 196 | 0x00,0x00,0x08,0x00,0x00, // symbol '·' 197 | 0x38,0x55,0x54,0x55,0x18, // rus 'ё' 198 | 0x7E,0x08,0x10,0x7F,0x01, // symbol '№' 199 | 0x08,0x10,0x08,0x04,0x02, // symbol 'є' 200 | 0x14,0x08,0x22,0x14,0x08, // symbol '¦' 201 | 0x0E,0x06,0x0A,0x10,0x20, // symbol '+' 202 | 0x20,0x10,0x0A,0x06,0x0E, // symbol '+' 203 | 0x38,0x30,0x28,0x04,0x02, // symbol '+' 204 | 0x02,0x04,0x28,0x30,0x38, // symbol 'ї' 205 | 0x7E,0x11,0x11,0x11,0x7E, // rus 'А' 206 | 0x7F,0x49,0x49,0x49,0x31, // rus 'Б' 207 | 0x7F,0x49,0x49,0x49,0x36, // rus 'В' 208 | 0x7F,0x01,0x01,0x01,0x03, // rus 'Г' 209 | 0x40,0x7F,0x03,0x7F,0x01, // rus 'Д' 210 | 0x7F,0x49,0x49,0x49,0x41, // rus 'Е' 211 | 0x77,0x08,0x7F,0x08,0x77, // rus 'Ж' 212 | 0x41,0x49,0x49,0x49,0x36, // rus 'З' 213 | 0x7F,0x10,0x08,0x04,0x7F, // rus 'И' 214 | 0x7C,0x21,0x12,0x09,0x7C, // rus 'Й' 215 | 0x7F,0x08,0x14,0x22,0x41, // rus 'К' 216 | 0x40,0x3E,0x01,0x01,0x7F, // rus 'Л' 217 | 0x7F,0x02,0x0C,0x02,0x7F, // rus 'М' 218 | 0x7F,0x08,0x08,0x08,0x7F, // rus 'Н' 219 | 0x3E,0x41,0x41,0x41,0x3E, // rus 'О' 220 | 0x7F,0x01,0x01,0x01,0x7F, // rus 'П' 221 | 0x7F,0x09,0x09,0x09,0x06, // rus 'Р' 222 | 0x3E,0x41,0x41,0x41,0x22, // rus 'С' 223 | 0x01,0x01,0x7F,0x01,0x01, // rus 'Т' 224 | 0x07,0x48,0x48,0x48,0x3F, // rus 'У' 225 | 0x0E,0x11,0x7F,0x11,0x0E, // rus 'Ф' 226 | 0x63,0x14,0x08,0x14,0x63, // rus 'Х' 227 | 0x7F,0x40,0x40,0x7F,0x40, // rus 'Ц' 228 | 0x07,0x08,0x08,0x08,0x7F, // rus 'Ч' 229 | 0x7F,0x40,0x7F,0x40,0x7F, // rus 'Ш' 230 | 0x7F,0x40,0x7F,0x40,0x7F, // rus 'Щ' 231 | 0x01,0x7F,0x48,0x48,0x30, // rus 'Ъ' 232 | 0x7F,0x48,0x48,0x30,0x7F, // rus 'Ы' 233 | 0x7F,0x48,0x48,0x48,0x30, // rus 'Ь' 234 | 0x22,0x41,0x49,0x49,0x3E, // rus 'Э' 235 | 0x7F,0x08,0x3E,0x41,0x3E, // rus 'Ю' 236 | 0x46,0x29,0x19,0x09,0x7F, // rus 'Я' 237 | 0x20,0x54,0x54,0x54,0x78, // rus 'а' 238 | 0x3C,0x4A,0x4A,0x49,0x31, // rus 'б' 239 | 0x7C,0x54,0x54,0x54,0x28, // rus 'в' 240 | 0x7C,0x04,0x04,0x04,0x0C, // rus 'г' 241 | 0x40,0x71,0x09,0x79,0x01, // rus 'д' 242 | 0x38,0x54,0x54,0x54,0x18, // rus 'е' 243 | 0x6C,0x10,0x7C,0x10,0x6C, // rus 'ж' 244 | 0x44,0x54,0x54,0x54,0x28, // rus 'з' 245 | 0x7C,0x20,0x10,0x08,0x7C, // rus 'и' 246 | 0x7C,0x40,0x26,0x10,0x7C, // rus 'й' 247 | 0x7C,0x10,0x10,0x28,0x44, // rus 'к' 248 | 0x40,0x38,0x04,0x04,0x7C, // rus 'л' 249 | 0x7C,0x08,0x10,0x08,0x7C, // rus 'м' 250 | 0x7C,0x10,0x10,0x10,0x7C, // rus 'н' 251 | 0x38,0x44,0x44,0x44,0x38, // rus 'о' 252 | 0x7C,0x04,0x04,0x04,0x7C, // rus 'п' 253 | 0x7C,0x14,0x14,0x14,0x08, // rus 'р' 254 | 0x38,0x44,0x44,0x44,0x48, // rus 'с' 255 | 0x04,0x04,0x7C,0x04,0x04, // rus 'т' 256 | 0x0C,0x50,0x50,0x50,0x3C, // rus 'у' 257 | 0x18,0x24,0x7C,0x49,0x30, // rus 'ф' 258 | 0x44,0x28,0x10,0x28,0x44, // rus 'х' 259 | 0x7C,0x40,0x40,0x7C,0x40, // rus 'ц' 260 | 0x0C,0x10,0x10,0x10,0x7C, // rus 'ч' 261 | 0x7C,0x40,0x7C,0x40,0x7C, // rus 'ш' 262 | 0x7C,0x40,0x7C,0x40,0x7C, // rus 'щ' 263 | 0x04,0x7C,0x50,0x50,0x20, // rus 'ъ' 264 | 0x7C,0x50,0x50,0x20,0x7C, // rus 'ы' 265 | 0x7C,0x50,0x50,0x50,0x20, // rus 'ь' 266 | 0x28,0x44,0x54,0x54,0x38, // rus 'э' 267 | 0x7C,0x10,0x38,0x44,0x38, // rus 'ю' 268 | 0x48,0x34,0x14,0x14,0x7C // rus 'я' 269 | }; 270 | 271 | -------------------------------------------------------------------------------- /keyboard.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "settings.h" 3 | 4 | void geti2cAdress(){ 5 | uint8_t error,address; 6 | i2c_adress=0; 7 | for(address = 1; address < 127; address++ ){ 8 | Wire.beginTransmission(address); 9 | error = Wire.endTransmission(); 10 | if (error == 0){ 11 | i2c_adress=address; 12 | return; 13 | } 14 | yield(); 15 | } 16 | } 17 | 18 | void scani2c(){ 19 | uint8_t error, address; 20 | int nDevices; 21 | nDevices = 0; 22 | for(address = 1; address < 127; address++ ){ 23 | Wire.beginTransmission(address); 24 | error = Wire.endTransmission(); 25 | if (error == 0){ 26 | Serial.print(F("I2C device found at address 0x")); 27 | if (address<16) 28 | Serial.print(F("0")); 29 | Serial.print(address,HEX); 30 | Serial.println(F(" !")); 31 | nDevices++; 32 | } 33 | else if (error==4){ 34 | Serial.print(F("Unknown error at address 0x")); 35 | if (address<16) 36 | Serial.print(F("0")); 37 | Serial.println(address,HEX); 38 | } 39 | } 40 | if (nDevices == 0) 41 | Serial.println(F("No I2C devices found\n")); 42 | } 43 | 44 | #ifdef ESPBOY 45 | void getKey(){ 46 | uint8_t keyread; 47 | thiskey = 0; 48 | keyread = mcp.readGPIOAB()&255; 49 | if(!(keyread&1)) thiskey |= 4; 50 | if(!(keyread&2)) thiskey |= 1; 51 | if(!(keyread&4)) thiskey |= 2; 52 | if(!(keyread&8)) thiskey |= 8; 53 | if(!(keyread&16)) thiskey |= 16; 54 | if(!(keyread&32)) thiskey |= 32; 55 | if(!(keyread&64)) thiskey |= 64; 56 | if(!(keyread&128)) thiskey |= 128; 57 | } 58 | #else 59 | void getKey(){ 60 | uint8_t dio_in; 61 | Wire.beginTransmission(i2c_adress); 62 | Wire.write(B11111111); //Конфигурация всех портов PCF8574P на клавиатуре как входа 63 | Wire.endTransmission(); 64 | Wire.requestFrom(i2c_adress,1); 65 | dio_in = Wire.read(); //читаем состояние портов PCF8574P(кнопок) 66 | thiskey = 0; 67 | if((dio_in & 128) == 0) 68 | thiskey |= 4; 69 | if((dio_in & 64) == 0) 70 | thiskey |= 8; 71 | if((dio_in & 32) == 0) 72 | thiskey |= 2; 73 | if((dio_in & 16) == 0) 74 | thiskey |= 1; //up 75 | if((dio_in & 8) == 0) 76 | thiskey |= 128; 77 | if((dio_in & 4) == 0) 78 | thiskey |= 32; 79 | if((dio_in & 2) == 0) 80 | thiskey |= 16; 81 | if((dio_in & 1) == 0) 82 | thiskey |= 64; 83 | } 84 | #endif 85 | 86 | const uint8_t v_keys[] PROGMEM = "0123456789[]qwertyuiop\"/asdfghjkl;= zxcvbnm,.- "; 87 | const uint8_t v_keysShift[] PROGMEM = "!@#$%^&*(){}QWERTYUIOP|?ASDFGHJKL:+ ZXCVBNM<>_ "; 88 | 89 | uint8_t virtualKeyboard(uint8_t kx, uint8_t ky, char buf[], uint8_t len){ 90 | int16_t x = 4, y = 4, px = 0, py = 0, pos = 0; 91 | uint8_t isShift = 0; 92 | TFT_eSprite img = TFT_eSprite(&tft); 93 | img.setColorDepth(1); 94 | img.createSprite(120, 32); 95 | img.setTextSize(2); 96 | tft.fillRect(kx, ky, 124, 48, 0x0000); 97 | tft.drawRect(kx, ky, 124, 48, 0xFC00); 98 | getKey(); 99 | while(1){ 100 | while(x != px * 16 || y != py * 16){ 101 | if(x < px * 16) 102 | x += 4; 103 | else if(x > px * 16) 104 | x -= 4; 105 | if(y < py * 16) 106 | y += 4; 107 | else if(y > py * 16) 108 | y -= 4; 109 | img.fillRect(0, 0, 120, 32, 0x0000); 110 | for(uint8_t i = 0; i < 4; i++){ 111 | for(uint8_t j = 0; j < 12; j++){ 112 | if(i == 3 && j == 11){ 113 | img.setTextSize(1); 114 | img.drawChar('D', 56 + j * 16 - x - 4, i * 16 - y + 4); 115 | img.drawChar('e', 56 + j * 16 - x + 2, i * 16 - y + 4); 116 | img.drawChar('l', 56 + j * 16 - x + 8, i * 16 - y + 4); 117 | img.setTextSize(2); 118 | } 119 | else if(i == 2 && j == 11){ 120 | img.setTextSize(1); 121 | img.drawChar('E', 56 + j * 16 - x - 4, i * 16 - y); 122 | img.drawChar('n', 56 + j * 16 - x + 2, i * 16 - y); 123 | img.drawChar('t', 56 + j * 16 - x - 4, i * 16 - y + 8); 124 | img.drawChar('e', 56 + j * 16 - x + 2, i * 16 - y + 8); 125 | img.drawChar('r', 56 + j * 16 - x + 8, i * 16 - y + 8); 126 | img.setTextSize(2); 127 | } 128 | else{ 129 | if(isShift) 130 | img.drawChar(pgm_read_byte(&v_keysShift[i * 12 + j]), 56 + j * 16 - x, i * 16 - y); 131 | else 132 | img.drawChar(pgm_read_byte(&v_keys[i * 12 + j]), 56 + j * 16 - x, i * 16 - y); 133 | } 134 | } 135 | } 136 | img.pushSprite(kx + 2, ky + 14); 137 | tft.drawRect(kx + 53, ky + 13, 18, 17, 0xFC00); 138 | delay(10); 139 | } 140 | delay(200); 141 | #ifdef ESPBOY 142 | if (keybModule.getPressedKey()){ 143 | if((char)keybModule.getLastPressedKey() == '>'){ 144 | img.deleteSprite(); 145 | if(pos + 1 < len){ 146 | buf[pos] = '\n'; 147 | pos++; 148 | } 149 | return pos; 150 | } 151 | if((char)keybModule.getLastPressedKey() == '<'){ 152 | if(pos > 0){ 153 | buf[pos] = 0; 154 | pos--; 155 | } 156 | } 157 | else{ 158 | if(pos < len){ 159 | buf[pos] = (char)keybModule.getLastPressedKey(); 160 | pos++; 161 | } 162 | } 163 | tft.fillRect(kx + 1, ky + 1, 122, 10, 0x0000); 164 | tft.setCursor(kx + 4,ky + 3); 165 | for(int i = max(0, pos - 10); i < pos; i++) 166 | tft.print(buf[i]); 167 | tft.setTextColor(0x6d2d); 168 | tft.setCursor(kx + 100 - ((pos > 9) ? ((pos > 99)? 12: 6) : 0) - ((len > 9) ? ((len > 99)? 12: 6) : 0), ky + 3); 169 | tft.print(pos); 170 | tft.print('/'); 171 | tft.print(len); 172 | tft.setTextColor(0xffff); 173 | } 174 | #endif 175 | getKey(); 176 | if(thiskey == 192){ //key select + start 177 | if(pause()) 178 | return 0; 179 | } 180 | if(thiskey & 2){//down 181 | if(py < 3) 182 | py++; 183 | else 184 | py = 0; 185 | } 186 | else if(thiskey & 1){//up 187 | if(py > 0) 188 | py--; 189 | else 190 | py = 3; 191 | } 192 | else if(thiskey & 8){//left 193 | if(px < 11) 194 | px++; 195 | else 196 | px = 0; 197 | } 198 | else if(thiskey & 4){//right 199 | if(px > 0) 200 | px--; 201 | else 202 | px = 11; 203 | } 204 | else if(thiskey & 16){//ok 205 | if(py == 3 && px == 11){//delete 206 | if(pos > 0){ 207 | buf[pos] = 0; 208 | pos--; 209 | } 210 | tft.fillRect(kx + 1, ky + 1, 122, 10, 0x0000); 211 | tft.setCursor(kx + 4,ky + 3); 212 | for(int i = max(0, pos - 10); i < pos; i++) 213 | tft.print(buf[i]); 214 | tft.setTextColor(0x6d2d); 215 | tft.setCursor(kx + 100 - ((pos > 9) ? ((pos > 99)? 12: 6) : 0) - ((len > 9) ? ((len > 99)? 12: 6) : 0), ky + 3); 216 | tft.print(pos); 217 | tft.print('/'); 218 | tft.print(len); 219 | tft.setTextColor(0xffff); 220 | delay(200); 221 | } 222 | else if(py == 2 && px == 11){ 223 | img.deleteSprite(); 224 | if(pos + 1 < len){ 225 | buf[pos] = '\n'; 226 | pos++; 227 | } 228 | return pos; 229 | } 230 | else{ 231 | if(pos < len){ 232 | if(isShift) 233 | buf[pos] = pgm_read_byte(&v_keysShift[px + py * 12]); 234 | else 235 | buf[pos] = pgm_read_byte(&v_keys[px + py * 12]); 236 | tft.fillRect(kx + 1, ky + 1, 122, 10, 0x0000); 237 | tft.setCursor(kx + 4,ky + 3); 238 | pos++; 239 | for(int i = max(0, pos - 10); i < pos; i++) 240 | tft.print(buf[i]); 241 | tft.setTextColor(0x6d2d); 242 | tft.setCursor(kx + 100 - ((pos > 9) ? ((pos > 99)? 12: 6) : 0) - ((len > 9) ? ((len > 99)? 12: 6) : 0), ky + 3); 243 | tft.print(pos); 244 | tft.print('/'); 245 | tft.print(len); 246 | tft.setTextColor(0xffff); 247 | } 248 | } 249 | } 250 | else if(thiskey & 32){//shift 251 | isShift = 1 - isShift; 252 | x += 4; 253 | } 254 | } 255 | return 0; 256 | } 257 | -------------------------------------------------------------------------------- /lge_memory.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "settings.h" 3 | 4 | uint8_t *lge_mem __attribute__ ((aligned)); 5 | 6 | void memoryAlloc(){ 7 | lge_mem = (uint8_t*)malloc(RAM_SIZE * sizeof(uint8_t)); 8 | if(lge_mem == NULL) 9 | Serial.println(F("Out of memory")); 10 | screenMemoryAlloc(); 11 | } 12 | 13 | void memoryFree(){ 14 | screenMemoryFree(); 15 | free(lge_mem); 16 | } 17 | 18 | inline void writeMem(uint16_t adr, int16_t n){ 19 | if(adr < RAM_SIZE) 20 | lge_mem[adr] = n; 21 | } 22 | 23 | inline uint8_t readMem(uint16_t adr){ 24 | return (adr < RAM_SIZE) ? lge_mem[adr] : 0; 25 | } 26 | 27 | inline void writeInt(uint16_t adr, int16_t n){ 28 | int8_t *nPtr; 29 | if(adr < RAM_SIZE - 1){ 30 | nPtr = (int8_t*)&n; 31 | lge_mem[adr++] = *nPtr; 32 | nPtr++; 33 | lge_mem[adr] = *nPtr; 34 | } 35 | } 36 | 37 | inline int16_t readInt(uint16_t adr){ 38 | int16_t n; 39 | int8_t *nPtr; 40 | if(adr < RAM_SIZE - 1){ 41 | nPtr = (int8_t*)&n; 42 | *nPtr = lge_mem[adr++]; 43 | nPtr++; 44 | *nPtr = lge_mem[adr]; 45 | return n; 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /lib/ESPboyLED.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ESPboy LED class 3 | for www.ESPboy.com project by RomanS 4 | */ 5 | 6 | #include "ESPboyLED.h" 7 | 8 | 9 | void ESPboyLED::begin(Adafruit_MCP23017 *mcpGUI){ 10 | mcp = mcpGUI; 11 | pinMode(LEDPIN, OUTPUT); 12 | mcp->pinMode(LEDLOCK, OUTPUT); 13 | LEDflagOnOff = 1; 14 | LEDr = 0; 15 | LEDg = 0; 16 | LEDb = 0; 17 | ledset(LEDr, LEDg, LEDb); 18 | } 19 | 20 | 21 | void ESPboyLED::off(){ 22 | LEDflagOnOff = 0; 23 | ledset(0, 0, 0); 24 | } 25 | 26 | 27 | void ESPboyLED::on(){ 28 | LEDflagOnOff = 1; 29 | ledset(LEDr, LEDg, LEDb); 30 | } 31 | 32 | 33 | uint8_t ESPboyLED::getState(){ 34 | return (LEDflagOnOff); 35 | } 36 | 37 | void ESPboyLED::setRGB (uint8_t red, uint8_t green, uint8_t blue){ 38 | LEDr = red; 39 | LEDg = green; 40 | LEDb = blue; 41 | if (LEDflagOnOff) ledset(LEDr, LEDg, LEDb); 42 | } 43 | 44 | 45 | void ESPboyLED::setR (uint8_t red){ 46 | LEDr = red; 47 | if (LEDflagOnOff) ledset(LEDr, LEDg, LEDb); 48 | } 49 | 50 | 51 | void ESPboyLED::setG (uint8_t green){ 52 | LEDg = green; 53 | if (LEDflagOnOff) ledset(LEDr, LEDg, LEDb); 54 | } 55 | 56 | 57 | void ESPboyLED::setB (uint8_t blue){ 58 | LEDb = blue; 59 | if (LEDflagOnOff) ledset(LEDr, LEDg, LEDb); 60 | } 61 | 62 | 63 | uint32_t ESPboyLED::getRGB(){ 64 | return (((uint32_t)LEDb<<16) + ((uint32_t)LEDg<<8) + ((uint32_t)LEDr) ); 65 | } 66 | 67 | 68 | uint8_t ESPboyLED::getR(){ 69 | return (LEDr); 70 | } 71 | 72 | 73 | uint8_t ESPboyLED::getG(){ 74 | return (LEDg); 75 | } 76 | 77 | 78 | uint8_t ESPboyLED::getB(){ 79 | return (LEDb); 80 | } 81 | 82 | 83 | void ICACHE_RAM_ATTR ESPboyLED::ledset(uint8_t rled, uint8_t gled, uint8_t bled) { 84 | static uint_fast32_t i, t, c, startTime, pixel, mask, t0h, t1h, ttot; 85 | static uint8_t cpuFreq; 86 | static const uint32_t pinMask = 1<digitalWrite(LEDLOCK, HIGH); 93 | 94 | cpuFreq = ESP.getCpuFreqMHz()/80; 95 | t0h = 32*cpuFreq; // 0.4us 96 | t1h = 64*cpuFreq; // 0.8us 97 | ttot = 100*cpuFreq; // 1.25us 98 | 99 | pixel = (gled<<16) + (rled<<8) + bled; 100 | mask = 0x800000; 101 | startTime = 0; 102 | os_intr_lock(); 103 | for (i=0; i<24; i++){ 104 | if (pixel & mask) t = t1h; 105 | else t = t0h; 106 | while (((c=ESP.getCycleCount()) - startTime) < ttot);// Wait for the previous bit to finish 107 | GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // digitalWrite HIGH 108 | startTime = c; 109 | while (((c=ESP.getCycleCount()) - startTime) < t); // Wait for high time to finish 110 | GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // digitalWrite LOW 111 | mask>>=1; 112 | } 113 | os_intr_unlock(); 114 | delay(1); 115 | GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); 116 | 117 | mcp->digitalWrite(LEDLOCK, LOW); 118 | } 119 | -------------------------------------------------------------------------------- /lib/ESPboyLED.h: -------------------------------------------------------------------------------- 1 | /* 2 | ESPboy LED class 3 | for www.ESPboy.com project by RomanS 4 | */ 5 | 6 | #include 7 | #include //to control LED lock 8 | 9 | #ifndef ESPboy_LED 10 | #define ESPboy_LED 11 | 12 | #define LEDPIN D4 13 | #define LEDLOCK 9 14 | 15 | class ESPboyLED{ 16 | private: 17 | Adafruit_MCP23017 *mcp; 18 | uint8_t LEDr, LEDg, LEDb, LEDflagOnOff; 19 | void ledset(uint8_t rled, uint8_t gled, uint8_t bled); 20 | 21 | public: 22 | void begin(Adafruit_MCP23017 *mcpGUI); 23 | void off(); 24 | void on(); 25 | uint8_t getState(); 26 | 27 | void setRGB (uint8_t red, uint8_t green, uint8_t blue); 28 | void setR (uint8_t red); 29 | void setG (uint8_t green); 30 | void setB (uint8_t blue); 31 | 32 | uint32_t getRGB(); 33 | uint8_t getR(); 34 | uint8_t getG(); 35 | uint8_t getB(); 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /lib/ESPboy_keyboard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ESPboy keyboard module class 3 | for www.ESPboy.com project by RomanS 4 | thanks to Plague for help with coding 5 | */ 6 | 7 | #include "ESPboy_keyboard.h" 8 | 9 | constexpr wchar_t keybCurrent[maxKeyboardLayouts][maxKeyboardRows][maxKeyboardCols + 1] PROGMEM = { 10 | {L"qeruo", L"wsghl", L"|dtyi", L"ap~><", L" zcnm", L"^xvb&", L"`~fjk"}, 11 | {L"QERUO", L"WSGHL", L"|DTYI", L"AP~><", L" ZCNM", L"^XVB$", L"`~FJK"}, 12 | {L"#23_+", L"14/:\"", L"|5()-", L"*@~><", L" 79,.", L"^8?!%", L"0~6;'"} 13 | }; 14 | 15 | 16 | keyboardModule::keyboardModule(uint8_t clickState, uint8_t backlitState, uint32_t bckltOffdelay){ 17 | currentLayout = keybNorm; 18 | clickFlag = clickState; 19 | backlitFlag = backlitState; 20 | backlitOffDelay = bckltOffdelay; 21 | autoBacklitOffFlag = 0; 22 | backlitOnTimer = millis(); 23 | } 24 | 25 | 26 | uint8_t keyboardModule::begin(){ 27 | Wire.begin(); 28 | Wire.beginTransmission(0x27); //check for MCP23017 Keyboard module at address 0x27 29 | if (!Wire.endTransmission()) 30 | { 31 | initFlag = 1; 32 | mcpKeyboard.begin(7); 33 | for (uint8_t i = 0; i < 7; i++){ 34 | mcpKeyboard.pinMode(i, OUTPUT); 35 | mcpKeyboard.digitalWrite(i, HIGH);} 36 | for (uint8_t i = 0; i < 5; i++){ 37 | mcpKeyboard.pinMode(i+8, INPUT); 38 | mcpKeyboard.pullUp(i+8, HIGH);} 39 | mcpKeyboard.pinMode(7, OUTPUT); 40 | mcpKeyboard.digitalWrite(7, HIGH); 41 | setBacklitState(backlitFlag); 42 | } 43 | else initFlag = 0; 44 | return (initFlag); 45 | } 46 | 47 | 48 | uint8_t keyboardModule::getKeyboardAvailable(){ 49 | return(initFlag); 50 | } 51 | 52 | 53 | void keyboardModule::scanKeyboard(){ 54 | static uint8_t keysReaded[7]; 55 | static uint8_t row, col; 56 | for (row = 0; row < 7; row++){ 57 | mcpKeyboard.digitalWrite(row, LOW); 58 | keysReaded [row] = ((mcpKeyboard.readGPIOAB()>>8) & 31); 59 | mcpKeyboard.digitalWrite(row, HIGH); 60 | } 61 | for (row = 0; row < 7; row++) 62 | for (col = 0; col < 5; col++) 63 | if (!((keysReaded[row] >> col) & 1)){ 64 | rowKey = row; 65 | colKey = col; 66 | pressedKey = pgm_read_word_near(&keybCurrent[currentLayout][rowKey][colKey]); 67 | } 68 | } 69 | 70 | 71 | wchar_t keyboardModule::getPressedKey (){ 72 | if(initFlag){ 73 | pressedKey = 0; 74 | scanKeyboard(); 75 | if (backlitOffDelay && !autoBacklitOffFlag && millis() > backlitOnTimer + backlitOffDelay){ 76 | autoBacklitOffFlag = 1; 77 | mcpKeyboard.digitalWrite(7, LOW); 78 | } 79 | if (pressedKey){ 80 | backlitOnTimer = millis(); 81 | autoBacklitOffFlag = 0; 82 | setBacklitState(backlitFlag); 83 | } 84 | switch (pressedKey){ 85 | case '|': 86 | currentLayout++; 87 | if (currentLayout > maxKeyboardLayouts-1) currentLayout = 0; 88 | while (keysUnpressed()); 89 | break; 90 | case '~': 91 | while (pressedKey == '~') scanKeyboard(); 92 | if (currentLayout == keybNorm ) 93 | pressedKey = pgm_read_word_near(&keybCurrent[keybShift][rowKey][colKey]); 94 | if (currentLayout == keybShift) 95 | pressedKey = pgm_read_word_near(&keybCurrent[keybNorm][rowKey][colKey]); 96 | break; 97 | case '^': 98 | while (pressedKey == '^') scanKeyboard(); 99 | pressedKey = pgm_read_word_near(&keybCurrent[keybAlt][rowKey][colKey]); 100 | break; 101 | case '`': 102 | setBacklitState (!backlitFlag); 103 | while (keysUnpressed()); 104 | break; 105 | case '&': 106 | if (clickFlag == 1) clickFlag = 0; 107 | else clickFlag = 1; 108 | while (keysUnpressed()); 109 | break; 110 | } 111 | if (pressedKey && clickFlag) tone(SOUNDPIN, 200, 10); 112 | if (pressedKey == '|' || pressedKey == '~' || pressedKey == '^' || pressedKey == '&' || pressedKey == '`') 113 | pressedKey = 0; 114 | return pressedKey; 115 | } 116 | else return (0); 117 | } 118 | 119 | 120 | uint8_t keyboardModule::keysUnpressed(){ 121 | static uint8_t keysPressed; 122 | static uint8_t row; 123 | keysPressed = 0; 124 | for (row = 0; row < 7; row++){ 125 | mcpKeyboard.digitalWrite(row, LOW); 126 | if ((mcpKeyboard.readGPIOAB() & 7936) != 7936) keysPressed++; 127 | mcpKeyboard.digitalWrite(row, HIGH); 128 | } 129 | yield(); 130 | return (keysPressed); 131 | } 132 | 133 | 134 | void keyboardModule::setBacklitState(uint8_t backlitState){ 135 | backlitFlag = backlitState; 136 | if (backlitFlag) mcpKeyboard.digitalWrite(7, HIGH); 137 | else mcpKeyboard.digitalWrite(7, LOW); 138 | } 139 | 140 | 141 | uint8_t keyboardModule::getLastPressedKeyRow(){ 142 | return (rowKey); 143 | } 144 | 145 | 146 | uint8_t keyboardModule::getLastPressedKeyCol(){ 147 | return (colKey); 148 | } 149 | 150 | 151 | wchar_t keyboardModule::getLastPressedKey(){ 152 | return (pressedKey); 153 | } 154 | 155 | 156 | uint8_t keyboardModule::getCurrentLayout(){ 157 | return(currentLayout); 158 | } 159 | 160 | uint8_t keyboardModule::getClickState(){ 161 | return(clickFlag); 162 | } 163 | 164 | void keyboardModule::setClickState(uint8_t clickState){ 165 | clickFlag = clickState; 166 | } 167 | 168 | uint8_t keyboardModule::getBacklitState(){ 169 | return(backlitFlag); 170 | } -------------------------------------------------------------------------------- /lib/ESPboy_keyboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | ESPboy keyboard module class 3 | for www.ESPboy.com project by RomanS 4 | thanks to Plague for help with coding 5 | COL0 COL1 COL2 COL3 COL4 6 | ROW0 Q E R U O 7 | ROW1 W S G H L 8 | ROW2 |sym D T Y I 9 | ROW3 A P ~sh2 >ent 16 | #include "Adafruit_MCP23017.h" 17 | 18 | #ifndef ESPboy_Keyboard 19 | #define ESPboy_Keyboard 20 | 21 | #define maxKeyboardLayouts 3 22 | #define maxKeyboardRows 7 23 | #define maxKeyboardCols 5 24 | 25 | #define SOUNDPIN D3 26 | 27 | 28 | class keyboardModule{ 29 | private: 30 | Adafruit_MCP23017 mcpKeyboard; 31 | enum keybLayouts {keybNorm = 0, keybShift, keybAlt}; 32 | wchar_t pressedKey; 33 | uint8_t initFlag, clickFlag, backlitFlag, rowKey, colKey, currentLayout, autoBacklitOffFlag; 34 | uint64_t backlitOnTimer; 35 | uint32_t backlitOffDelay; 36 | void scanKeyboard(); 37 | public: 38 | keyboardModule(uint8_t clickState, uint8_t backlitState, uint32_t bckltOffdelay); 39 | uint8_t begin(); 40 | uint8_t keysUnpressed(); 41 | uint8_t getLastPressedKeyRow(); 42 | uint8_t getLastPressedKeyCol(); 43 | uint8_t getCurrentLayout(); 44 | uint8_t getClickState(); 45 | void setClickState(uint8_t clickState); 46 | uint8_t getBacklitState(); 47 | void setBacklitState(uint8_t backlitState); 48 | wchar_t getPressedKey (); 49 | wchar_t getLastPressedKey(); 50 | uint8_t getKeyboardAvailable(); 51 | }; 52 | 53 | #endif -------------------------------------------------------------------------------- /libraries.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/libraries.7z -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corax89/esp8266_game_engine/d23560cd5a48cbbde90103b7eeb629a57df69844/logo.png -------------------------------------------------------------------------------- /rom.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #ifndef ROM_NAME 3 | #include "rom.h" 4 | #endif 5 | 6 | 7 | const uint8_t splashscreen[] PROGMEM = { 8 | 0x90,0x00,0x42,0x02,0x11,0x01,0xD4,0x21,0x01,0x01,0x3C,0x08,0x12,0x00,0x54,0x12,0x55,0x00,0xD0,0x00, 9 | 0x11,0x01,0x01,0x02,0x5C,0x02,0xD5,0x12,0x11,0x02,0x01,0x02,0x5C,0x03,0xD5,0x12,0x11,0x03,0x01,0x02, 10 | 0x5C,0x04,0xD5,0x12,0x11,0x04,0x01,0x02,0xFC,0x06,0xD5,0x12,0x11,0x05,0x01,0x02,0x5C,0x05,0xD5,0x12, 11 | 0x11,0x01,0x06,0x01,0x02,0x00,0x04,0x10,0x02,0x00,0x12,0x04,0xC1,0x12,0xC2,0x12,0xB1,0x00,0x92,0x00, 12 | 0x80,0x00,0x04,0x10,0x02,0x00,0x12,0x03,0x13,0x14,0xF1,0x23,0x04,0x10,0x02,0x00,0x12,0x04,0x13,0x10, 13 | 0xF1,0x23,0x04,0x10,0x02,0x00,0x12,0x05,0x13,0x20,0xF1,0x23,0x04,0x10,0x02,0x00,0x07,0x21,0xA8,0x02, 14 | 0x06,0x02,0x02,0x00,0x90,0x00,0x42,0x00,0x11,0x03,0x12,0x06,0x01,0x03,0x4A,0x01,0xF1,0x23,0x11,0x04, 15 | 0x12,0x02,0x13,0x14,0xF1,0x23,0x11,0x04,0x12,0x04,0x13,0x14,0xF1,0x23,0x11,0x04,0x12,0x05,0x13,0x20, 16 | 0xF1,0x23,0x11,0x05,0x12,0x03,0x13,0x14,0xF1,0x23,0x11,0x05,0x12,0x04,0x13,0x1A,0xF1,0x23,0x11,0x05, 17 | 0x12,0x05,0x13,0x20,0xF1,0x23,0x11,0x01,0x12,0x14,0x01,0x03,0xE0,0xFF,0xE1,0x23,0x11,0x02,0x12,0x36, 18 | 0x01,0x03,0xE0,0xFF,0xE1,0x23,0x11,0x05,0x12,0x54,0x01,0x03,0xE0,0xFF,0xE1,0x23,0x11,0x01,0x12,0x01, 19 | 0xDC,0x12,0x12,0x40,0xC1,0x12,0xC2,0x12,0xB1,0x00,0x92,0x00,0xEE,0x00,0x90,0x00,0xD8,0x00,0x11,0x01, 20 | 0x06,0x01,0x02,0x00,0x04,0x10,0x02,0x00,0x12,0x04,0xC1,0x12,0xC2,0x12,0xB1,0x00,0x92,0x00,0x20,0x01, 21 | 0x04,0x10,0x02,0x00,0x12,0x03,0x01,0x03,0xF6,0xFF,0xF1,0x23,0x04,0x10,0x02,0x00,0x07,0x21,0xA8,0x02, 22 | 0x06,0x02,0x02,0x00,0x90,0x00,0xF4,0x00,0x11,0x03,0x12,0x5A,0x13,0x01,0x14,0x01,0xDC,0x34,0xE1,0x23, 23 | 0x11,0x05,0x12,0x07,0x13,0x00,0xF1,0x23,0x11,0x03,0x12,0x06,0x01,0x03,0x50,0x01,0xF1,0x23,0x99,0x00, 24 | 0x52,0x02,0x99,0x00,0x52,0x02,0x11,0x03,0x12,0x06,0x01,0x03,0x52,0x01,0xF1,0x23,0x99,0x00,0x52,0x02, 25 | 0x99,0x00,0x52,0x02,0x11,0x03,0x12,0x06,0x01,0x03,0x56,0x01,0xF1,0x23,0x99,0x00,0x52,0x02,0x99,0x00, 26 | 0x52,0x02,0x11,0x03,0x12,0x06,0x01,0x03,0x5E,0x01,0xF1,0x23,0x99,0x00,0x52,0x02,0x99,0x00,0x52,0x02, 27 | 0x11,0x03,0x12,0x06,0x13,0x00,0xF1,0x23,0x99,0x00,0x52,0x02,0x11,0x01,0x12,0x01,0xDC,0x12,0x12,0x30, 28 | 0xC1,0x12,0xC2,0x13,0xB1,0x00,0x92,0x00,0x9E,0x01,0x90,0x00,0x88,0x01,0x11,0x01,0x06,0x01,0x02,0x00, 29 | 0x04,0x10,0x02,0x00,0x12,0x04,0xC1,0x12,0xC2,0x12,0xB1,0x00,0x92,0x00,0xCE,0x01,0x04,0x10,0x02,0x00, 30 | 0x12,0x03,0x13,0x00,0xF1,0x23,0x04,0x10,0x02,0x00,0x07,0x21,0xA8,0x02,0x06,0x02,0x02,0x00,0x90,0x00, 31 | 0xA4,0x01,0x11,0x04,0x12,0x00,0x13,0x01,0x14,0x01,0xDC,0x34,0xE1,0x23,0x11,0x04,0x12,0x00,0xDC,0x12, 32 | 0x12,0x80,0xC1,0x12,0xC2,0x12,0xB1,0x00,0x92,0x00,0xF0,0x01,0x90,0x00,0xDA,0x01,0x11,0x01,0x01,0x02, 33 | 0xE8,0x03,0x51,0x12,0x11,0x01,0x52,0x01,0xB1,0x00,0x92,0x00,0x06,0x02,0x90,0x00,0xF8,0x01,0x11,0x01, 34 | 0x06,0x01,0x02,0x00,0x04,0x10,0x02,0x00,0x12,0x05,0xC1,0x12,0xC2,0x12,0xB1,0x00,0x92,0x00,0x36,0x02, 35 | 0x04,0x10,0x02,0x00,0x12,0x07,0x13,0x00,0xF1,0x23,0x04,0x10,0x02,0x00,0x07,0x21,0xA8,0x02,0x06,0x02, 36 | 0x02,0x00,0x90,0x00,0x0C,0x02,0xD0,0x00,0x99,0x00,0x52,0x02,0x99,0x00,0x52,0x02,0x9A,0x00,0x01,0x0F, 37 | 0x00,0x00,0x06,0xF0,0x1D,0x09,0xA9,0x20,0x99,0x00,0x04,0x00,0x50,0x00,0xC2,0x16,0xB1,0x00,0x92,0x00, 38 | 0x52,0x02,0x9A,0x00,0x04,0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00, 39 | 0x42,0x22,0x44,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x44,0x00, 40 | 0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00, 41 | 0x42,0x22,0x44,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x44,0x00, 42 | 0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00, 43 | 0x42,0x22,0x44,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x44,0x00, 44 | 0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00, 45 | 0x42,0x22,0x44,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x44,0x00, 46 | 0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00, 47 | 0x42,0x22,0x44,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x44,0x00, 48 | 0x00,0x00,0x00,0x00,0x42,0x22,0x24,0x00,0x00,0x00,0x00,0x00,0x42,0x22,0x22,0x44,0x44,0x44,0x44,0x40, 49 | 0x42,0x22,0x22,0x22,0x22,0x22,0x24,0x24,0x42,0x22,0x22,0x22,0x22,0x22,0x22,0x44,0x42,0x22,0x22,0x22, 50 | 0x22,0x22,0x24,0x24,0x04,0x22,0x22,0x22,0x22,0x22,0x22,0x44,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x40, 51 | 0x06,0x66,0x66,0x66,0x66,0x66,0x66,0x60,0x63,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x63,0x33,0x33,0x33, 52 | 0x33,0x33,0x33,0x66,0x63,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x63,0x33,0x33,0x33,0x33,0x33,0x33,0x36, 53 | 0x63,0x33,0x36,0x66,0x66,0x63,0x33,0x36,0x63,0x33,0x36,0x00,0x00,0x63,0x33,0x36,0x63,0x33,0x66,0x00, 54 | 0x00,0x63,0x33,0x36,0x63,0x33,0x36,0x00,0x00,0x06,0x66,0x60,0x63,0x33,0x66,0x00,0x00,0x00,0x00,0x00, 55 | 0x63,0x33,0x36,0x00,0x00,0x00,0x00,0x00,0x63,0x33,0x36,0x00,0x00,0x00,0x00,0x00,0x63,0x33,0x66,0x00, 56 | 0x00,0x00,0x00,0x00,0x63,0x33,0x36,0x00,0x00,0x00,0x00,0x00,0x63,0x33,0x66,0x00,0x00,0x00,0x00,0x00, 57 | 0x63,0x33,0x36,0x00,0x00,0x00,0x00,0x00,0x63,0x33,0x36,0x00,0x00,0x00,0x00,0x00,0x63,0x33,0x66,0x00, 58 | 0x00,0x00,0x00,0x00,0x63,0x33,0x36,0x00,0x66,0x66,0x66,0x60,0x63,0x33,0x66,0x06,0x33,0x33,0x33,0x36, 59 | 0x63,0x33,0x36,0x06,0x33,0x33,0x33,0x66,0x63,0x33,0x36,0x06,0x33,0x33,0x33,0x36,0x63,0x33,0x66,0x06, 60 | 0x33,0x33,0x33,0x36,0x63,0x33,0x36,0x00,0x66,0x66,0x33,0x66,0x63,0x33,0x66,0x00,0x00,0x06,0x33,0x36, 61 | 0x63,0x33,0x36,0x00,0x00,0x06,0x33,0x66,0x63,0x33,0x33,0x66,0x66,0x66,0x33,0x36,0x63,0x33,0x33,0x33, 62 | 0x33,0x33,0x33,0x36,0x63,0x33,0x33,0x33,0x33,0x33,0x33,0x66,0x63,0x33,0x33,0x33,0x33,0x33,0x33,0x36, 63 | 0x63,0x33,0x33,0x33,0x33,0x33,0x33,0x66,0x06,0x66,0x66,0x66,0x66,0x66,0x66,0x60,0x09,0x99,0x99,0x99, 64 | 0x99,0x99,0x99,0x90,0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xD9,0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0x99, 65 | 0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xD9,0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0x99,0x9D,0xDD,0xD9,0x99, 66 | 0x99,0x99,0x99,0x90,0x9D,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0x99,0x00,0x00,0x00,0x00,0x00, 67 | 0x9D,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0x99,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xD9,0x00, 68 | 0x00,0x00,0x00,0x00,0x9D,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0x99,0x99,0x99,0x90,0x00,0x00, 69 | 0x9D,0xDD,0xDD,0xDD,0xDD,0xD9,0x00,0x00,0x9D,0xDD,0xDD,0xDD,0xDD,0x99,0x00,0x00,0x9D,0xDD,0xDD,0xDD, 70 | 0xDD,0xD9,0x00,0x00,0x9D,0xDD,0xDD,0xDD,0xDD,0x99,0x00,0x00,0x9D,0xDD,0x99,0x99,0x99,0x90,0x00,0x00, 71 | 0x9D,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0x99,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xD9,0x00, 72 | 0x00,0x00,0x00,0x00,0x9D,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0x99,0x00,0x00,0x00,0x00,0x00, 73 | 0x9D,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0x99,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xD9,0x00, 74 | 0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0x99,0x99,0x99,0x99,0x90,0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xD9, 75 | 0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0x99,0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xD9,0x9D,0xDD,0xDD,0xDD, 76 | 0xDD,0xDD,0xDD,0x99,0x09,0x99,0x99,0x99,0x99,0x99,0x99,0x90,0x00,0x00,0x00,0x00,0x00,0x09,0x90,0x00, 77 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x9D,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 78 | 0x00,0x09,0x9D,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x9D,0xDD,0xDD,0x9D,0x90,0x00, 79 | 0x00,0x00,0x00,0x00,0x00,0x09,0x9D,0xDD,0xDD,0xDD,0xDD,0x90,0x00,0x00,0x00,0x00,0x00,0x09,0x9D,0xDD, 80 | 0xDD,0xDD,0xDD,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0xDD,0xDD,0x99,0x00,0x00,0x00,0x00, 81 | 0x00,0x00,0x00,0x9D,0xDD,0xDD,0xDD,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xDD,0xD9, 82 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xDD,0x9D,0x90,0x00,0x00,0x00,0x00,0x00,0x00, 83 | 0x00,0x00,0x00,0x9D,0xDD,0xDD,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xD9,0xD9, 84 | 0x00,0x00,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xDD,0xD9,0x00,0x99,0xD9,0x90,0x00,0x00,0x00, 85 | 0x00,0x00,0x09,0xDD,0xDD,0x9D,0x99,0xDD,0xDD,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0xDD, 86 | 0xDD,0xD9,0xD9,0x00,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0xDD,0xDD,0xDD,0xD9,0x00,0x00,0x00,0x00, 87 | 0x00,0x00,0x09,0xDD,0xDD,0xDD,0xDD,0xD9,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xDD,0xDD,0xD9, 88 | 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 89 | 0x00,0x00,0x9D,0xDD,0xDD,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xD9,0xD9,0x00, 90 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xDD,0xD9,0x00,0x00,0x00,0x09,0x90,0x00,0x00,0x00, 91 | 0x00,0x00,0x9D,0xDD,0x9D,0x90,0x00,0x09,0x9D,0x99,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0x90,0x09, 92 | 0xDD,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xD9,0xD9,0x9D,0xDD,0xDD,0x9D,0x90,0x00,0x00,0x00, 93 | 0x00,0x09,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0x90,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0xDD,0xDD, 94 | 0xDD,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x9D,0xDD,0xDD,0xDD,0xDD,0xD9,0x00,0x00,0x00,0x00,0x00,0x00, 95 | 0x00,0x09,0xDD,0xDD,0xDD,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0xDD,0xDD,0x99,0x00,0x00, 96 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9D,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 97 | 0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00, 98 | 0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00, 99 | 0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00, 100 | 0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00, 101 | 0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00, 102 | 0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00, 103 | 0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00, 104 | 0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00, 105 | 0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00, 106 | 0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00, 107 | 0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01, 108 | 0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x11, 109 | 0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x11, 110 | 0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11, 111 | 0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x11,0x11, 112 | 0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x11,0x11, 113 | 0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x73,0x3A,0x64,0x3D,0x34,0x2C,0x6F,0x3D,0x37,0x2C,0x62,0x3D, 114 | 0x39,0x30,0x30,0x3A,0x64,0x23,0x2C,0x66,0x23,0x2C,0x65,0x2C,0x34,0x65,0x34,0x2C,0x65,0x2C,0x67,0x2C, 115 | 0x66,0x2C,0x34,0x63,0x34,0x2C,0x66,0x2C,0x67,0x23,0x2C,0x66,0x23,0x2C,0x34,0x65,0x34,0x2C,0x66,0x23, 116 | 0x2C,0x61,0x2C,0x67,0x2C,0x34,0x63,0x34,0x2C,0x67,0x2C,0x61,0x23,0x2C,0x67,0x23,0x2C,0x34,0x65,0x34, 117 | 0x2C,0x67,0x23,0x2C,0x62,0x2C,0x61,0x2C,0x34,0x63,0x34,0x2C,0x67,0x23,0x2C,0x67,0x2C,0x66,0x23,0x2C, 118 | 0x34,0x65,0x34,0x2C,0x66,0x2C,0x65,0x2C,0x64,0x23,0x2C,0x34,0x63,0x34,0x2C,0x64,0x2C,0x63,0x23,0x2C, 119 | 0x63,0x2C,0x34,0x65,0x34,0x2C,0x64,0x23,0x2C,0x66,0x2C,0x64,0x23,0x2C,0x34,0x63,0x34,0x2C,0x64,0x23, 120 | 0x2C,0x66,0x2C,0x64,0x23,0x2C,0x34,0x63,0x34,0x2C,0x64,0x23,0x2C,0x66,0x2C,0x64,0x23,0x2C,0x34,0x63, 121 | 0x34,0x2C,0x64,0x23,0x2C,0x66,0x2C,0x64,0x23,0x2C,0x70,0x2C,0x70,0x2C,0x33,0x32,0x66,0x23,0x35,0x2C, 122 | 0x33,0x32,0x65,0x36,0x2C,0x33,0x32,0x63,0x23,0x35,0x2C,0x33,0x32,0x66,0x23,0x34,0x2C,0x33,0x32,0x63, 123 | 0x34,0x2C,0x33,0x32,0x67,0x34,0x2C,0x33,0x32,0x66,0x34,0x2C,0x33,0x32,0x64,0x34,0x2C,0x33,0x32,0x65, 124 | 0x34,0x2C,0x33,0x32,0x63,0x23,0x34,0x2C,0x33,0x32,0x65,0x34,0x00 125 | }; 126 | 127 | void loadSplashscreen(){ 128 | for(int i = 0; i < sizeof(splashscreen); i++) 129 | writeMem(i, pgm_read_byte(&splashscreen[i])); 130 | } 131 | 132 | void loadRom(){ 133 | for(int i = 0; i < sizeof(rom); i++) 134 | writeMem(i, pgm_read_byte(&rom[i])); 135 | } 136 | 137 | void loadRomIco(){ 138 | for(int i = 0; i < sizeof(romImage); i++) 139 | writeMem(i + 1024, pgm_read_byte(&romImage[i])); 140 | } 141 | -------------------------------------------------------------------------------- /settings.h: -------------------------------------------------------------------------------- 1 | #define ESPBOY 2 | #define RAM_SIZE 20 * 1024 3 | #define FREQUENCY 160 // valid 80, 160 4 | #define APPSK "87654321" 5 | #define BUILD_VERSION_MAJOR "1" 6 | #define BUILD_VERSION_MINOR "010" 7 | 8 | #ifdef ESPBOY 9 | #define APSSID "ESPboy" 10 | #define APHOST "espboy" 11 | #define MCP4725address 0x60 12 | #define MCP23017address 0 13 | #define csTFTMCP23017pin 8 14 | #define LEDquantity 1 15 | #define LEDPIN D4 16 | #define SOUNDPIN D3 17 | #else 18 | #define APSSID "ESPlge" 19 | #define APHOST "esplge" 20 | #define SOUNDPIN -1 21 | #define DEBUG_ON_SCREEN 22 | #endif 23 | 24 | #define SCREEN_WIDTH 128 25 | #define SCREEN_WIDTH_BYTES 64 26 | #define SCREEN_HEIGHT 128 27 | #ifdef ESPBOY 28 | #define SCREEN_REAL_WIDTH 128 29 | #define SCREEN_REAL_HEIGHT 128 30 | #else 31 | #define SCREEN_REAL_WIDTH 320 32 | #define SCREEN_REAL_HEIGHT 240 33 | #endif 34 | #define SCREEN_SIZE (SCREEN_HEIGHT * SCREEN_WIDTH_BYTES) 35 | #define SCREEN_ARRAY_DEF SCREEN_SIZE 36 | #define SCREEN_ADDR(x, y) ((int(y) << 6) + int(x)) 37 | 38 | #define MULTIPLY_FP_RESOLUTION_BITS 8 39 | #define PARTICLE_COUNT 32 40 | #define SPRITE_COUNT 32 41 | #define EEPROM_SIZE 512 42 | -------------------------------------------------------------------------------- /sound.ino: -------------------------------------------------------------------------------- 1 | #include "settings.h" 2 | #define NEXT_CHAR rtttl.startposition++; c = (char)readMem(rtttl.startposition); if(c == 0) return 0; 3 | #define NEXT_CHAR_IN_P rtttl.position++; c = (char)readMem(rtttl.startposition + rtttl.position); if(c == 0) return 50; 4 | #define OCTAVE_OFFSET 0 5 | 6 | #pragma GCC optimize ("-O2") 7 | #pragma GCC push_options 8 | 9 | const int notes[] PROGMEM = { 0, 10 | 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 11 | 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 12 | 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, 13 | 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951 14 | }; 15 | 16 | unsigned int millisec = (unsigned int)millis(); 17 | 18 | struct RTTTL { 19 | uint16_t address; 20 | uint16_t position; 21 | uint16_t startposition; 22 | uint8_t loop; 23 | uint8_t play; 24 | uint8_t default_dur; 25 | uint8_t default_oct; 26 | uint16_t bpm; 27 | uint32_t wholenote; 28 | uint16_t this_tone; 29 | int16_t delay; 30 | uint8_t isPlayed; 31 | }; 32 | 33 | struct PLAY_TONE { 34 | uint16_t freq; 35 | int16_t time; 36 | }; 37 | 38 | struct RTTTL rtttl; 39 | struct PLAY_TONE play_tone; 40 | 41 | inline void addTone(uint16_t f, uint16_t t){ 42 | play_tone.freq = f; 43 | play_tone.time = t; 44 | } 45 | 46 | uint8_t loadRtttl(){ 47 | uint16_t num; 48 | char c; 49 | rtttl.default_dur = 4; 50 | rtttl.default_oct = 6; 51 | rtttl.bpm = 63; 52 | rtttl.startposition = rtttl.address; 53 | c = readMem(rtttl.startposition); 54 | while(c != ':'){ 55 | // ignore name 56 | NEXT_CHAR 57 | } 58 | NEXT_CHAR // skip ':' 59 | // get default duration 60 | if(c == 'd'){ 61 | NEXT_CHAR 62 | NEXT_CHAR// skip "d=" 63 | num = 0; 64 | while(isdigit(c)){ 65 | num = (num * 10) + (c - '0'); 66 | NEXT_CHAR 67 | } 68 | if(num > 0) 69 | rtttl.default_dur = num; 70 | NEXT_CHAR // skip comma 71 | } 72 | // get default octave 73 | if(c == 'o'){ 74 | NEXT_CHAR 75 | NEXT_CHAR// skip "o=" 76 | num = c - '0'; 77 | NEXT_CHAR 78 | if(num >= 3 && num <=7) 79 | rtttl.default_oct = num; 80 | NEXT_CHAR // skip comma 81 | } 82 | // get BPM 83 | if(c == 'b'){ 84 | NEXT_CHAR 85 | NEXT_CHAR// skip "b=" 86 | num = 0; 87 | while(isdigit(c)){ 88 | num = (num * 10) + (c - '0'); 89 | NEXT_CHAR 90 | } 91 | rtttl.bpm = num; 92 | } 93 | rtttl.wholenote = (60 * 1000 / rtttl.bpm) * 4; 94 | NEXT_CHAR 95 | rtttl.position = 0; 96 | rtttl.delay = 0; 97 | return 1; 98 | } 99 | 100 | void setRtttlAddress(uint16_t adr){ 101 | rtttl.address = adr; 102 | loadRtttl(); 103 | } 104 | 105 | void setRtttlLoop(uint8_t loop){ 106 | rtttl.loop = loop; 107 | } 108 | 109 | void setRtttlPlay(uint8_t play){ 110 | if(play == 0){ 111 | rtttl.play = 0; 112 | noTone(SOUNDPIN); 113 | } 114 | else if(play == 1){ 115 | rtttl.play = 1; 116 | } 117 | else{ 118 | rtttl.play = 0; 119 | rtttl.position = 0; 120 | noTone(SOUNDPIN); 121 | } 122 | rtttl.isPlayed = 0; 123 | rtttl.delay = 0; 124 | } 125 | 126 | inline void updateRtttl(){ 127 | if(rtttl.delay > 0) 128 | rtttl.delay--; 129 | if(play_tone.time > 0) 130 | play_tone.time--; 131 | //play single tone 132 | if(play_tone.time > 0){ 133 | if(rtttl.delay <= 0){ 134 | tone(SOUNDPIN, play_tone.freq, 128); 135 | rtttl.isPlayed = 0; 136 | return; 137 | } 138 | if(play_tone.time & 1){ 139 | tone(SOUNDPIN, play_tone.freq, 128); 140 | rtttl.isPlayed = 0; 141 | return; 142 | } 143 | } 144 | //player 145 | if(rtttl.play == 0){ 146 | return; 147 | } 148 | if(rtttl.delay > 0){ 149 | if(!rtttl.isPlayed){ 150 | rtttl.isPlayed = 1; 151 | tone(SOUNDPIN, rtttl.this_tone, rtttl.delay); 152 | } 153 | return; 154 | } 155 | } 156 | 157 | int playRtttl(){ 158 | uint16_t num; 159 | uint32_t duration; 160 | uint8_t note; 161 | uint8_t scale; 162 | char c; 163 | //first, get note duration, if available 164 | noTone(SOUNDPIN); 165 | if(rtttl.play == 0 || rtttl.startposition == 0){ 166 | return 50; 167 | } 168 | num = 0; 169 | c = (char)readMem(rtttl.startposition + rtttl.position); 170 | if(c == 0){ 171 | if(!rtttl.loop){ 172 | rtttl.play = 0; 173 | rtttl.isPlayed = 0; 174 | rtttl.this_tone = 0; 175 | rtttl.delay = 0; 176 | } 177 | rtttl.position = 0; 178 | c = (char)readMem(rtttl.startposition + rtttl.position); 179 | } 180 | while(isdigit(c)){ 181 | num = (num * 10) + (c - '0'); 182 | NEXT_CHAR_IN_P 183 | } 184 | if(num) 185 | duration = rtttl.wholenote / num; 186 | else 187 | duration = rtttl.wholenote / rtttl.default_dur; // we will need to check if we are a dotted note after 188 | //now get the note 189 | note = 0; 190 | switch(c){ 191 | case 'c': 192 | case 'C': 193 | note = 1; 194 | break; 195 | case 'd': 196 | case 'D': 197 | note = 3; 198 | break; 199 | case 'e': 200 | case 'E': 201 | note = 5; 202 | break; 203 | case 'f': 204 | case 'F': 205 | note = 6; 206 | break; 207 | case 'g': 208 | case 'G': 209 | note = 8; 210 | break; 211 | case 'a': 212 | case 'A': 213 | note = 10; 214 | break; 215 | case 'b': 216 | case 'B': 217 | note = 12; 218 | break; 219 | case 'p': 220 | case 'P': 221 | default: 222 | note = 0; 223 | } 224 | NEXT_CHAR_IN_P 225 | // now, get optional '#' sharp 226 | if(c == '#'){ 227 | note++; 228 | NEXT_CHAR_IN_P 229 | } 230 | // now, get optional '.' dotted note 231 | if(c == '.'){ 232 | duration += duration/2; 233 | NEXT_CHAR_IN_P 234 | } 235 | else if(c == ';'){ 236 | duration += duration; 237 | NEXT_CHAR_IN_P 238 | } 239 | else if(c == '&'){ 240 | duration += duration / 2 * 3; 241 | NEXT_CHAR_IN_P 242 | } 243 | // now, get scale 244 | if(isdigit(c)){ 245 | scale = c - '0'; 246 | NEXT_CHAR_IN_P 247 | } 248 | else{ 249 | scale = rtttl.default_oct; 250 | } 251 | scale += OCTAVE_OFFSET; 252 | if(c == ',') 253 | NEXT_CHAR_IN_P // skip comma for next note (or we may be at the end) 254 | // now play the note 255 | rtttl.delay = duration; 256 | if(note){ 257 | rtttl.this_tone = pgm_read_word(¬es[note + ((scale - 4) * 12)]); 258 | tone(SOUNDPIN, rtttl.this_tone, rtttl.delay); 259 | } 260 | else{ 261 | rtttl.this_tone = 0; 262 | } 263 | rtttl.isPlayed = 1; 264 | return (duration > 8)?duration - 8 : 0; 265 | } 266 | --------------------------------------------------------------------------------