diff --git a/src/boards/RNBW/bootrom_chr.h b/src/boards/RNBW/bootrom_chr.h new file mode 100644 index 00000000..63d42c31 --- /dev/null +++ b/src/boards/RNBW/bootrom_chr.h @@ -0,0 +1,258 @@ +const unsigned char bootrom_chr[4096] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0x81,0xA5,0x81,0xBD,0x99,0x81,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0xFF,0xDB,0xFF,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x6C,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x38,0x7C,0x38,0xFE,0xFE,0xD6,0x10,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x03,0x0F,0x1C,0x30,0x30,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xC0,0xF0,0x3A,0x1E,0x0E,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1C,0x1C,0x1C,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x44,0xC6,0xC6,0xFE,0x7C,0x38,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0D,0x0D,0x00,0x0F,0xDF,0xD8,0x1B,0xDB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xB0,0xB0,0x00,0xF0,0xFB,0x1B,0xD8,0xDB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0F,0x1F,0x38,0x75,0x65,0x65,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFE,0xFE,0x06,0x56,0x56,0x56,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7F,0x63,0x7F,0x63,0x63,0x67,0xE6,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x99,0x5A,0x3C,0xE7,0xE7,0x3C,0x5A,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x80,0xE0,0xF8,0xFE,0xF8,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x0E,0x3E,0xFE,0x3E,0x0E,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x3C,0x7E,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7F,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0xC3,0x78,0xCC,0xCC,0x78,0x8C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x60,0x60,0x30,0x30,0x1C,0x0F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x0C,0x0C,0x38,0xF0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x38,0x38,0x38,0x38,0x38,0x28,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xDB,0x1B,0xD8,0xDF,0x0F,0x00,0x0D,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xDB,0xD8,0x1B,0xFB,0xF0,0x00,0xB0,0xB0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x60,0x60,0x60,0x60,0x60,0x7F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x06,0x06,0x06,0x06,0x06,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xFF,0xFF,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x7C,0xC0,0x78,0x0C,0xF8,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xC6,0xCC,0x18,0x30,0x66,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x38,0x6C,0x38,0x76,0xDC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x60,0x30,0x18,0x18,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x70,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0xDC,0xFC,0xEC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0xF0,0x30,0x30,0x30,0x30,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0x0C,0x38,0x60,0xCC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0x0C,0x38,0x0C,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0xC0,0xF8,0x0C,0x0C,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x38,0x60,0xC0,0xF8,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0xCC,0x0C,0x18,0x30,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0xCC,0x78,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0xCC,0x7C,0x0C,0x18,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x30,0x30,0x00,0x70,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xFC,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0x0C,0x18,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7C,0xC6,0xDE,0xDE,0xDE,0xC0,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x78,0xCC,0xCC,0xFC,0xCC,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0x66,0x66,0x7C,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0x6C,0x66,0x66,0x66,0x6C,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFE,0x62,0x68,0x78,0x68,0x62,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFE,0x62,0x68,0x78,0x68,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3C,0x66,0xC0,0xC0,0xCE,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1E,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE6,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xF0,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC6,0xEE,0xFE,0xD6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0xCC,0xCC,0xDC,0x78,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0x66,0x66,0x7C,0x78,0x6C,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xCC,0xE0,0x38,0x1C,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0xB4,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xCC,0xCC,0xCC,0x78,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFE,0xCC,0x98,0x30,0x62,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0x18,0x18,0x18,0x18,0x18,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x78,0x0C,0x7C,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0x60,0x7C,0x66,0x66,0x66,0xBC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x78,0xCC,0xC0,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1C,0x0C,0x0C,0x7C,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x78,0xCC,0xFC,0xC0,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x38,0x6C,0x60,0xF0,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0x60,0x6C,0x76,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x00,0x70,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x00,0x78,0x18,0x18,0x18,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0x60,0x66,0x6C,0x78,0x6C,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xEC,0xFE,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x78,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xDC,0x66,0x66,0x7C,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xD8,0x6C,0x6C,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x7C,0xC0,0x78,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x30,0x7C,0x30,0x30,0x34,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xC6,0xC6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xC6,0x6C,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xCC,0xCC,0xCC,0x7C,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xFC,0x98,0x30,0x64,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1C,0x30,0x30,0xE0,0x30,0x30,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0x30,0x30,0x1C,0x30,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x03,0x0F,0x1E,0x3E,0x3F,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xC0,0xF0,0x78,0x7C,0xFC,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x1F,0x3F,0x78,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xE0,0xF8,0xFC,0x1E,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x20,0x70,0xF8,0x7C,0x3F,0x1F,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x1C,0x3E,0x7C,0xF8,0xF0,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x05,0x0E,0x1C,0x38,0x70,0xE0,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x51,0x71,0x71,0x71,0x7F,0x71,0x7F,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFA,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3F,0x07,0x0F,0x1D,0x39,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x23,0x27,0x2E,0x3C,0x38,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC0,0x47,0x47,0xE7,0x00,0x00,0xE0,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x02,0x02,0x04,0x04,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x70,0x8C,0x02,0x32,0x81,0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0x7E,0x3E,0x3E,0x1F,0x0F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0x7E,0x7C,0x7C,0xF8,0xF0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x83,0x87,0x0C,0x08,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC1,0xE1,0x30,0x10,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0F,0x1F,0x3F,0x7C,0xF8,0x70,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0xF0,0xF8,0x7C,0x3E,0x1C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x27,0x53,0xA9,0x54,0x2A,0x15,0x0A,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x80,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7F,0x71,0x7F,0x31,0x3F,0x31,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFE,0xFE,0xFE,0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x44,0xEE,0x7C,0x38,0x7C,0xEE,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x08,0x14,0x22,0x14,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x47,0xE7,0x00,0x00,0xE0,0x47,0x27,0xE7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x05,0x0E,0x1C,0x38,0x70,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x8C,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3C,0x7C,0xFF,0xFF,0x80,0x80,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xF8,0xF8,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3C,0xFC,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x40,0x82,0x00,0x00,0xFF,0x00,0x00,0x00, +0x00,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, +0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC0,0x60,0x70,0x78,0x3C,0x04,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC0,0xE0,0xF0,0xF8,0xFC,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x01,0x03,0x02,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x80,0x80,0xC0,0x40,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3F,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3F,0x7C,0x79,0x7F,0x7F,0x7E,0x7E,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFC,0x3E,0x9E,0x9E,0x3E,0x7E,0x7E,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x04,0x3F,0x7F,0x00,0x35,0x35,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xF0,0x10,0xFE,0xFF,0x00,0x56,0x56,0x56,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1F,0x1F,0x3F,0x3F,0x3F,0x3F,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFE,0xFE,0xFE,0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x3F,0x30,0x3F,0x30,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0C,0xFC,0x0C,0xFC,0x0C,0xFC,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x30,0x3E,0x3E,0x3E,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0C,0x0C,0x7C,0x7C,0x7C,0xFC,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0E,0x0E,0x1E,0x1F,0x3E,0x3E,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x70,0x70,0x78,0xF8,0x7C,0x7C,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0x7E,0x7F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0x7E,0xFE,0xFC,0xF8,0x38,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0x7E,0x7F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7E,0x7E,0xFE,0xFC,0xF8,0x38,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x35,0x35,0x35,0x35,0x35,0x35,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x56,0x56,0x56,0x56,0x56,0x56,0xFE,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x0C,0x1E,0x3E,0x38,0x70,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x07,0x08,0x10,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xE0,0xF8,0x3C,0x1E,0x0E,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xFF,0xFF,0xFE,0xFC,0xF8,0xF1,0xE3,0xE7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x1E,0x33,0x73,0xFE,0xFC,0xF8,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x1A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x07,0x2E,0xFC,0xF8,0xFC,0x78,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x0F,0x1C,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xE0,0xF0,0x38,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3F,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC0,0xE0,0xF0,0xF8,0x7C,0x7C,0xFC,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x60,0x20,0x20,0x10,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE7,0xE1,0xC5,0xC8,0xC0,0xE3,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0xC0,0x80,0x10,0x30,0xF0,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1C,0x3E,0x1F,0x1F,0x3F,0x72,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x18,0x1C,0x0F,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x18,0x38,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3E,0x3E,0x3E,0x3E,0x3E,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7C,0x7C,0x7C,0x7C,0x7C,0xFC,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x17,0x16,0x36,0x36,0x30,0x1F,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x79,0xB6,0x32,0xBA,0x32,0x78,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x82,0x84,0x84,0x88,0x88,0x80,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x11,0x9C,0x1E,0x0F,0x1F,0x5F,0x3F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xC0,0xE4,0xF0,0xFC,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x40,0x40,0x20,0x20,0x20,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x03,0x03,0x07,0xFF,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x80,0x80,0xC0,0xFE,0xFE,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0F,0x18,0x30,0x67,0xCC,0x98,0x91,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0x30,0x18,0xCC,0x66,0x32,0x12,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x1F,0x3E,0x77,0x6F,0xFE,0xDC,0xD0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE0,0xF8,0x7C,0xBE,0xBE,0x17,0x07,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x03,0x07,0x0F,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x20,0x70,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x0E,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x80,0xC0,0xE0,0xF0,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0E,0x67,0xF3,0x50,0x02,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE7,0x06,0xF8,0x00,0x04,0x03,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x2C,0x2C,0x38,0x00,0x00,0xE0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x10,0x00,0x7F,0x9F,0x97,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x08,0x00,0xFE,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x02,0x04,0x04,0x04,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3F,0x1F,0x1F,0x1F,0x3F,0x3F,0x78,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xF8,0xF0,0xF0,0xF0,0xF8,0xF8,0x3C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x91,0x00,0x03,0x07,0x07,0x03,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x12,0x00,0x80,0xC0,0xC0,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xC8,0xC4,0xE6,0x67,0x73,0x3E,0x1F,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1F,0x1F,0x07,0x86,0x8E,0x3C,0xF8,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1E,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x80,0xC0,0xE0,0xF0,0x70,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x01,0x03,0x07,0x0F,0x0E,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; \ No newline at end of file diff --git a/src/boards/rainbow2.cpp b/src/boards/rainbow2.cpp index 9cb6167c..d843a3b9 100644 --- a/src/boards/rainbow2.cpp +++ b/src/boards/rainbow2.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - // mapper 3873 - Rainbow2 board v1.0 revA and v1.1 by Broke Studio + // mapper 682 - Rainbow2 board v1.0 revA and v1.1 by Broke Studio // // documentation available here: https://github.com/BrokeStudio/rainbow-lib @@ -35,266 +35,7 @@ #define UDBG(...) #endif -const unsigned char bootloader_chr[4096] = { -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0x81,0xA5,0x81,0xBD,0x99,0x81,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0xFF,0xDB,0xFF,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x6C,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x38,0x7C,0x38,0xFE,0xFE,0xD6,0x10,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x10,0x38,0x7C,0xFE,0x7C,0x10,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0F,0x07,0x0F,0x7D,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3C,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x33,0x3F,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7F,0x63,0x7F,0x63,0x63,0x67,0xE6,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x99,0x5A,0x3C,0xE7,0xE7,0x3C,0x5A,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x80,0xE0,0xF8,0xFE,0xF8,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x02,0x0E,0x3E,0xFE,0x3E,0x0E,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x3C,0x7E,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7F,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0xC3,0x78,0xCC,0xCC,0x78,0x8C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x7E,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x24,0x66,0xFF,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0xFF,0xFF,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x7C,0xC0,0x78,0x0C,0xF8,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0xC6,0xCC,0x18,0x30,0x66,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x38,0x6C,0x38,0x76,0xDC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x60,0x30,0x18,0x18,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x70,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0xDC,0xFC,0xEC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0xF0,0x30,0x30,0x30,0x30,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0x0C,0x38,0x60,0xCC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0x0C,0x38,0x0C,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0xC0,0xF8,0x0C,0x0C,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x38,0x60,0xC0,0xF8,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0xCC,0x0C,0x18,0x30,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0xCC,0x78,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0xCC,0x7C,0x0C,0x18,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x30,0x30,0x00,0x70,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xFC,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0x0C,0x18,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7C,0xC6,0xDE,0xDE,0xDE,0xC0,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x78,0xCC,0xCC,0xFC,0xCC,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0x66,0x66,0x7C,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0x6C,0x66,0x66,0x66,0x6C,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFE,0x62,0x68,0x78,0x68,0x62,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFE,0x62,0x68,0x78,0x68,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3C,0x66,0xC0,0xC0,0xCE,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1E,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE6,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xF0,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC6,0xEE,0xFE,0xD6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0xCC,0xCC,0xDC,0x78,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0x66,0x66,0x7C,0x78,0x6C,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xCC,0xE0,0x38,0x1C,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0xB4,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xCC,0xCC,0xCC,0x78,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFE,0xCC,0x98,0x30,0x62,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0x18,0x18,0x18,0x18,0x18,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x78,0x0C,0x7C,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE0,0x60,0x7C,0x66,0x66,0x66,0xBC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x78,0xCC,0xC0,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1C,0x0C,0x0C,0x7C,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x78,0xCC,0xFC,0xC0,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x38,0x6C,0x60,0xF0,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE0,0x60,0x6C,0x76,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x00,0x70,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x00,0x78,0x18,0x18,0x18,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE0,0x60,0x66,0x6C,0x78,0x6C,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xEC,0xFE,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x78,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xDC,0x66,0x66,0x7C,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xD8,0x6C,0x6C,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x7C,0xC0,0x78,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x30,0x7C,0x30,0x30,0x34,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xC6,0xC6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xC6,0x6C,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xCC,0xCC,0xCC,0x7C,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xFC,0x98,0x30,0x64,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1C,0x30,0x30,0xE0,0x30,0x30,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE0,0x30,0x30,0x1C,0x30,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x03,0x0F,0x1E,0x3E,0x3F,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0xC0,0xF0,0x78,0x7C,0xFC,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x07,0x1F,0x3F,0x78,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xE0,0xF8,0xFC,0x1E,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x20,0x70,0xF8,0x7C,0x3F,0x1F,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x08,0x1C,0x3E,0x7C,0xF8,0xF0,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x03,0x05,0x0E,0x1C,0x38,0x70,0xE0,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x51,0x71,0x71,0x71,0x7F,0x71,0x7F,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFA,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x07,0x0F,0x1D,0x39,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x23,0x27,0x2E,0x3C,0x38,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC0,0x47,0x47,0xE7,0x00,0x00,0xE0,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x01,0x02,0x02,0x04,0x04,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x70,0x8C,0x02,0x32,0x81,0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0x7E,0x3E,0x3E,0x1F,0x0F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0x7E,0x7C,0x7C,0xF8,0xF0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x83,0x87,0x0C,0x08,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC1,0xE1,0x30,0x10,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0F,0x1F,0x3F,0x7C,0xF8,0x70,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE0,0xF0,0xF8,0x7C,0x3E,0x1C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x27,0x53,0xA9,0x54,0x2A,0x15,0x0A,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x80,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7F,0x71,0x7F,0x31,0x3F,0x31,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFE,0xFE,0xFE,0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x44,0xEE,0x7C,0x38,0x7C,0xEE,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x08,0x14,0x22,0x14,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x47,0xE7,0x00,0x00,0xE0,0x47,0x27,0xE7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x02,0x05,0x0E,0x1C,0x38,0x70,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x02,0x8C,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3C,0x7C,0xFF,0xFF,0x80,0x80,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xF8,0xF8,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3C,0xFC,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC0,0x60,0x70,0x78,0x3C,0x04,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC0,0xE0,0xF0,0xF8,0xFC,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x01,0x01,0x03,0x02,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x80,0x80,0xC0,0x40,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x7C,0x79,0x7F,0x7F,0x7E,0x7E,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFC,0x3E,0x9E,0x9E,0x3E,0x7E,0x7E,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x07,0x04,0x3F,0x7F,0x00,0x35,0x35,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xF0,0x10,0xFE,0xFF,0x00,0x56,0x56,0x56,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1F,0x1F,0x3F,0x3F,0x3F,0x3F,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFE,0xFE,0xFE,0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x3F,0x30,0x3F,0x30,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0C,0xFC,0x0C,0xFC,0x0C,0xFC,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x30,0x30,0x3E,0x3E,0x3E,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0C,0x0C,0x7C,0x7C,0x7C,0xFC,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0E,0x0E,0x1E,0x1F,0x3E,0x3E,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x70,0x70,0x78,0xF8,0x7C,0x7C,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0x7E,0x7F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0x7E,0xFE,0xFC,0xF8,0x38,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0x7E,0x7F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7E,0x7E,0xFE,0xFC,0xF8,0x38,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x35,0x35,0x35,0x35,0x35,0x35,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x56,0x56,0x56,0x56,0x56,0x56,0xFE,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x0C,0x1E,0x3E,0x38,0x70,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x01,0x07,0x08,0x10,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0xE0,0xF8,0x3C,0x1E,0x0E,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xFF,0xFF,0xFE,0xFC,0xF8,0xF1,0xE3,0xE7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x08,0x1E,0x33,0x73,0xFE,0xFC,0xF8,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x1A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x03,0x07,0x2E,0xFC,0xF8,0xFC,0x78,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x07,0x0F,0x1C,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0xE0,0xF0,0x38,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3F,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xC0,0xE0,0xF0,0xF8,0x7C,0x7C,0xFC,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x60,0x20,0x20,0x10,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE7,0xE1,0xC5,0xC8,0xC0,0xE3,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE0,0xC0,0x80,0x10,0x30,0xF0,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1C,0x3E,0x1F,0x1F,0x3F,0x72,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x18,0x1C,0x0F,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x18,0x38,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3E,0x3E,0x3E,0x3E,0x3E,0x3F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x7C,0x7C,0x7C,0x7C,0x7C,0xFC,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x18,0x17,0x16,0x36,0x36,0x30,0x1F,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x79,0xB6,0x32,0xBA,0x32,0x78,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x02,0x82,0x84,0x84,0x88,0x88,0x80,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x11,0x9C,0x1E,0x0F,0x1F,0x5F,0x3F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xC0,0xE4,0xF0,0xFC,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x40,0x40,0x20,0x20,0x20,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x02,0x02,0x04,0x04,0x04,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x01,0x03,0x03,0x07,0xFF,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x80,0x80,0xC0,0xFE,0xFE,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x01,0x03,0x07,0x0F,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x20,0x70,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x04,0x0E,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x80,0xC0,0xE0,0xF0,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x0E,0x67,0xF3,0x50,0x02,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE7,0x06,0xF8,0x00,0x04,0x03,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x2C,0x2C,0x38,0x00,0x00,0xE0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x10,0x10,0x00,0x7F,0x9F,0x97,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x08,0x08,0x00,0xFE,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x3F,0x1F,0x1F,0x1F,0x3F,0x3F,0x78,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xF8,0xF0,0xF0,0xF0,0xF8,0xF8,0x3C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x1E,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x80,0xC0,0xE0,0xF0,0x70,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x01,0x03,0x07,0x0F,0x0E,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x78,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -#define MAPPER_VERSION 0b01000001 +#define MAPPER_VERSION 0b01000000 #define MIRR_VERTICAL 0b00 // VRAM #define MIRR_HORIZONTAL 0b01 // VRAM @@ -333,7 +74,9 @@ const unsigned char bootloader_chr[4096] = { #define PPUON (PPU[1] & 0x18) //PPU should operate #define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8 -static uint8 prg_rom_mode, prg_ram_mode, bootloader; +static void Rainbow2Reset(void); + +static uint8 prg_rom_mode, prg_ram_mode, bootrom; static uint16 prg[11]; // 0: $5000, 1: $6000, 2: $7000, 3: $8000, 4: $9000, etc static uint8 chr_chip, chr_spr_ext_mode, chr_mode; @@ -346,8 +89,11 @@ static uint16 SPR_bank[64]; static uint8 audio_output; static uint8 rx_address, tx_address, rx_index; +static uint32 PRGSIZE = 0; +static uint32 CHRSIZE = 0; + static uint8 *WRAM = NULL; -const uint32 WRAMSIZE = 128 * 1024; // max 128 KiB +static int WRAMSIZE = 0; // max 512 KiB static uint8 *FPGA_RAM = NULL; const uint32 FPGA_RAMSIZE = 8 * 1024; @@ -359,7 +105,7 @@ static uint8 *DUMMY_CHRROM = NULL; const uint32 DUMMY_CHRROMSIZE = 8192 * 1024; // max 8192 MiB static uint8 *CHRRAM = NULL; -const uint32 CHRRAMSIZE = 128 * 1024; // max 128 KiB +static int CHRRAMSIZE = 0; // max 512 KiB extern uint8 *ExtraNTARAM; @@ -388,6 +134,11 @@ const uint32 PRG_FLASHROMSIZE = 8192 * 1024; // max 8MiB static uint8 *CHR_FLASHROM = NULL; const uint32 CHR_FLASHROMSIZE = 8192 * 1024; // max 8MiB +const bool S29AL008_TOP = false; +const bool S29AL016_TOP = true; +const bool S29JL032_TOP = false; +const bool S29GL064S_TOP = false; + static SFORMAT FlashRegs[] = { { &flash_mode, 2, "FMOD" }, @@ -479,7 +230,7 @@ static void Rainbow2IRQ(int a) { if (!ppuon || sl >= 241) { - // whenever rendering is off for any reason (vblank or forced disable + // whenever rendering is off for any reason (vblank or forced disable) // the irq counter resets, as well as the inframe flag (easily verifiable from software) S_IRQcontrol &= ~0x40; // in-frame flag cleared S_IRQcontrol &= ~0x80; // pending IRQ flag cleared @@ -564,7 +315,7 @@ static void Sync(void) { uint8 cart_chr_map; // $8000-$ffff - uint8 t_prg_rom_mode = bootloader ? PRG_ROM_MODE_3 : prg_rom_mode; + uint8 t_prg_rom_mode = bootrom ? PRG_ROM_MODE_3 : prg_rom_mode; // 32K if (t_prg_rom_mode == PRG_ROM_MODE_0) @@ -626,8 +377,8 @@ static void Sync(void) { for (uint8 i = 0; i < 4; i++) { // PRG-ROM - if (i == 3 && bootloader) - setprg8r(0x11, 0xe000, 0x7FFF); // ~0); + if (i == 3 && bootrom) + setprg8r(0x13, 0xe000, 1); else if (!(prg[3 + i * 2] & 0x8000)) setprg8r(0x11, 0x8000 + 0x2000 * i, prg[3 + i * 2] & 0x7fff); @@ -658,7 +409,7 @@ static void Sync(void) { { // WRAM if (((prg[1] & 0xC000) >> 14) == 2) - setprg8r(0x10, 0x6000, prg[1] & 0x03); + setprg8r(0x10, 0x6000, prg[1] & 0x3f); // FPGA-RAM if (((prg[1] & 0xC000) >> 14) == 3) setprg8r(0x12, 0x6000, 0); @@ -672,7 +423,7 @@ static void Sync(void) { { // WRAM if (((prg[1] & 0xC000) >> 14) == 2) - setprg4r(0x10, 0x6000, prg[1] & 0x07); + setprg4r(0x10, 0x6000, prg[1] & 0x7f); // FPGA-RAM if (((prg[1] & 0xC000) >> 14) == 3) setprg4r(0x12, 0x6000, prg[1] & 0x01); @@ -682,7 +433,7 @@ static void Sync(void) { // WRAM if (((prg[2] & 0xC000) >> 14) == 2) - setprg4r(0x10, 0x7000, prg[2] & 0x07); + setprg4r(0x10, 0x7000, prg[2] & 0x7f); // FPGA-RAM if (((prg[2] & 0xC000) >> 14) == 3) setprg4r(0x12, 0x7000, prg[2] & 0x01); @@ -692,8 +443,8 @@ static void Sync(void) { } // $5000-$5fff - 4K FPGA-RAM - if (bootloader) - setprg4r(0x11, 0x5000, 124); + if (bootrom) + setprg4r(0x13, 0x5000, 1); else setprg4r(0x12, 0x5000, prg[0] & 0x01); @@ -779,7 +530,7 @@ static void Sync(void) { } -static DECLFW(Rainbow2SW) { +static DECLFW(RNBW_ExpAudioWr) { if (A >= 0x41A0 && A <= 0x41A2) { vpsg1[A & 3] = V; @@ -900,7 +651,7 @@ static DECLFR(FPGA_0x4800Rd) //return FPGA_RAM[(A & 0x7ff) + 0x1800]; } -static DECLFR(Rainbow2Read) { +static DECLFR(RNBW_0x4100Rd) { switch (A) { case 0x4100: return (prg_ram_mode << 6) | prg_rom_mode; @@ -939,7 +690,7 @@ static DECLFR(Rainbow2Read) { } } -static DECLFW(Rainbow2Write) { +static DECLFW(RNBW_0x4100Wr) { switch (A) { // Mapper configuration @@ -1049,8 +800,9 @@ static DECLFW(Rainbow2Write) { } // Scanline IRQ case 0x4150: S_IRQlatch = V; break; - case 0x4151: S_IRQcontrol = (S_IRQcontrol & 0x7F) | (V & 0x01); break; - case 0x4152: S_IRQoffset = V > 169 ? 169 : V; break; + case 0x4151: S_IRQcontrol |= 1; break; + case 0x4152: S_IRQcontrol &= 0x7E; break; + case 0x4153: S_IRQoffset = V > 169 ? 169 : V; break; // CPU Cycle IRQ case 0x4158: C_IRQLatch &= 0xFF00; C_IRQLatch |= V; C_IRQCount = C_IRQLatch; break; case 0x4159: C_IRQLatch &= 0x00FF; C_IRQLatch |= V << 8; C_IRQCount = C_IRQLatch; break; @@ -1097,15 +849,8 @@ static DECLFW(Rainbow2Write) { rx_index = V; break; case 0x41FF: - bootloader = V & 0x01; - if (V == 0xff) - { - // init FPGA_RAM with PRG ROM data - for (size_t i = 0; i < 4096; i++) - { - FPGA_RAM[4096 + i] = PRG_FLASHROM[0x7c000 + i]; - } - } + bootrom = V & 0x01; + if (bootrom == 0) Rainbow2Reset(); // a bit hacky but does the job for testing Sync(); break; case 0x4240: @@ -1189,30 +934,42 @@ uint8 Rainbow2FlashID(uint8 chip, uint32 A) { // but some tests of the chip currently being used found it repeats in 512-byte patterns. // http://forums.nesdev.com/viewtopic.php?p=178728#p178728 + uint32 flash_size; + + if (chip == CHIP_TYPE_PRG) flash_size = ROM_size * 16; + else if (chip == CHIP_TYPE_CHR) flash_size = VROM_size * 8; + uint32 aid = A & 0x1FF; switch (aid) { - case 0: return 0xBF; - case 1: + case 0x00: return 0x01; // 0x01 = Cypress + case 0x02: { - switch (chip) + switch (flash_size) { - case CHIP_TYPE_PRG: - switch (ROM_size * 16) - { - case 128: return 0xD5; - case 256: return 0xD6; - case 512: return 0xD7; - default: return 0xFF; - } - case CHIP_TYPE_CHR: - switch (VROM_size * 8) - { - case 128: return 0xD5; - case 256: return 0xD6; - case 512: return 0xD7; - default: return 0xFF; - } + case 1024: return S29AL008_TOP ? 0xDA : 0x5B; // S29AL008: 0xDA = top boot block | 0x5B = bottom boot block + case 2048: return S29AL016_TOP ? 0xC4 : 0x49; // S29AL016: 0xC4 = top boot block | 0x49 = bottom boot block + case 4096: return 0x7E; // S29JL032 + case 8192: return 0x7E; // S29GL064S + default: return 0xFF; + } + } + case 0x1C: + { + switch (flash_size) + { + case 4096: return 0x0A; // S29JL032 + case 8192: return 0x10; // S29GL064S + default: return 0xFF; + } + } + case 0x1E: + { + switch (flash_size) + { + case 4096: return S29JL032_TOP ? 0x01 : 0x00; // S29JL032: 0x00 = bottom boot block | 0x01 = top boot block + case 8192: return S29GL064S_TOP ? 0x01 : 0x00; // S29GL064S: 0x00 = bottom boot block | 0x01 = top boot block + default: return 0xFF; } } default: return 0xFF; @@ -1236,7 +993,7 @@ void Rainbow2FlashIDEnter(uint8 chip) if (flash_id[chip]) return; flash_id[chip] = 1; - if (bootloader) + if (bootrom) SetReadHandler(0x8000, 0xDFFF, Rainbow2FlashPrgID); else SetReadHandler(0x8000, 0xFFFF, Rainbow2FlashPrgID); @@ -1277,12 +1034,13 @@ void Rainbow2FlashIDExit(uint8 chip) void Rainbow2Flash(uint8 chip, uint32 flash_addr, uint8 V) { - uint32 command_addr = flash_addr & 0x7FFF; + uint32 command_addr = flash_addr & 0x0FFF; enum { flash_mode_READY = 0, flash_mode_COMMAND, + flash_mode_UNLOCK_BYPASS, flash_mode_BYTE_WRITE, flash_mode_ERASE, }; @@ -1291,7 +1049,7 @@ void Rainbow2Flash(uint8 chip, uint32 flash_addr, uint8 V) { { default: case flash_mode_READY: - if (command_addr == 0x5555 && V == 0xAA) + if (command_addr == 0x0AAA && V == 0xAA) { flash_mode[chip] = flash_mode_COMMAND; flash_sequence[chip] = 0; @@ -1304,7 +1062,7 @@ void Rainbow2Flash(uint8 chip, uint32 flash_addr, uint8 V) { case flash_mode_COMMAND: if (flash_sequence[chip] == 0) { - if (command_addr == 0x2AAA && V == 0x55) + if (command_addr == 0x0555 && V == 0x55) { flash_sequence[chip] = 1; } @@ -1315,12 +1073,13 @@ void Rainbow2Flash(uint8 chip, uint32 flash_addr, uint8 V) { } else if (flash_sequence[chip] == 1) { - if (command_addr == 0x5555) + if (command_addr == 0x0AAA) { flash_sequence[chip] = 0; switch (V) { default: flash_mode[chip] = flash_mode_READY; break; + case 0x20: flash_mode[chip] = flash_mode_UNLOCK_BYPASS; break; case 0xA0: flash_mode[chip] = flash_mode_BYTE_WRITE; break; case 0x80: flash_mode[chip] = flash_mode_ERASE; break; case 0x90: Rainbow2FlashIDEnter(chip); flash_mode[chip] = flash_mode_READY; break; @@ -1333,56 +1092,174 @@ void Rainbow2Flash(uint8 chip, uint32 flash_addr, uint8 V) { else flash_mode[chip] = flash_mode_READY; // should be unreachable break; + case flash_mode_UNLOCK_BYPASS: + if (flash_sequence[chip] == 0) + { + switch (V) + { + case 0xA0: flash_sequence[chip] = 1; break; + case 0x90: flash_sequence[chip] = 2; break; + } + } + else if (flash_sequence[chip] == 1) + { + flash_sequence[chip] = 0; + if (chip == CHIP_TYPE_PRG) + { + if (PRG_FLASHROM[flash_addr] == 0xff) PRG_FLASHROM[flash_addr] &= V; + } + else if (chip == CHIP_TYPE_CHR) + { + if (CHR_FLASHROM[flash_addr] == 0xff) CHR_FLASHROM[flash_addr] &= V; + } + } + else if (flash_sequence[chip] == 2) + { + if (V == 0x00) + { + flash_sequence[chip] = 0; + flash_mode[chip] = flash_mode_READY; + } + } + break; case flash_mode_BYTE_WRITE: if (chip == CHIP_TYPE_PRG) { - PRG_FLASHROM[flash_addr] &= V; + if (PRG_FLASHROM[flash_addr] == 0xff) PRG_FLASHROM[flash_addr] &= V; } else if (chip == CHIP_TYPE_CHR) { - CHR_FLASHROM[flash_addr] &= V; + if (CHR_FLASHROM[flash_addr] == 0xff) CHR_FLASHROM[flash_addr] &= V; } flash_mode[chip] = flash_mode_READY; break; case flash_mode_ERASE: if (flash_sequence[chip] == 0) { - if (command_addr == 0x5555 && V == 0xAA) + if (command_addr == 0x0AAA && V == 0xAA) flash_sequence[chip] = 1; else flash_mode[chip] = flash_mode_READY; } else if (flash_sequence[chip] == 1) { - if (command_addr == 0x2AAA && V == 0x55) + if (command_addr == 0x0555 && V == 0x55) flash_sequence[chip] = 2; else flash_mode[chip] = flash_mode_READY; } else if (flash_sequence[chip] == 2) { - if (command_addr == 0x5555 && V == 0x10) // erase chip + if (command_addr == 0x0AAA && V == 0x10) // erase chip { if (chip == CHIP_TYPE_PRG) - { memset(PRG_FLASHROM, 0xFF, PRG_FLASHROMSIZE); - } else if (chip == CHIP_TYPE_CHR) - { memset(CHR_FLASHROM, 0xFF, CHR_FLASHROMSIZE); - } + } - else if (V == 0x30) // erase 4k sector + else if (V == 0x30) // erase sectors { - uint32 sector = flash_addr & 0x7F000; + uint32 sector_offset = (flash_addr & 0xFF0000); + uint8 sector_index = sector_offset >> 16; + uint8 sector_size = 64; + uint32 flash_size; + if (chip == CHIP_TYPE_PRG) - { - memset(PRG_FLASHROM + sector, 0xFF, 1024 * 4); - } + flash_size = ROM_size * 16; else if (chip == CHIP_TYPE_CHR) + flash_size = VROM_size * 8; + + switch (flash_size) { - memset(CHR_FLASHROM + sector, 0xFF, 1024 * 4); + case 1024: // S29AL008 + if (S29AL008_TOP && sector_index == 15) + { + if (flash_addr >= 0xF0000 && flash_addr <= 0xF7FFF) { sector_offset = 0xF0000; sector_size = 32; } + else if (flash_addr >= 0xF8000 && flash_addr <= 0xF9FFF) { sector_offset = 0xF8000; sector_size = 8; } + else if (flash_addr >= 0xFA000 && flash_addr <= 0xFBFFF) { sector_offset = 0xFA000; sector_size = 8; } + else if (flash_addr >= 0xFC000 && flash_addr <= 0xFFFFF) { sector_offset = 0xFC000; sector_size = 16; } + } + else if (!S29AL008_TOP && sector_index == 0) + { + if (flash_addr >= 0x00000 && flash_addr <= 0x03FFF) { sector_offset = 0x00000; sector_size = 16; } + else if (flash_addr >= 0x04000 && flash_addr <= 0x05FFF) { sector_offset = 0x04000; sector_size = 8; } + else if (flash_addr >= 0x06000 && flash_addr <= 0x07FFF) { sector_offset = 0x06000; sector_size = 8; } + else if (flash_addr >= 0x08000 && flash_addr <= 0x0FFFF) { sector_offset = 0x08000; sector_size = 32; } + } + break; + case 2048: // S29AL016 + if (S29AL016_TOP && sector_index == 31) + { + if (flash_addr >= 0x1F0000 && flash_addr <= 0x1F7FFF) { sector_offset = 0xF0000; sector_size = 32; } + else if (flash_addr >= 0x1F8000 && flash_addr <= 0x1F9FFF) { sector_offset = 0xF8000; sector_size = 8; } + else if (flash_addr >= 0x1FA000 && flash_addr <= 0x1FBFFF) { sector_offset = 0xFA000; sector_size = 8; } + else if (flash_addr >= 0x1FC000 && flash_addr <= 0x1FFFFF) { sector_offset = 0xFC000; sector_size = 16; } + } + else if (!S29AL016_TOP && sector_index == 0) + { + if (flash_addr >= 0x00000 && flash_addr <= 0x03FFF) { sector_offset = 0x00000; sector_size = 16; } + else if (flash_addr >= 0x04000 && flash_addr <= 0x05FFF) { sector_offset = 0x04000; sector_size = 8; } + else if (flash_addr >= 0x06000 && flash_addr <= 0x07FFF) { sector_offset = 0x06000; sector_size = 8; } + else if (flash_addr >= 0x08000 && flash_addr <= 0x0FFFF) { sector_offset = 0x08000; sector_size = 32; } + } + break; + case 4096: // S29JL032 + if (S29JL032_TOP && sector_index == 63) + { + if (flash_addr >= 0x3F0000 && flash_addr <= 0x3F1FFF) { sector_offset = 0x3F0000; sector_size = 8; } + else if (flash_addr >= 0x3F2000 && flash_addr <= 0x3F3FFF) { sector_offset = 0x3F2000; sector_size = 8; } + else if (flash_addr >= 0x3F4000 && flash_addr <= 0x3F5FFF) { sector_offset = 0x3F4000; sector_size = 8; } + else if (flash_addr >= 0x3F6000 && flash_addr <= 0x3F7FFF) { sector_offset = 0x3F6000; sector_size = 8; } + else if (flash_addr >= 0x3F8000 && flash_addr <= 0x3F9FFF) { sector_offset = 0x3F8000; sector_size = 8; } + else if (flash_addr >= 0x3FA000 && flash_addr <= 0x3FBFFF) { sector_offset = 0x3FA000; sector_size = 8; } + else if (flash_addr >= 0x3FC000 && flash_addr <= 0x3FDFFF) { sector_offset = 0x3FC000; sector_size = 8; } + else if (flash_addr >= 0x3FE000 && flash_addr <= 0x3FFFFF) { sector_offset = 0x3FE000; sector_size = 8; } + + } + else if (!S29JL032_TOP && sector_index == 0) + { + if (flash_addr >= 0x000000 && flash_addr <= 0x001FFF) { sector_offset = 0x000000; sector_size = 8; } + else if (flash_addr >= 0x002000 && flash_addr <= 0x003FFF) { sector_offset = 0x002000; sector_size = 8; } + else if (flash_addr >= 0x004000 && flash_addr <= 0x005FFF) { sector_offset = 0x004000; sector_size = 8; } + else if (flash_addr >= 0x006000 && flash_addr <= 0x007FFF) { sector_offset = 0x006000; sector_size = 8; } + else if (flash_addr >= 0x008000 && flash_addr <= 0x009FFF) { sector_offset = 0x008000; sector_size = 8; } + else if (flash_addr >= 0x00A000 && flash_addr <= 0x00BFFF) { sector_offset = 0x00A000; sector_size = 8; } + else if (flash_addr >= 0x00C000 && flash_addr <= 0x00DFFF) { sector_offset = 0x00C000; sector_size = 8; } + else if (flash_addr >= 0x00E000 && flash_addr <= 0x00FFFF) { sector_offset = 0x00E000; sector_size = 8; } + } + break; + case 8192: // S29GL064S + if (!S29GL064S_TOP && sector_index == 0) + { + if (flash_addr >= 0x000000 && flash_addr <= 0x001FFF) { sector_offset = 0x000000; sector_size = 8; } + else if (flash_addr >= 0x002000 && flash_addr <= 0x003FFF) { sector_offset = 0x002000; sector_size = 8; } + else if (flash_addr >= 0x004000 && flash_addr <= 0x005FFF) { sector_offset = 0x004000; sector_size = 8; } + else if (flash_addr >= 0x006000 && flash_addr <= 0x007FFF) { sector_offset = 0x006000; sector_size = 8; } + else if (flash_addr >= 0x008000 && flash_addr <= 0x009FFF) { sector_offset = 0x008000; sector_size = 8; } + else if (flash_addr >= 0x00A000 && flash_addr <= 0x00BFFF) { sector_offset = 0x00A000; sector_size = 8; } + else if (flash_addr >= 0x00C000 && flash_addr <= 0x00DFFF) { sector_offset = 0x00C000; sector_size = 8; } + else if (flash_addr >= 0x00E000 && flash_addr <= 0x00FFFF) { sector_offset = 0x00E000; sector_size = 8; } + } + else if (S29GL064S_TOP && sector_index == 127) + { + if (flash_addr >= 0x7F0000 && flash_addr <= 0x7F1FFF) { sector_offset = 0x7F0000; sector_size = 8; } + else if (flash_addr >= 0x7F2000 && flash_addr <= 0x7F3FFF) { sector_offset = 0x7F2000; sector_size = 8; } + else if (flash_addr >= 0x7F4000 && flash_addr <= 0x7F5FFF) { sector_offset = 0x7F4000; sector_size = 8; } + else if (flash_addr >= 0x7F6000 && flash_addr <= 0x7F7FFF) { sector_offset = 0x7F6000; sector_size = 8; } + else if (flash_addr >= 0x7F8000 && flash_addr <= 0x7F9FFF) { sector_offset = 0x7F8000; sector_size = 8; } + else if (flash_addr >= 0x7FA000 && flash_addr <= 0x7FBFFF) { sector_offset = 0x7FA000; sector_size = 8; } + else if (flash_addr >= 0x7FC000 && flash_addr <= 0x7FDFFF) { sector_offset = 0x7FC000; sector_size = 8; } + else if (flash_addr >= 0x7FE000 && flash_addr <= 0x7FFFFF) { sector_offset = 0x7FE000; sector_size = 8; } + } + break; } + + if (chip == CHIP_TYPE_PRG) + memset(PRG_FLASHROM + sector_offset, 0xFF, 1024 * sector_size); + else if (chip == CHIP_TYPE_CHR) + memset(CHR_FLASHROM + sector_offset, 0xFF, 1024 * sector_size); + } flash_mode[chip] = flash_mode_READY; } @@ -1392,11 +1269,14 @@ void Rainbow2Flash(uint8 chip, uint32 flash_addr, uint8 V) { } } -static DECLFW(Rainbow2PrgFlash) { +static DECLFW(RNBW_0x8000Wr) { if ((A < 0x6000) || A > (0xFFFF)) return; uint32 flash_addr = A; + + uint8 t_prg_rom_mode = bootrom ? PRG_ROM_MODE_3 : prg_rom_mode; + if ((A >= 0x6000) & (A < 0x8000)) { switch (prg_ram_mode) @@ -1431,7 +1311,7 @@ static DECLFW(Rainbow2PrgFlash) { } else if ((A >= 0x8000) & (A <= 0xFFFF)) { - switch (prg_rom_mode) + switch (t_prg_rom_mode) { case PRG_ROM_MODE_0: flash_addr &= 0x7FFF; @@ -1546,7 +1426,7 @@ static void Rainbow2PPUWrite(uint32 A, uint8 V) { // NOTE: plus les bons modes ? case CHR_MODE_0: flash_addr &= 0x1FFF; - flash_addr |= (chr[0] & 0xffff) << 13; + flash_addr |= (chr[A >> 13] & 0xffff) << 13; break; case CHR_MODE_1: flash_addr &= 0xFFF; @@ -1572,9 +1452,9 @@ static void Rainbow2PPUWrite(uint32 A, uint8 V) { } static void Rainbow2Reset(void) { - // PRG - 32K banks mapped to last PRG-ROM bank + // PRG - 32K banks mapped to first PRG-ROM bank prg_rom_mode = PRG_ROM_MODE_0; - prg[3] = 0x7FFF; + prg[3] = 0; // CHR - 8K banks mapped to first bank of CHR-ROM // extended sprite mode disabled @@ -1617,7 +1497,8 @@ static void Rainbow2Reset(void) { static void Rainbow2Power(void) { // mapper init - bootloader = 0x00; + if(MiscROMS) bootrom = 1; + else bootrom = 0; Rainbow2Reset(); SetReadHandler(0x4800, 0xFFFF, CartBR); @@ -1629,13 +1510,13 @@ static void Rainbow2Power(void) { FCEU_CheatAddRAM(0x1800 >> 10, 0x4800, FPGA_RAM); */ // mapper registers (writes) - SetWriteHandler(0x4100, 0x47ff, Rainbow2Write); + SetWriteHandler(0x4100, 0x47ff, RNBW_0x4100Wr); // mapper registers (reads) - SetReadHandler(0x4100, 0x47ff, Rainbow2Read); + SetReadHandler(0x4100, 0x47ff, RNBW_0x4100Rd); // audio expansion registers (writes) - SetWriteHandler(0x41A0, 0x41A8, Rainbow2SW); + SetWriteHandler(0x41A0, 0x41A8, RNBW_ExpAudioWr); // FPGA WRAM @ $4800-$4fff (reads/writes) SetWriteHandler(0x4800, 0x4fff, FPGA_0x4800Wr); @@ -1656,16 +1537,16 @@ static void Rainbow2Power(void) { flash_sequence[CHIP_TYPE_CHR] = 0; flash_id[CHIP_TYPE_PRG] = false; flash_id[CHIP_TYPE_CHR] = false; - SetWriteHandler(0x8000, 0xFFFF, Rainbow2PrgFlash); + SetWriteHandler(0x8000, 0xFFFF, RNBW_0x8000Wr); // fill WRAM/FPGA_RAM/CHRRAM/DUMMY_CHRRAM/DUMMY_CHRROM with random values - if (WRAM && RNBWbattery) + if (WRAM && !RNBWbattery) FCEU_MemoryRand(WRAM, WRAMSIZE, false); - if (FPGA_RAM && RNBWbattery) + if (FPGA_RAM && !RNBWbattery) FCEU_MemoryRand(FPGA_RAM, FPGA_RAMSIZE, false); - if (CHRRAM && RNBWbattery) + if (CHRRAM && !RNBWbattery) FCEU_MemoryRand(CHRRAM, CHRRAMSIZE, false); if (DUMMY_CHRRAM) @@ -1674,10 +1555,20 @@ static void Rainbow2Power(void) { if (DUMMY_CHRROM) FCEU_MemoryRand(DUMMY_CHRROM, DUMMY_CHRROMSIZE, false); - // init FPGA RAM with bootloader CHR data - for (size_t i = 0; i < 4096; i++) + // init FPGA RAM with bootrom CHR data + for (size_t i = 0; i < 0x1000; i++) { - FPGA_RAM[i] = bootloader_chr[i]; + FPGA_RAM[i] = bootrom_chr[i]; + } + + // init FPGA RAM with bootrom PRG data + if (MiscROMS) + { + // init FPGA_RAM with MISC ROM data + for (size_t i = 0; i < 0xE00; i++) + { + FPGA_RAM[0x1000 + i] = MiscROMS[i]; + } } // ESP firmware @@ -1960,7 +1851,7 @@ static void Rainbow2ESI(void) { void NSFRainbow2_Init(void) { Rainbow2ESI(); - SetWriteHandler(0x8000, 0xbfff, Rainbow2SW); + SetWriteHandler(0x8000, 0xbfff, RNBW_ExpAudioWr); } #endif @@ -1976,13 +1867,34 @@ void RAINBOW2_Init(CartInfo *info) { // WRAM if (info->wram_size != 0) { - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - if (RNBWbattery) + if (info->wram_size > 0x80000) { - info->addSaveGameBuf(WRAM, WRAMSIZE); + WRAMSIZE = 0x80000; // maximum is 512KiB + } + else if (info->wram_size > 0x80000) + { + WRAMSIZE = 0x8000; // minimum is 32Kib + } + else + { + WRAMSIZE = info->wram_size & 0xF8000; // we need this to match the hardware as close as possible + } + + if (WRAMSIZE != 0) + { + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + info->wram_size = WRAMSIZE; + + if (RNBWbattery) + { + info->addSaveGameBuf(WRAM, WRAMSIZE); + } + } + else + { + info->wram_size = 0; } } @@ -2005,7 +1917,7 @@ void RAINBOW2_Init(CartInfo *info) { } // copy PRG ROM into PRG_FLASHROM, use it instead of PRG ROM - const uint32 PRGSIZE = ROM_size * 16 * 1024; + PRGSIZE = ROM_size * 16 * 1024; for (uint32 w = 0, r = 0; w < PRG_FLASHROMSIZE; ++w) { PRG_FLASHROM[w] = ROM[r]; @@ -2018,11 +1930,33 @@ void RAINBOW2_Init(CartInfo *info) { // CHR-RAM if (info->vram_size != 0) { - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x11, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - ExtraNTARAM = CHRRAM + 30 * 1024; - AddExState(ExtraNTARAM, 2048, 0, "EXNR"); + if (info->vram_size > 0x80000) + { + CHRRAMSIZE = 0x80000; // maximum is 512KiB + } + else if (info->vram_size > 0x80000) + { + CHRRAMSIZE = 0x8000; // minimum is 32Kib + } + else + { + CHRRAMSIZE = info->vram_size & 0xF8000; // we need this to match the hardware as close as possible + } + + if (CHRRAMSIZE != 0) + { + CHRRAMSIZE = info->vram_size; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x11, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); + ExtraNTARAM = CHRRAM + 30 * 1024; + AddExState(ExtraNTARAM, 2048, 0, "EXNR"); + info->vram_size = CHRRAMSIZE; + } + else + { + info->vram_size = 0; + } } else { @@ -2044,7 +1978,7 @@ void RAINBOW2_Init(CartInfo *info) { } // copy CHR ROM into CHR_FLASHROM, use it instead of CHR ROM - const uint32 CHRSIZE = VROM_size * 8 * 1024; + CHRSIZE = VROM_size * 8 * 1024; for (uint32 w = 0, r = 0; w < CHR_FLASHROMSIZE; ++w) { CHR_FLASHROM[w] = VROM[r]; @@ -2062,6 +1996,12 @@ void RAINBOW2_Init(CartInfo *info) { SetupCartCHRMapping(0x10, DUMMY_CHRROM, DUMMY_CHRROMSIZE, 0); } + // BOOTROM + if (info->misc_roms != 0 && MiscROMS) + { + SetupCartPRGMapping(0x13, MiscROMS, MiscROMS_size, 0); + } + FFCEUX_PPURead = Rainbow2PPURead; FFCEUX_PPUWrite = Rainbow2PPUWrite; diff --git a/src/boards/rainbow_esp.cpp b/src/boards/rainbow_esp.cpp index 8d9c849c..cb4b304d 100644 --- a/src/boards/rainbow_esp.cpp +++ b/src/boards/rainbow_esp.cpp @@ -90,7 +90,7 @@ std::vector readHostFile(std::string const& file_path) { return data; } -std::array dir_names = { "SAVE", "ROMS", "USER" }; +std::array dir_names = { "save", "roms", "user" }; } @@ -118,7 +118,7 @@ BrokeStudioFirmware::BrokeStudioFirmware() { this->nc = mg_bind(&this->mgr, httpd_port, BrokeStudioFirmware::httpdEvent); if (this->nc == NULL) { printf("Failed to create web server\n"); - }else { + } else { mg_set_protocol_http_websocket(this->nc); this->httpd_thread = std::thread([this] { while (this->httpd_run) { @@ -128,15 +128,6 @@ BrokeStudioFirmware::BrokeStudioFirmware() { }); } - // Clear file list - for (uint8 p = 0; p < NUM_FILE_PATHS; p++) - { - for (uint8 f = 0; f < NUM_FILES; f++) - { - this->file_exists[p][f] = false; - } - } - // Init fake registered networks this->networks = { { {"FCEUX_SSID", "FCEUX_PASS", true}, @@ -230,7 +221,11 @@ void BrokeStudioFirmware::processBufferedMessage() { case toesp_cmds_t::ESP_GET_STATUS: UDBG("RAINBOW BrokeStudioFirmware received message ESP_GET_STATUS\n"); - this->tx_messages.push_back({1, static_cast(fromesp_cmds_t::READY)}); + this->tx_messages.push_back({ + 2, + static_cast(fromesp_cmds_t::READY), + static_cast(isSdCardFilePresent ? 1 : 0) + }); break; case toesp_cmds_t::DEBUG_GET_LEVEL: UDBG("RAINBOW BrokeStudioFirmware received message DEBUG_GET_LEVEL\n"); @@ -293,22 +288,46 @@ void BrokeStudioFirmware::processBufferedMessage() { break; case toesp_cmds_t::ESP_GET_FIRMWARE_VERSION: UDBG("RAINBOW BrokeStudioFirmware received message ESP_GET_FIRMWARE_VERSION\n"); - this->tx_messages.push_back({ 7, static_cast(fromesp_cmds_t::ESP_FIRMWARE_VERSION), 5, 'F', 'C', 'E', 'U', 'X' }); + this->tx_messages.push_back({ 16, static_cast(fromesp_cmds_t::ESP_FIRMWARE_VERSION), 14, 'F', 'C', 'E', 'U', 'X', '_', 'F', 'I', 'R', 'M', 'W', 'A', 'R', 'E' }); + break; + + case toesp_cmds_t::ESP_FACTORY_SETTINGS: + UDBG("RAINBOW BrokeStudioFirmware received message ESP_FACTORY_SETTINGS\n"); + UDBG("ESP_FACTORY_SETTINGS has no use here\n"); + this->tx_messages.push_back({2,static_cast(fromesp_cmds_t::ESP_FACTORY_RESET),static_cast(esp_factory_reset::ERROR_WHILE_RESETTING_CONFIG)}); + break; + + case toesp_cmds_t::ESP_RESTART: + UDBG("RAINBOW BrokeStudioFirmware received message ESP_RESTART\n"); + UDBG("ESP_RESTART has no use here\n"); break; // WIFI CMDS case toesp_cmds_t::WIFI_GET_STATUS: UDBG("RAINBOW BrokeStudioFirmware received message WIFI_GET_STATUS\n"); - this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::WIFI_STATUS), 3 }); // Simple answer, wifi is ok + this->tx_messages.push_back({ 3, static_cast(fromesp_cmds_t::WIFI_STATUS), 3, 0 }); // Simple answer, wifi is ok break; + // WIFI_GET_SSID/WIFI_GET_IP config commands are not relevant here, so we'll just use fake data case toesp_cmds_t::WIFI_GET_SSID: UDBG("RAINBOW BrokeStudioFirmware received message WIFI_GET_SSID\n"); - this->tx_messages.push_back({ 12, static_cast(fromesp_cmds_t::SSID), 10, 'F', 'C', 'E', 'U', 'X', '_', 'S', 'S', 'I', 'D' }); + if ((this->wifi_config & static_cast(wifi_config_t::WIFI_ENABLE)) == static_cast(wifi_config_t::WIFI_ENABLE)) + { + this->tx_messages.push_back({ 12, static_cast(fromesp_cmds_t::SSID), 10, 'F', 'C', 'E', 'U', 'X', '_', 'S', 'S', 'I', 'D' }); + } else + { + this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::SSID), 0 }); + } break; case toesp_cmds_t::WIFI_GET_IP: - UDBG("RAINBOW BrokeStudioFirmware received message WIFI_GET_ID\n"); - this->tx_messages.push_back({ 14, static_cast(fromesp_cmds_t::IP_ADDRESS), 12, '1', '9', '2', '.', '1', '6', '8', '.', '1', '.', '1', '0' }); + UDBG("RAINBOW BrokeStudioFirmware received message WIFI_GET_IP\n"); + if ((this->wifi_config & static_cast(wifi_config_t::WIFI_ENABLE)) == static_cast(wifi_config_t::WIFI_ENABLE)) + { + this->tx_messages.push_back({ 14, static_cast(fromesp_cmds_t::IP_ADDRESS), 12, '1', '9', '2', '.', '1', '6', '8', '.', '1', '.', '1', '0' }); + } else + { + this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::IP_ADDRESS), 0 }); + } break; case toesp_cmds_t::WIFI_GET_CONFIG: UDBG("RAINBOW BrokeStudioFirmware received message WIFI_GET_CONFIG\n"); @@ -320,14 +339,26 @@ void BrokeStudioFirmware::processBufferedMessage() { break; // AP CMDS - // GET/SET AP config commands are not relevant here, so we'll just use a fake variable + // AP_GET_SSID/AP_GET_IP config commands are not relevant here, so we'll just use fake data case toesp_cmds_t::AP_GET_SSID: UDBG("RAINBOW BrokeStudioFirmware received message AP_GET_SSID\n"); - this->tx_messages.push_back({ 12, static_cast(fromesp_cmds_t::SSID), 10, 'F', 'C', 'E', 'U', 'X', '_', 'S', 'S', 'I', 'D' }); + if ((this->wifi_config & static_cast(wifi_config_t::AP_ENABLE)) == static_cast(wifi_config_t::AP_ENABLE)) + { + this->tx_messages.push_back({ 15, static_cast(fromesp_cmds_t::SSID), 13, 'F', 'C', 'E', 'U', 'X', '_', 'A', 'P', '_', 'S', 'S', 'I', 'D' }); + } else + { + this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::SSID), 0 }); + } break; case toesp_cmds_t::AP_GET_IP: UDBG("RAINBOW BrokeStudioFirmware received message AP_GET_ID\n"); - this->tx_messages.push_back({ 16, static_cast(fromesp_cmds_t::IP_ADDRESS), 14, '1', '2', '7', '.', '0', '.', '0', '.', '1', ':', '8', '0', '8', '0' }); + if ((this->wifi_config & static_cast(wifi_config_t::AP_ENABLE)) == static_cast(wifi_config_t::AP_ENABLE)) + { + this->tx_messages.push_back({ 16, static_cast(fromesp_cmds_t::IP_ADDRESS), 14, '1', '2', '7', '.', '0', '.', '0', '.', '1', ':', '8', '0', '8', '0' }); + } else + { + this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::IP_ADDRESS), 0 }); + } break; // RND CMDS @@ -465,8 +496,18 @@ void BrokeStudioFirmware::processBufferedMessage() { } break; } - case toesp_cmds_t::SERVER_GET_CONFIG_SETTINGS: { - UDBG("RAINBOW BrokeStudioFirmware received message SERVER_GET_CONFIG_SETTINGS\n"); + case toesp_cmds_t::SERVER_SET_SETTINGS: + UDBG("RAINBOW BrokeStudioFirmware received message SERVER_SET_SETTINGS\n"); + if (message_size >= 3) { + this->server_settings_port = + (static_cast(this->rx_buffer.at(2)) << 8) + + (static_cast(this->rx_buffer.at(3))); + uint8 len = this->rx_buffer.at(4); + this->server_settings_address = std::string(this->rx_buffer.begin() + 4, this->rx_buffer.begin() + 4 + len); + } + break; + case toesp_cmds_t::SERVER_GET_SAVED_SETTINGS: { + UDBG("RAINBOW BrokeStudioFirmware received message SERVER_GET_SAVED_SETTINGS\n"); if (this->default_server_settings_address.empty() && this->default_server_settings_port == 0) { this->tx_messages.push_back({ 1, @@ -485,18 +526,19 @@ void BrokeStudioFirmware::processBufferedMessage() { } break; } - case toesp_cmds_t::SERVER_SET_SETTINGS: - UDBG("RAINBOW BrokeStudioFirmware received message SERVER_SET_SETTINGS\n"); - if (message_size >= 3) { - this->server_settings_port = - (static_cast(this->rx_buffer.at(2)) << 8) + - (static_cast(this->rx_buffer.at(3))); - uint8 len = this->rx_buffer.at(4); - this->server_settings_address = std::string(this->rx_buffer.begin()+4, this->rx_buffer.begin()+4+len); - } + case toesp_cmds_t::SERVER_SET_SAVED_SETTINGS: { + UDBG("RAINBOW BrokeStudioFirmware received message SERVER_SET_SAVED_SETTINGS\n"); + this->default_server_settings_port = + (static_cast(this->rx_buffer.at(2)) << 8) + + (static_cast(this->rx_buffer.at(3))); + uint8 len = this->rx_buffer.at(4); + this->default_server_settings_address = std::string(this->rx_buffer.begin() + 4, this->rx_buffer.begin() + 4 + len); + this->server_settings_port = this->default_server_settings_port; + this->server_settings_address = default_server_settings_address; break; - case toesp_cmds_t::SERVER_RESTORE_SETTINGS: - UDBG("RAINBOW BrokeStudioFirmware received message SERVER_RESTORE_SETTINGS\n"); + } + case toesp_cmds_t::SERVER_RESTORE_SAVED_SETTINGS: + UDBG("RAINBOW BrokeStudioFirmware received message SERVER_RESTORE_SAVED_SETTINGS\n"); this->server_settings_address = this->default_server_settings_address; this->server_settings_port = this->default_server_settings_port; break; @@ -599,7 +641,7 @@ void BrokeStudioFirmware::processBufferedMessage() { if (networkItem > NUM_NETWORKS - 1) break; bool const networkActive = this->rx_buffer.at(3) == 0 ? false : true; if (networkActive) { - for (size_t i = 0; i < NUM_NETWORKS; i++) + for (size_t i = 0; i < NUM_NETWORKS; ++i) { this->networks[i].active = false; } @@ -631,7 +673,7 @@ void BrokeStudioFirmware::processBufferedMessage() { UDBG("%d (%s)\n", networkItem, networkActive ? "active" : "inactive"); if (this->networks[networkItem].ssid == "") break; if (networkActive) { - for (size_t i = 0; i < NUM_NETWORKS; i++) + for (size_t i = 0; i < NUM_NETWORKS; ++i) { this->networks[i].active = false; } @@ -646,56 +688,75 @@ void BrokeStudioFirmware::processBufferedMessage() { UDBG("RAINBOW BrokeStudioFirmware received message FILE_OPEN\n"); if (message_size >= 4) { uint8 config = this->rx_buffer.at(2); - uint8 access_mode = config & static_cast(file_config_flags_t::ACCESS_MODE); + FileConfig file_config = parseFileConfig(config); + std::string filename; - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { uint8 const path = this->rx_buffer.at(3); uint8 const file = this->rx_buffer.at(4); if (path < NUM_FILE_PATHS && file < NUM_FILES) { - this->file_exists[path][file] = true; - this->working_path = path; - this->working_file = file; - this->working_file_config = config; - this->file_offset = 0; - this->saveFiles(); + filename = getAutoFilename(path, file); + int i = findFile(file_config.drive, filename); + if (i == -1) { + FileStruct temp_file = { file_config.drive, filename, std::vector() }; + this->files.push_back(temp_file); + } + } + } else if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_MANUAL)) { + uint8 const path_length = this->rx_buffer.at(3); + filename = std::string(this->rx_buffer.begin() + 4, this->rx_buffer.begin() + 4 + path_length); + int i = findFile(file_config.drive, filename); + if (i == -1) { + FileStruct temp_file = { file_config.drive, filename, std::vector() }; + this->files.push_back(temp_file); } - }else { - //TODO manual mode } + int i = findFile(file_config.drive, filename); + this->working_file.active = true; + this->working_file.offset = 0; + this->working_file.file = &this->files.at(i); + this->saveFiles(); } break; } case toesp_cmds_t::FILE_CLOSE: UDBG("RAINBOW BrokeStudioFirmware received message FILE_CLOSE\n"); - this->working_file = NO_WORKING_FILE; + this->working_file.active = false; this->saveFiles(); break; case toesp_cmds_t::FILE_STATUS: { UDBG("RAINBOW BrokeStudioFirmware received message FILE_STATUS\n"); - uint8 access_mode = this->working_file_config & static_cast(file_config_flags_t::ACCESS_MODE); - - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { - if (this->working_file == NO_WORKING_FILE) { - this->tx_messages.push_back({ - 2, - static_cast(fromesp_cmds_t::FILE_STATUS), - 0 + if (this->working_file.active == false) { + this->tx_messages.push_back({ + 2, + static_cast(fromesp_cmds_t::FILE_STATUS), + 0 }); - }else { + } else { + FileConfig file_config = parseFileConfig(this->working_file.config); + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { this->tx_messages.push_back({ 5, static_cast(fromesp_cmds_t::FILE_STATUS), 1, - static_cast(this->working_file_config), - static_cast(this->working_path), - static_cast(this->working_file), - }); + static_cast(this->working_file.config), + static_cast(this->working_file.auto_path), + static_cast(this->working_file.auto_file), + }); + } else if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_MANUAL)) { + std::string filename = this->working_file.file->filename; + filename = filename.substr(filename.find_first_of("/") + 1); + std::deque message({ + static_cast(3 + filename.size()), + static_cast(fromesp_cmds_t::FILE_STATUS), + 1, + static_cast(filename.size()), + }); + message.insert(message.end(), filename.begin(), filename.end()); + this->tx_messages.push_back(message); } } - else { - //TODO manual mode - } break; } case toesp_cmds_t::FILE_EXISTS: { @@ -705,23 +766,43 @@ void BrokeStudioFirmware::processBufferedMessage() { break; } uint8 config = this->rx_buffer.at(2); - uint8 access_mode = config & static_cast(file_config_flags_t::ACCESS_MODE); + FileConfig file_config = parseFileConfig(config); + std::string filename; + int i = -1; - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { if (message_size == 4) { uint8 const path = this->rx_buffer.at(3); uint8 const file = this->rx_buffer.at(4); - if (path < NUM_FILE_PATHS && file < NUM_FILES) { - this->tx_messages.push_back({ - 2, - static_cast(fromesp_cmds_t::FILE_EXISTS), - static_cast(this->file_exists[path][file] ? 1 : 0) - }); - } + filename = getAutoFilename(path, file); } - }else { - //TODO manual mode + }else if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_MANUAL)) { + uint8 const path_length = this->rx_buffer.at(3); + filename = std::string(this->rx_buffer.begin() + 4, this->rx_buffer.begin() + 4 + path_length); } + + // special case just for emulation + if (filename == "/web/") + { + if (::getenv("RAINBOW_WWW_ROOT") != NULL) i = 1; + } + else + { + if (filename.find_last_of("/") == filename.length() - 1) + { + i = findPath(file_config.drive, filename); + } + else + { + i = findFile(file_config.drive, filename); + } + } + + this->tx_messages.push_back({ + 2, + static_cast(fromesp_cmds_t::FILE_EXISTS), + static_cast(i == -1 ? 0 : 1) + }); break; } case toesp_cmds_t::FILE_DELETE: { @@ -731,67 +812,77 @@ void BrokeStudioFirmware::processBufferedMessage() { break; } uint8 config = this->rx_buffer.at(2); - uint8 access_mode = config & static_cast(file_config_flags_t::ACCESS_MODE); + FileConfig file_config = parseFileConfig(config); + std::string filename; + int i = -1; - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { if (message_size == 4) { uint8 const path = this->rx_buffer.at(3); uint8 const file = this->rx_buffer.at(4); if (path < NUM_FILE_PATHS && file < NUM_FILES) { - if (this->file_exists[path][file]) { - // File exists, let's delete it - this->files[path][file].clear(); - this->file_exists[path][file] = false; - this->tx_messages.push_back({ - 2, - static_cast(fromesp_cmds_t::FILE_DELETE), - static_cast(file_delete_results_t::SUCCESS) - }); - this->saveFiles(); - }else { - // File does not exist - this->tx_messages.push_back({ - 2, - static_cast(fromesp_cmds_t::FILE_DELETE), - static_cast(file_delete_results_t::FILE_NOT_FOUND) - }); - } - }else { - // Error while deleting the file + filename = getAutoFilename(path, file); + } else { + // Invalid path or file this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::FILE_DELETE), static_cast(file_delete_results_t::INVALID_PATH_OR_FILE) }); + break; } } } - else { - //TODO manual mode + else if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_MANUAL)) { + uint8 const path_length = this->rx_buffer.at(4); + filename = std::string(this->rx_buffer.begin() + 5, this->rx_buffer.begin() + 5 + path_length); } + + i = findFile(file_config.drive, filename); + if (i == -1) { + // File does not exist + this->tx_messages.push_back({ + 2, + static_cast(fromesp_cmds_t::FILE_DELETE), + static_cast(file_delete_results_t::FILE_NOT_FOUND) + }); + break; + } else { + this->files.erase(this->files.begin() + i); + this->saveFiles(); + } + + this->tx_messages.push_back({ + 2, + static_cast(fromesp_cmds_t::FILE_DELETE), + static_cast(file_delete_results_t::SUCCESS) + }); + break; } case toesp_cmds_t::FILE_SET_CUR: UDBG("RAINBOW BrokeStudioFirmware received message FILE_SET_CUR\n"); if (2 <= message_size && message_size <= 5) { - this->file_offset = this->rx_buffer.at(2); - this->file_offset += static_cast(message_size >= 3 ? this->rx_buffer.at(3) : 0) << 8; - this->file_offset += static_cast(message_size >= 4 ? this->rx_buffer.at(4) : 0) << 16; - this->file_offset += static_cast(message_size >= 5 ? this->rx_buffer.at(5) : 0) << 24; + if (this->working_file.active) { + this->working_file.offset = this->rx_buffer.at(2); + this->working_file.offset += static_cast(message_size >= 3 ? this->rx_buffer.at(3) : 0) << 8; + this->working_file.offset += static_cast(message_size >= 4 ? this->rx_buffer.at(4) : 0) << 16; + this->working_file.offset += static_cast(message_size >= 5 ? this->rx_buffer.at(5) : 0) << 24; + } } break; case toesp_cmds_t::FILE_READ: UDBG("RAINBOW BrokeStudioFirmware received message FILE_READ\n"); if (message_size == 2) { - if (this->working_file != NO_WORKING_FILE) { + if (this->working_file.active) { uint8 const n = this->rx_buffer.at(2); - this->readFile(this->working_path, this->working_file, n, this->file_offset); - this->file_offset += n; - UDBG("working file offset: %u (%x)\n", this->file_offset, this->file_offset); - UDBG("file size: %lu bytes\n", this->files[this->working_path][this->working_file].size()); - if (this->file_offset > this->files[this->working_path][this->working_file].size()) { - this->file_offset = this->files[this->working_path][this->working_file].size(); - } + this->readFile(n); + this->working_file.offset += n; + UDBG("working file offset: %u (%x)\n", this->working_file.offset, this->working_file.offset); + /*UDBG("file size: %lu bytes\n", this->esp_files[this->working_path_auto][this->working_file_auto].size()); + if (this->working_file.offset > this->esp_files[this->working_path_auto][this->working_file_auto].size()) { + this->working_file.offset = this->esp_files[this->working_path_auto][this->working_file_auto].size(); + }*/ }else { this->tx_messages.push_back({2, static_cast(fromesp_cmds_t::FILE_DATA), 0}); } @@ -799,15 +890,15 @@ void BrokeStudioFirmware::processBufferedMessage() { break; case toesp_cmds_t::FILE_WRITE: UDBG("RAINBOW BrokeStudioFirmware received message FILE_WRITE\n"); - if (message_size >= 3 && this->working_file != NO_WORKING_FILE) { - this->writeFile(this->working_path, this->working_file, this->file_offset, this->rx_buffer.begin() + 2, this->rx_buffer.begin() + message_size + 1); - this->file_offset += message_size - 1; + if (message_size >= 3 && this->working_file.active) { + this->writeFile(this->rx_buffer.begin() + 2, this->rx_buffer.begin() + message_size + 1); + this->working_file.offset += message_size - 1; } break; case toesp_cmds_t::FILE_APPEND: UDBG("RAINBOW BrokeStudioFirmware received message FILE_APPEND\n"); - if (message_size >= 3 && this->working_file != NO_WORKING_FILE) { - this->writeFile(this->working_path, this->working_file, this->files[working_path][working_file].size(), this->rx_buffer.begin() + 2, this->rx_buffer.begin() + message_size + 1); + if (message_size >= 3 && this->working_file.active) { + //this->appendFile(this->rx_buffer.begin() + 2, this->rx_buffer.begin() + message_size + 1); } break; case toesp_cmds_t::FILE_COUNT: { @@ -817,9 +908,9 @@ void BrokeStudioFirmware::processBufferedMessage() { break; } uint8 config = this->rx_buffer.at(2); - uint8 access_mode = config & static_cast(file_config_flags_t::ACCESS_MODE); + FileConfig file_config = parseFileConfig(config); - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { if (message_size == 3) { uint8 const path = this->rx_buffer.at(3); if (path >= NUM_FILE_PATHS) { @@ -830,20 +921,22 @@ void BrokeStudioFirmware::processBufferedMessage() { }); }else { uint8 nb_files = 0; - for (bool exists : this->file_exists[path]) { - if (exists) { - ++nb_files; - } + + for (uint8_t file = 0; file < NUM_FILES; ++file) { + std::string filename = getAutoFilename(path, file); + int i = findFile(file_config.drive, filename); + if (i != -1) nb_files++; } + this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::FILE_COUNT), nb_files - }); + }); UDBG("%u files found in path %u\n", nb_files, path); } } - }else { + } else { //TODO manual mode } @@ -855,9 +948,9 @@ void BrokeStudioFirmware::processBufferedMessage() { break; } uint8 config = this->rx_buffer.at(2); - uint8 access_mode = config & static_cast(file_config_flags_t::ACCESS_MODE); + FileConfig file_config = parseFileConfig(config); - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { if (message_size >= 3) { std::vector existing_files; uint8 const path = this->rx_buffer.at(3); @@ -869,18 +962,31 @@ void BrokeStudioFirmware::processBufferedMessage() { } uint8 page_start = current_page * page_size; uint8 page_end = current_page * page_size + page_size; - uint8 nFiles = 0; - if (page_end > this->file_exists[path].size()) - page_end = this->file_exists[path].size(); - for (uint8 i = 0; i < NUM_FILES; ++i) { - if (this->file_exists[path][i]) { - if (nFiles >= page_start && nFiles < page_end) { - existing_files.push_back(i); - } - nFiles++; - } - if (nFiles >= page_end) break; + uint8 nb_files = 0; + + for (uint8_t file = 0; file < NUM_FILES; ++file) { + std::string filename = getAutoFilename(path, file); + int i = findFile(file_config.drive, filename); + if (i != -1) nb_files++; } + + if (page_end > nb_files) { + page_end = nb_files; + } + + nb_files = 0; + for (uint8_t file = 0; file < NUM_FILES; ++file) { + std::string filename = getAutoFilename(path, file); + int i = findFile(file_config.drive, filename); + if (i != -1) { + if (nb_files >= page_start && nb_files < page_end) { + existing_files.push_back(file); + } + nb_files++; + } + if (nb_files >= page_end) break; + } + std::deque message({ static_cast(existing_files.size() + 2), static_cast(fromesp_cmds_t::FILE_LIST), @@ -889,32 +995,152 @@ void BrokeStudioFirmware::processBufferedMessage() { message.insert(message.end(), existing_files.begin(), existing_files.end()); this->tx_messages.push_back(message); } - } - else { + } else { //TODO manual mode + this->tx_messages.push_back({ + 2, + static_cast(fromesp_cmds_t::FILE_LIST), + 0 + }); } break; } case toesp_cmds_t::FILE_GET_FREE_ID: UDBG("RAINBOW BrokeStudioFirmware received message FILE_GET_FREE_ID\n"); - if (message_size == 2) { - uint8 const file_id = this->getFreeFileId(this->rx_buffer.at(2)); - if (file_id != 128) { + if (message_size == 3) { + uint8 const drive = this->rx_buffer.at(2); + uint8 const path = this->rx_buffer.at(3); + uint8 i; + + for (i = 0; i < NUM_FILES; ++i) { + std::string filename = getAutoFilename(path, i); + int f = findFile(drive, filename); + if (f == -1) break; + } + + if (i != NUM_FILES) { // Free file ID found this->tx_messages.push_back({ 2, static_cast(fromesp_cmds_t::FILE_ID), - file_id, - }); - }else { + i, + }); + } + else { // Free file ID not found this->tx_messages.push_back({ 1, static_cast(fromesp_cmds_t::FILE_ID) - }); + }); } } break; + case toesp_cmds_t::FILE_GET_FS_INFO: { + UDBG("RAINBOW BrokeStudioFirmware received message FILE_GET_FS_INFO\n"); + if (message_size < 2) { + break; + } + uint8 config = this->rx_buffer.at(2); + FileConfig file_config = parseFileConfig(config); + uint64 free = 0; + uint64 used = 0; + uint8 free_pct = 0; + uint8 used_pct = 0; + if (file_config.drive == static_cast(file_config_flags_t::DESTINATION_ESP)) { + + for (size_t i = 0; i < this->files.size(); ++i) { + if ((this->files.at(i).drive == static_cast(file_config_flags_t::DESTINATION_ESP))) { + used += this->files.at(i).data.size(); + } + } + + free = ESP_FLASH_SIZE - used; + free_pct = ((ESP_FLASH_SIZE - used) * 100) / ESP_FLASH_SIZE; + used_pct = 100 - free_pct; // (used * 100) / ESP_FLASH_SIZE; + + this->tx_messages.push_back({ + 27, + static_cast(fromesp_cmds_t::FILE_FS_INFO), + (ESP_FLASH_SIZE >> 54) & 0xff, + (ESP_FLASH_SIZE >> 48) & 0xff, + (ESP_FLASH_SIZE >> 40) & 0xff, + (ESP_FLASH_SIZE >> 32) & 0xff, + (ESP_FLASH_SIZE >> 24) & 0xff, + (ESP_FLASH_SIZE >> 16) & 0xff, + (ESP_FLASH_SIZE >> 8) & 0xff, + (ESP_FLASH_SIZE) & 0xff, + static_cast((free >> 54) & 0xff), + static_cast((free >> 48) & 0xff), + static_cast((free >> 40) & 0xff), + static_cast((free >> 32) & 0xff), + static_cast((free >> 24) & 0xff), + static_cast((free >> 16) & 0xff), + static_cast((free >> 8) & 0xff), + static_cast((free) & 0xff), + free_pct, + static_cast((used >> 54) & 0xff), + static_cast((used >> 48) & 0xff), + static_cast((used >> 40) & 0xff), + static_cast((used >> 32) & 0xff), + static_cast((used >> 24) & 0xff), + static_cast((used >> 16) & 0xff), + static_cast((used >> 8) & 0xff), + static_cast((used) & 0xff), + used_pct + }); + break; + } else if (file_config.drive == static_cast(file_config_flags_t::DESTINATION_SD)) { + if (isSdCardFilePresent) { + + for (size_t i = 0; i < this->files.size(); ++i) { + if ((this->files.at(i).drive == static_cast(file_config_flags_t::DESTINATION_SD))) { + used += this->files.at(i).data.size(); + } + } + + free = SD_CARD_SIZE - used; + free_pct = ((SD_CARD_SIZE - used) * 100) / SD_CARD_SIZE; + used_pct = 100 - free_pct; // (used * 100) / SD_CARD_SIZE; + + this->tx_messages.push_back({ + 27, + static_cast(fromesp_cmds_t::FILE_FS_INFO), + (SD_CARD_SIZE >> 54) & 0xff, + (SD_CARD_SIZE >> 48) & 0xff, + (SD_CARD_SIZE >> 40) & 0xff, + (SD_CARD_SIZE >> 32) & 0xff, + (SD_CARD_SIZE >> 24) & 0xff, + (SD_CARD_SIZE >> 16) & 0xff, + (SD_CARD_SIZE >> 8) & 0xff, + (SD_CARD_SIZE) & 0xff, + static_cast((free >> 54) & 0xff), + static_cast((free >> 48) & 0xff), + static_cast((free >> 40) & 0xff), + static_cast((free >> 32) & 0xff), + static_cast((free >> 24) & 0xff), + static_cast((free >> 16) & 0xff), + static_cast((free >> 8) & 0xff), + static_cast((free) & 0xff), + free_pct, + static_cast((used >> 54) & 0xff), + static_cast((used >> 48) & 0xff), + static_cast((used >> 40) & 0xff), + static_cast((used >> 32) & 0xff), + static_cast((used >> 24) & 0xff), + static_cast((used >> 16) & 0xff), + static_cast((used >> 8) & 0xff), + static_cast((used) & 0xff), + used_pct + }); + break; + } + } + this->tx_messages.push_back({ + 1, + static_cast(fromesp_cmds_t::FILE_FS_INFO) + }); + break; + } case toesp_cmds_t::FILE_GET_INFO: { UDBG("RAINBOW BrokeStudioFirmware received message FILE_GET_INFO\n"); @@ -922,18 +1148,20 @@ void BrokeStudioFirmware::processBufferedMessage() { break; } uint8 config = this->rx_buffer.at(2); - uint8 access_mode = config & static_cast(file_config_flags_t::ACCESS_MODE); + FileConfig file_config = parseFileConfig(config); - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { if (message_size == 4) { uint8 const path = this->rx_buffer.at(3); uint8 const file = this->rx_buffer.at(4); - if (path < NUM_FILE_PATHS && file < NUM_FILES && this->file_exists[path][file]) { + std::string filename = getAutoFilename(path, file); + int i = findFile(file_config.drive, filename); + if (path < NUM_FILE_PATHS && file < NUM_FILES && i != -1) { // Compute info uint32 file_crc32; - file_crc32 = CalcCRC32(0L, this->files[path][file].data(), this->files[path][file].size()); + file_crc32 = CalcCRC32(0L, this->files.at(i).data.data(), this->files.at(i).data.size()); - uint32 file_size = this->files[path][file].size(); + uint32 file_size = this->files.at(i).data.size(); // Send info this->tx_messages.push_back({ @@ -958,7 +1186,7 @@ void BrokeStudioFirmware::processBufferedMessage() { }); } } - }else { + } else { //TODO manual mode } @@ -971,9 +1199,9 @@ void BrokeStudioFirmware::processBufferedMessage() { break; } uint8 config = this->rx_buffer.at(2); - uint8 access_mode = config & static_cast(file_config_flags_t::ACCESS_MODE); + FileConfig file_config = parseFileConfig(config); - if (access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { + if (file_config.access_mode == static_cast(file_config_flags_t::ACCESS_MODE_AUTO)) { if (message_size > 6) { // Parse uint8 const urlLength = this->rx_buffer.at(3); @@ -987,10 +1215,10 @@ void BrokeStudioFirmware::processBufferedMessage() { // Delete existing file if (path < NUM_FILE_PATHS && file < NUM_FILES) { - if (this->file_exists[path][file]) { - // File exists, let's delete it - this->files[path][file].clear(); - this->file_exists[path][file] = false; + std::string filename = getAutoFilename(path, file); + int i = findFile(file_config.drive, filename); + if (i != -1) { + this->files.erase(this->files.begin() + i); this->saveFiles(); } }else { @@ -1008,20 +1236,16 @@ void BrokeStudioFirmware::processBufferedMessage() { // Download new file this->downloadFile(url, path, file); } - }else { + } else { //TODO manual mode } break; } case toesp_cmds_t::FILE_FORMAT: UDBG("RAINBOW BrokeStudioFirmware received message FILE_FORMAT\n"); - if (message_size == 1) { - // Clear file list - for (uint8 p = 0; p < NUM_FILE_PATHS; p++) { - for (uint8 f = 0; f < NUM_FILES; f++) { - this->file_exists[p][f] = false; - } - } + if (message_size == 2) { + uint8 drive = rx_buffer.at(2); + clearFiles(drive); } break; default: @@ -1033,20 +1257,45 @@ void BrokeStudioFirmware::processBufferedMessage() { this->rx_buffer.clear(); } -void BrokeStudioFirmware::readFile(uint8 path, uint8 file, uint8 n, uint32 offset) { - assert(path < NUM_FILE_PATHS); - assert(file < NUM_FILES); +FileConfig BrokeStudioFirmware::parseFileConfig(uint8 config) { + return FileConfig({ + static_cast(config & static_cast(file_config_flags_t::ACCESS_MODE_MASK)), + static_cast((config & static_cast(file_config_flags_t::DESTINATION_MASK))) + }); +} +int BrokeStudioFirmware::findFile(uint8 drive, std::string filename) { + for (size_t i = 0; i < this->files.size(); ++i) { + if ((this->files.at(i).drive == drive) && (this->files.at(i).filename == filename)) { + return i; + } + } + return -1; +} + +int BrokeStudioFirmware::findPath(uint8 drive, std::string path) { + for (size_t i = 0; i < this->files.size(); ++i) { + if ((this->files.at(i).drive == drive) && (this->files.at(i).filename.substr(0, path.length()) == path)) { + return i; + } + } + return -1; +} + +std::string BrokeStudioFirmware::getAutoFilename(uint8 path, uint8 file) { + return "/" + dir_names[path] + "/file" + std::to_string(file) + ".bin"; +} + +void BrokeStudioFirmware::readFile(uint8 n) { // Get data range - std::vector const& f = this->files[path][file]; std::vector::const_iterator data_begin; std::vector::const_iterator data_end; - if (offset >= f.size()) { - data_begin = f.end(); + if (this->working_file.offset >= this->working_file.file->data.size()) { + data_begin = this->working_file.file->data.end(); data_end = data_begin; }else { - data_begin = f.begin() + offset; - data_end = f.begin() + std::min(static_cast::size_type>(offset) + n, f.size()); + data_begin = this->working_file.file->data.begin() + this->working_file.offset; + data_end = this->working_file.file->data.begin() + std::min(static_cast::size_type>(this->working_file.offset) + n, this->working_file.file->data.size()); } std::vector::size_type const data_size = data_end - data_begin; @@ -1061,144 +1310,151 @@ void BrokeStudioFirmware::readFile(uint8 path, uint8 file, uint8 n, uint32 offse } template -void BrokeStudioFirmware::writeFile(uint8 path, uint8 file, uint32 offset, I data_begin, I data_end) { - std::vector& f = this->files[path][file]; - auto const data_size = data_end - data_begin; - uint32 const offset_end = offset + data_size; - if (offset_end > f.size()) { - f.resize(offset_end, 0); - } - - for (std::vector::size_type i = offset; i < offset_end; ++i) { - f[i] = *data_begin; - ++data_begin; - } - this->file_exists[path][file] = true; -} - -uint8 BrokeStudioFirmware::getFreeFileId(uint8 path) const { - uint8 const NOT_FOUND = 128; - if (path >= NUM_FILE_PATHS) { - return NOT_FOUND; - } - std::array const& existing_files = this->file_exists.at(path); - for (size_t i = 0; i < existing_files.size(); ++i) { - if (!existing_files[i]) { - return i; - } - } - return NOT_FOUND; -} - -void BrokeStudioFirmware::saveFiles() const { - char const* filesystem_file_path = ::getenv("RAINBOW_FILESYSTEM_FILE"); - if (filesystem_file_path == NULL) { - FCEU_printf("RAINBOW_FILESYSTEM_FILE environment variable is not set\n"); +void BrokeStudioFirmware::writeFile(I data_begin, I data_end) { + if (this->working_file.active == false) { return; } - std::ofstream ofs(filesystem_file_path); - for (uint8 p = 0; p < NUM_FILE_PATHS; p++) - { - for (uint8 f = 0; f < NUM_FILES; f++) - { - if (this->file_exists[p][f]) - { - ofs << (char)p << (char)f; - uint32 size = this->files[p][f].size(); - ofs << (char)((size & 0xff000000) >> 24); - ofs << (char)((size & 0x00ff0000) >> 16); - ofs << (char)((size & 0x0000ff00) >> 8); - ofs << (char)((size & 0x000000ff)); - for (uint8 byte : this->files[p][f]) { - ofs << (char)byte; - } - } - } + auto const data_size = data_end - data_begin; + uint32 const offset_end = this->working_file.offset + data_size; + if (offset_end > this->working_file.file->data.size()) { + this->working_file.file->data.resize(offset_end, 0); } -/* - for(std::array const& path: this->file_exists) { - for(bool exists: path) { - ofs << exists << ' '; - } - ofs << '\n'; - } - ofs << '\n'; - for (std::array, NUM_FILES> const& path: this->files) { - for (std::vector const& file: path) { - ofs << (char)file.size(); - for (uint8 byte: file) { - ofs << (char)byte; - } - ofs << '\n'; + for (std::vector::size_type i = this->working_file.offset; i < offset_end; ++i) { + this->working_file.file->data[i] = *data_begin; + ++data_begin; + } +} + +void BrokeStudioFirmware::saveFiles() { + char const* esp_filesystem_file_path = ::getenv("RAINBOW_ESP_FILESYSTEM_FILE"); + if (esp_filesystem_file_path == NULL) { + FCEU_printf("RAINBOW_ESP_FILESYSTEM_FILE environment variable is not set\n"); + } else { + _saveFiles(0, esp_filesystem_file_path); + } + + char const* sd_filesystem_file_path = ::getenv("RAINBOW_SD_FILESYSTEM_FILE"); + if (sd_filesystem_file_path == NULL) { + FCEU_printf("RAINBOW_SD_FILESYSTEM_FILE environment variable is not set\n"); + } else { + _saveFiles(2, sd_filesystem_file_path); + } +} + +void BrokeStudioFirmware::_saveFiles(uint8 drive, char const* filename) { + std::ofstream ofs(filename, std::ios::binary); + if (ofs.fail()) { + FCEU_printf("Couldn't open RAINBOW_FILESYSTEM_FILE (%s)\n", filename); + return; + } + + ofs << (char)(0x00); //file format version + + auto file = this->files.begin(); + for (file; file != this->files.end(); ++file) + { + if (file->drive != drive) continue; + ofs << (char)file->filename.length(); //filename length + for (char& c : std::string(file->filename)) { //filename + ofs << (c); + } + uint32 size = file->data.size(); //data size + ofs << (char)((size & 0xff000000) >> 24); + ofs << (char)((size & 0x00ff0000) >> 16); + ofs << (char)((size & 0x0000ff00) >> 8); + ofs << (char)((size & 0x000000ff)); + for (uint8 byte : file->data) { //actual data + ofs << (char)byte; } } -*/ } void BrokeStudioFirmware::loadFiles() { - char const* filesystem_file_path = ::getenv("RAINBOW_FILESYSTEM_FILE"); - if (filesystem_file_path == NULL) { - FCEU_printf("RAINBOW_FILESYSTEM_FILE environment variable is not set\n"); - return; + char const* esp_filesystem_file_path = ::getenv("RAINBOW_ESP_FILESYSTEM_FILE"); + if (esp_filesystem_file_path == NULL) { + isEspFlashFilePresent = false; + FCEU_printf("RAINBOW_ESP_FILESYSTEM_FILE environment variable is not set\n"); + } + else { + isEspFlashFilePresent = true; + _loadFiles(0, esp_filesystem_file_path); } - std::ifstream ifs(filesystem_file_path); + char const* sd_filesystem_file_path = ::getenv("RAINBOW_SD_FILESYSTEM_FILE"); + if (sd_filesystem_file_path == NULL) { + isSdCardFilePresent = false; + FCEU_printf("RAINBOW_SD_FILESYSTEM_FILE environment variable is not set\n"); + } + else { + isSdCardFilePresent = true; + _loadFiles(2, sd_filesystem_file_path); + } +} + +void BrokeStudioFirmware::_loadFiles(uint8 drive, char const* filename) { + std::ifstream ifs(filename, std::ios::binary); if (ifs.fail()) { - FCEU_printf("Couldn't open RAINBOW_FILESYSTEM_FILE\n"); + FCEU_printf("Couldn't open RAINBOW_FILESYSTEM_FILE (%s)\n", filename); return; } + + // Stop eating new lines in binary mode!!! + ifs.unsetf(std::ios::skipws); - while (!ifs.peek()) - { - uint8 p; - uint8 f; - uint8 t; - uint32 size = 0; - ifs >> p; - ifs >> f; - ifs >> t; - size |= (t << 24); - ifs >> t; - size |= (t << 16); - ifs >> t; - size |= (t << 8); - ifs >> t; - size |= t; - this->file_exists[p][f] = true; - this->files[p][f].clear(); - this->files[p][f].reserve(size); - for (uint32 i = 0; i < size; i++) - { - ifs >> t; - this->files[p][f].push_back(t); - } + clearFiles(drive); - } -/* - for(std::array& path: this->file_exists) { - for(bool& exists: path) { - ifs >> exists; - } - } + char c; + uint8 l; + uint8 t; + uint32 size; + uint8 v; - for (std::array, NUM_FILES>& path: this->files) { - for (std::vector& file: path) { - size_t file_size; - ifs >> file_size; + v = ifs.get(); //file format version - file.clear(); - file.reserve(file_size); - for (size_t i = 0; i < file_size; ++i) { - uint16_t byte; - ifs >> byte; - if (byte > 255) throw std::runtime_error("invalid filesystem file"); - file.push_back(byte); + if (v == 0) { + while (ifs.peek() != EOF) { + FileStruct temp_file;// = { 0, 0, 0, "", std::vector() }; + temp_file.drive = drive; //drive + l = ifs.get(); //filename length + temp_file.filename.reserve(l); + for (size_t i = 0; i < l; ++i) { //filename + c = ifs.get(); + temp_file.filename.push_back(c); } + size = 0; //data size + t = ifs.get(); + size |= (t << 24); + t = ifs.get(); + size |= (t << 16); + t = ifs.get(); + size |= (t << 8); + t = ifs.get(); + size |= t; + temp_file.data.clear(); + temp_file.data.reserve(size); + for (uint32 i = 0; i < size; ++i) { //actual data + t = ifs.get(); + temp_file.data.push_back(t); + } + this->files.push_back(temp_file); + } + } else { + FCEU_printf("RAINBOW_FILESYSTEM_FILE (%s) format version unknown\n", filename); + } +} + +void BrokeStudioFirmware::clearFiles(uint8 drive) { + unsigned int i = 0; + while (i < this->files.size()) { + if (this->files.at(i).drive == drive) { + this->files.erase(this->files.begin() + i); + } + else { + ++i; } } -*/ } template @@ -1569,15 +1825,19 @@ void BrokeStudioFirmware::httpdEvent(mg_connection *nc, int ev, void *ev_data) { UDBG("http request event \n"); struct http_message *hm = (struct http_message *) ev_data; UDBG(" uri: %.*s\n", hm->uri.len, hm->uri.p); - if (std::string("/api/config") == std::string(hm->uri.p, hm->uri.len)) { + if (std::string("/api/esp/status") == std::string(hm->uri.p, hm->uri.len)) { + if (mg_vcasecmp(&hm->method, "GET") == 0) { + mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); + mg_printf(nc, "{\"sd\":{\"isPresent\":%s}}\n", self->isSdCardFilePresent ? "true" : "false"); + nc->flags |= MG_F_SEND_AND_CLOSE; + } + } + else if (std::string("/api/config") == std::string(hm->uri.p, hm->uri.len)) { if (mg_vcasecmp(&hm->method, "GET") == 0) { mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); mg_printf(nc, "{\"server\":{\"host\":\"%s\", \"port\":\"%u\"}}\n", self->server_settings_address.c_str(), self->server_settings_port); nc->flags |= MG_F_SEND_AND_CLOSE; - } - } - else if (std::string("/api/config/update") == std::string(hm->uri.p, hm->uri.len)) { - if (mg_vcasecmp(&hm->method, "POST") == 0) { + } else if (mg_vcasecmp(&hm->method, "POST") == 0) { char var_name[100], file_name[100]; const char *chunk; size_t chunk_len, n1, n2; @@ -1591,14 +1851,19 @@ void BrokeStudioFirmware::httpdEvent(mg_connection *nc, int ev, void *ev_data) { } n1 += n2; } - send_message(200, "{\"success\":\"true\"}\n", "application/json"); - } - else { + mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); + mg_printf(nc, "{\"success\":\"true\", \"config\":{\"server\":{\"host\":\"%s\", \"port\":\"%u\"}}}\n", self->server_settings_address.c_str(), self->server_settings_port); + nc->flags |= MG_F_SEND_AND_CLOSE; + } else { send_generic_error(); } } - else if (std::string("/api/esp/debugconfig") == std::string(hm->uri.p, hm->uri.len)) { - if (mg_vcasecmp(&hm->method, "POST") == 0) { + else if (std::string("/api/esp/advancedconfig") == std::string(hm->uri.p, hm->uri.len)) { + if (mg_vcasecmp(&hm->method, "GET") == 0) { + mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); + mg_printf(nc, "{\"debugConfig\":\"%u\"}", self->debug_config); + nc->flags |= MG_F_SEND_AND_CLOSE; + } else if (mg_vcasecmp(&hm->method, "POST") == 0) { char var_name[100], file_name[100]; const char *chunk; size_t chunk_len, n1, n2; @@ -1612,245 +1877,387 @@ void BrokeStudioFirmware::httpdEvent(mg_connection *nc, int ev, void *ev_data) { n1 += n2; } }else { - mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); - mg_printf(nc, "{\"debugConfig\":\"%u\"}", self->debug_config); - nc->flags |= MG_F_SEND_AND_CLOSE; + send_generic_error(); } } else if (std::string("/api/file/list") == std::string(hm->uri.p, hm->uri.len)) { - char path[256]; - int const path_len = mg_get_http_var(&hm->query_string, "path", path, 256); - if (path_len < 0) { - send_generic_error(); - return; - } - mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); - mg_printf(nc, "["); - if (path_len == 0) { - // Send three paths - for (uint8_t path_index = 0; path_index < NUM_FILE_PATHS; ++path_index) { - if (path_index != 0) - { - mg_printf(nc, ","); - } - uint32_t path_size = 0L; - for (uint8_t file_index = 0; file_index < NUM_FILES; ++file_index) { - if (self->file_exists[path_index][file_index]) - path_size += self->files[path_index][file_index].size(); - } - mg_printf(nc, "{\"id\":\"%d\",\"type\":\"dir\",\"name\":\"%s\",\"size\":\"%d\"}", path_index, dir_names[path_index].c_str(), path_size); + if (mg_vcasecmp(&hm->method, "GET") == 0) { + char _drive[256]; + int const drive_len = mg_get_http_var(&hm->query_string, "drive", _drive, 256); + if (drive_len < 0) { + send_generic_error(); + return; } - } - else { - // Send path content - int path_index = path[0] - '0'; - mg_printf(nc, "{\"id\":\"\",\"type\":\"dir\",\"name\":\"..\",\"size\":\"-1\"}"); - for (uint8_t file_index = 0; file_index < self->file_exists[path_index].size(); ++file_index) { - if (self->file_exists[path_index][file_index]) { - mg_printf(nc, ","); - mg_printf(nc, "{\"id\":\"%d\",\"type\":\"file\",\"name\":\"file%d.bin\",\"size\":\"%d\"}", file_index, file_index, static_cast(self->files[path_index][file_index].size())); + char _path[256]; + int const path_len = mg_get_http_var(&hm->query_string, "path", _path, 256); + if (path_len < 0) { + send_generic_error(); + return; + } + + mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); + mg_printf(nc, "["); + + int slash_pos; + int id = 0; + int drive = std::atoi(_drive); + + std::vector path_list; + + std::string label = ""; // Dir: b | File: esp8266.txt + std::string path = "/"; // Dir: /a | File: /a/b + std::string filename = ""; // Dir: b | File: esp8266.txt + std::string fullname = ""; // Dir: /a/b | File: /a/b/esp8266.txt + uint32 size = 0L; + + std::string full_path = ""; + std::string request_path = std::string(_path); + + // Need to go up? + if (request_path != "/") + { + request_path = request_path + "/"; + std::string parent_path = "/"; + slash_pos = request_path.find_last_of("/", request_path.size() - 2); + if (slash_pos != 0) + { + parent_path = request_path.substr(0, slash_pos); + } + mg_printf( + nc, + "{\"id\":\"%d\",\"type\":\"dir\",\"label\":\"..\",\"path\":\"%s\",\"filename\":\"..\",\"fullname\":\"%s\",\"size\":-1}", + id, parent_path.c_str(), parent_path.c_str() + ); + id++; + } + + // Loop through files + for (size_t i = 0; i < self->files.size(); ++i) { + if (self->files.at(i).drive == drive) { + + fullname = self->files.at(i).filename; + + // In requested path? + std::string tmp = fullname.substr(0, request_path.size()); + if (tmp != request_path) + { + continue; + } + + // File or Dir? + slash_pos = fullname.find("/", request_path.size() + 1); + if (slash_pos == -1) + { + // File + + // Split file path and file name + slash_pos = fullname.find_last_of("/"); + path = fullname.substr(0, slash_pos + 1); + filename = fullname.substr(slash_pos + 1); + label = filename; + + if (id != 0) { + mg_printf(nc, ","); + } + + mg_printf( + nc, + "{\"id\":%d,\"type\":\"file\",\"label\":\"%s\",\"path\":\"%s\",\"filename\":\"%s\",\"fullname\":\"%s\",\"size\":%d}", + id, label.c_str(), path.c_str(), filename.c_str(), fullname.c_str(), self->files.at(i).data.size() + ); + id++; + } + else + { + // Dir + + slash_pos = fullname.find_first_of("/", request_path.size()); + path = fullname.substr(0, slash_pos); + bool found = false; + for (auto &i : path_list) { + if (i == path) { + found = true; + break; + } + } + if (!found) + { + path_list.push_back(path); + + slash_pos = path.find_last_of("/"); + filename = path.substr(slash_pos + 1); + label = filename; + + full_path = path; + + slash_pos = path.find_last_of("/"); + path = path.substr(0, slash_pos + 1); + if (path == "") path = "/"; + + if (id != 0) { + mg_printf(nc, ","); + } + + mg_printf( + nc, + "{\"id\":%d,\"type\":\"dir\",\"label\":\"%s\",\"path\":\"%s\",\"filename\":\"%s\",\"fullname\":\"%s\",\"size\":-1}", + id, label.c_str(), path.c_str(), filename.c_str(), full_path.c_str() + ); + id++; + } } } + } + mg_printf(nc, "]"); + nc->flags |= MG_F_SEND_AND_CLOSE; + } else { + send_generic_error(); } - mg_printf(nc, "]"); - nc->flags |= MG_F_SEND_AND_CLOSE; } else if (std::string("/api/file/free") == std::string(hm->uri.p, hm->uri.len)) { - char path[256]; - int const path_len = mg_get_http_var(&hm->query_string, "path", path, 256); - if (path_len <= 0) { - send_generic_error(); - return; - } - mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); - mg_printf(nc, "["); - int path_index = std::atoi(path); - bool found = false; - for (uint8_t file_index = 0; file_index < NUM_FILES; ++file_index) { - if (!self->file_exists[path_index][file_index]) { - if (found) { - mg_printf(nc, ","); - } - mg_printf(nc, "{\"id\":\"%d\",\"name\":\"%d\"}", file_index, file_index); - found = true; + if (mg_vcasecmp(&hm->method, "GET") == 0) { + char drive[256]; + int const drive_len = mg_get_http_var(&hm->query_string, "drive", drive, 256); + if (drive_len < 0) { + send_generic_error(); + return; } + char path[256]; + int const path_len = mg_get_http_var(&hm->query_string, "path", path, 256); + if (path_len <= 0) { + send_generic_error(); + return; + } + mg_send_response_line(nc, 200, "Content-Type: application/json\r\nConnection: close\r\n"); + mg_printf(nc, "["); + int drive_index = std::atoi(drive); + int path_index = std::atoi(path); + bool found = false; + for (uint8_t file_index = 0; file_index < NUM_FILES; ++file_index) { + std::string filename = self->getAutoFilename(path_index, file_index); + int i = self->findFile(drive_index, filename); + if (i == -1) { + if (found) { + mg_printf(nc, ","); + } + mg_printf(nc, "{\"id\":\"%d\",\"name\":\"%d\"}", file_index, file_index); + found = true; + } + } + mg_printf(nc, "]"); + nc->flags |= MG_F_SEND_AND_CLOSE; + } else { + send_generic_error(); } - mg_printf(nc, "]"); - nc->flags |= MG_F_SEND_AND_CLOSE; }else if (std::string("/api/file/delete") == std::string(hm->uri.p, hm->uri.len)) { - char path[256]; - char file[256]; - int const path_len = mg_get_http_var(&hm->query_string, "path", path, 256); - int const file_len = mg_get_http_var(&hm->query_string, "file", file, 256); + if (mg_vcasecmp(&hm->method, "POST") == 0) { + char _drive[256]; + int const drive_len = mg_get_http_var(&hm->query_string, "drive", _drive, 256); + if (drive_len < 0) { + send_generic_error(); + return; + } + char _filename[256]; + int const filename_len = mg_get_http_var(&hm->query_string, "filename", _filename, 256); + if (filename_len < 0) { + send_generic_error(); + return; + } + std::string filename = std::string(_filename); + int drive = atoi(_drive); + int i = self->findFile(drive, filename); - if (path_len <= 0 || file_len <= 0) { + UDBG("RAINBOW Web(self=%p) deleting file %s\n", self, filename); + self->files.erase(self->files.begin() + i); + self->saveFiles(); + send_message(200, "{\"success\":\"true\"}\n", "application/json"); + } else { send_generic_error(); - return; } - uint8 path_index = std::atoi(path); - uint8 file_index = std::atoi(file); - - if (path_index >= NUM_FILE_PATHS || file_index >= NUM_FILES || !self->file_exists[path_index][file_index]) { - send_generic_error(); - return; - } - - UDBG("RAINBOW Web(self=%p) deleting file %d/%d\n", self, path_index, file_index); - self->file_exists[path_index][file_index] = false; - self->files[path_index][file_index].clear(); - self->saveFiles(); - send_message(200, "{\"success\":\"true\"}\n", "application/json"); - }else if (std::string("/api/file/rename") == std::string(hm->uri.p, hm->uri.len)) { - char path[256]; - char file[256]; - char new_path[256]; - char new_file[256]; - int const path_len = mg_get_http_var(&hm->query_string, "path", path, 256); - int const file_len = mg_get_http_var(&hm->query_string, "file", file, 256); - int const new_path_len = mg_get_http_var(&hm->query_string, "newPath", new_path, 256); - int const new_file_len = mg_get_http_var(&hm->query_string, "newFile", new_file, 256); + if (mg_vcasecmp(&hm->method, "POST") == 0) { + char _drive[256]; + int const drive_len = mg_get_http_var(&hm->query_string, "drive", _drive, 256); + if (drive_len < 0) { + send_generic_error(); + return; + } + char _new_drive[256]; + int const new_drive_len = mg_get_http_var(&hm->query_string, "newDrive", _new_drive, 256); + if (new_drive_len < 0) { + send_generic_error(); + return; + } + char _filename[256]; + int const filename_len = mg_get_http_var(&hm->query_string, "filename", _filename, 256); + if (filename_len < 0) { + send_generic_error(); + return; + } + char _new_filename[256]; + int const new_filename_len = mg_get_http_var(&hm->query_string, "newFilename", _new_filename, 256); + if (new_filename_len < 0) { + send_generic_error(); + return; + } + std::string filename = std::string(_filename); + std::string new_filename = std::string(_new_filename); + int drive = atoi(_drive); + int new_drive = atoi(_new_drive); - if (path_len <= 0 || file_len <= 0 || new_path_len <= 0 || new_file_len <= 0) { + int i = self->findFile(new_drive, new_filename); + if (i != -1) + { + send_message(200, "{\"success\":false,\"message\":\"Destination file already exists.\"}\n", "application/json"); + return; + } + + i = self->findFile(drive, filename); + if (i == -1) + { + send_message(200, "{\"success\":false,\"message\":\"Source file does not exist.\"}\n", "application/json"); + return; + } + + self->files.at(i).filename = new_filename; + self->files.at(i).drive = new_drive; + self->saveFiles(); + + send_message(200, "{\"success\":\"true\"}\n", "application/json"); + } else { send_generic_error(); - return; } - - uint8 path_index = std::atoi(path); - uint8 file_index = std::atoi(file); - uint8 new_path_index = std::atoi(new_path); - uint8 new_file_index = std::atoi(new_file); - UDBG("%d %d %d %d\n", path_index, file_index, new_path_index, new_file_index); - - if (path_index >= NUM_FILE_PATHS || file_index >= NUM_FILES || new_path_index >= NUM_FILE_PATHS || new_file_index >= NUM_FILES|| !self->file_exists[path_index][file_index]) { - send_generic_error(); - return; - } - - self->files[new_path_index][new_file_index] = self->files[path_index][file_index]; - self->file_exists[new_path_index][new_file_index] = self->file_exists[path_index][file_index]; - self->file_exists[path_index][file_index] = false; - self->files[path_index][file_index].clear(); - self->saveFiles(); - - send_message(200, "{\"success\":\"true\"}\n", "application/json"); }else if (std::string("/api/file/download") == std::string(hm->uri.p, hm->uri.len)) { - char path[256]; - char file[256]; - int const path_len = mg_get_http_var(&hm->query_string, "path", path, 256); - int const file_len = mg_get_http_var(&hm->query_string, "file", file, 256); - - if (path_len <= 0 ||file_len <= 0) { - send_generic_error(); - return; - } - - uint8 path_index = std::atoi(path); - uint8 file_index = std::atoi(file); - - if (path_index >= NUM_FILE_PATHS || file_index >= NUM_FILES || !self->file_exists[path_index][file_index]) { - send_generic_error(); - return; - } - mg_send_response_line( - nc, 200, - "Content-Type: application/octet-stream\r\n" - "Connection: close\r\n" - ); - mg_send(nc, self->files[path_index][file_index].data(), self->files[path_index][file_index].size()); - nc->flags |= MG_F_SEND_AND_CLOSE; - }else if (std::string("/api/file/upload") == std::string(hm->uri.p, hm->uri.len)) { - // Get boundary for multipart form in HTTP headers - std::string multipart_boundary; - { - mg_str const * content_type = mg_get_http_header(hm, "Content-Type"); - if (content_type == NULL) { + if (mg_vcasecmp(&hm->method, "GET") == 0) { + char _drive[256]; + int const drive_len = mg_get_http_var(&hm->query_string, "drive", _drive, 256); + if (drive_len < 0) { send_generic_error(); return; } - static std::regex const content_type_regex("multipart/form-data; boundary=(.*)"); - std::smatch match; - std::string content_type_str(content_type->p, content_type->len); - if (!std::regex_match(content_type_str, match, content_type_regex)) { + char _filename[256]; + int const filename_len = mg_get_http_var(&hm->query_string, "filename", _filename, 256); + if (filename_len < 0) { send_generic_error(); return; } - assert(match.size() == 2); - multipart_boundary = match[1]; - } + std::string filename = std::string(_filename); + int drive = atoi(_drive); + int i = self->findFile(drive, filename); - // Parse form parts - std::map params; - { - std::string body_str(hm->body.p, hm->body.len); - std::string::size_type pos = 0; - while (pos != std::string::npos) { - // Find the parameter name - std::string::size_type found_pos = body_str.find("form-data; name=\"", pos); - if (found_pos == std::string::npos) { - break; - } - pos = found_pos + 17; - found_pos = body_str.find('"', pos); - if (found_pos == std::string::npos) { - break; - } - std::string const param_name = body_str.substr(pos, found_pos - pos); - pos = found_pos; - - // Find the begining of the body - found_pos = body_str.find("\r\n\r\n", pos); - if (found_pos == std::string::npos) { - break; - } - pos = found_pos + 4; - - // Find the begining of the next delimiter - found_pos = body_str.find("\r\n--" + multipart_boundary, pos); - if (found_pos == std::string::npos) { - break; - } - std::string const param_value = body_str.substr(pos, found_pos - pos); - pos = found_pos; - - // Store parsed parameter - params[param_name] = param_value; - } - } - - // Process request - std::map::const_iterator file_data = params.find("file_data"); - std::map::const_iterator path = params.find("path"); - std::map::const_iterator file = params.find("file"); - - if (file_data == params.end() || path == params.end() || file == params.end()) { + mg_send_response_line( + nc, 200, + "Content-Type: application/octet-stream\r\n" + "Connection: close\r\n" + ); + mg_send(nc, self->files.at(i).data.data(), self->files.at(i).data.size()); + nc->flags |= MG_F_SEND_AND_CLOSE; + } else { send_generic_error(); - return; } + }else if (std::string("/api/upload") == std::string(hm->uri.p, hm->uri.len)) { + if (mg_vcasecmp(&hm->method, "POST") == 0) { + char _drive[256]; + int const drive_len = mg_get_http_var(&hm->query_string, "drive", _drive, 256); + if (drive_len < 0) { + send_generic_error(); + return; + } + uint8 drive = atoi(_drive); - uint8 path_index = std::atoi(path->second.c_str()); - uint8 file_index = std::atoi(file->second.c_str()); + // Get boundary for multipart form in HTTP headers + std::string multipart_boundary; + { + mg_str const * content_type = mg_get_http_header(hm, "Content-Type"); + if (content_type == NULL) { + send_generic_error(); + return; + } + static std::regex const content_type_regex("multipart/form-data; boundary=(.*)"); + std::smatch match; + std::string content_type_str(content_type->p, content_type->len); + if (!std::regex_match(content_type_str, match, content_type_regex)) { + send_generic_error(); + return; + } + assert(match.size() == 2); + multipart_boundary = match[1]; + } - self->files[path_index][file_index] = std::vector(file_data->second.begin(), file_data->second.end()); - self->file_exists[path_index][file_index] = true; - self->saveFiles(); + // Parse form parts + std::map params; + { + std::string body_str(hm->body.p, hm->body.len); + std::string::size_type pos = 0; + while (pos != std::string::npos) { + // Find the parameter name + std::string::size_type found_pos = body_str.find("form-data; name=\"", pos); + if (found_pos == std::string::npos) { + break; + } + pos = found_pos + 17; + found_pos = body_str.find('"', pos); + if (found_pos == std::string::npos) { + break; + } + std::string const param_name = body_str.substr(pos, found_pos - pos); + pos = found_pos; - UDBG("RAINBOW Web(self=%p) sucessfuly uploaded file %d/%d\n", self, path_index, file_index); + // Find the begining of the body + found_pos = body_str.find("\r\n\r\n", pos); + if (found_pos == std::string::npos) { + break; + } + pos = found_pos + 4; - // Return something webbrowser friendly - send_message(200, "{\"success\":\"true\"}\n", "application/json"); + // Find the begining of the next delimiter + found_pos = body_str.find("\r\n--" + multipart_boundary, pos); + if (found_pos == std::string::npos) { + break; + } + std::string const param_value = body_str.substr(pos, found_pos - pos); + pos = found_pos; + + // Store parsed parameter + params[param_name] = param_value; + } + } + + // Process request + std::map::const_iterator filename = params.find("filename"); + std::map::const_iterator file_data = params.find("file"); + + if (file_data == params.end() || filename == params.end()) { + send_generic_error(); + return; + } + + self->files.push_back(FileStruct({ drive, filename->second , std::vector(file_data->second.begin(), file_data->second.end()) })); + self->saveFiles(); + + UDBG("RAINBOW Web(self=%p) sucessfuly uploaded file %s\n", self, filename->second); + + // Return something webbrowser friendly + send_message(200, "{\"success\":\"true\"}\n", "application/json"); + } else { + send_generic_error(); + } }else if (std::string("/api/file/format") == std::string(hm->uri.p, hm->uri.len)) { if (mg_vcasecmp(&hm->method, "POST") == 0) { - // Clear file list - for (uint8 p = 0; p < NUM_FILE_PATHS; p++) - { - for (uint8 f = 0; f < NUM_FILES; f++) - { - self->file_exists[p][f] = false; - } + char _drive[256]; + int const drive_len = mg_get_http_var(&hm->query_string, "drive", _drive, 256); + if (drive_len < 0) { + send_generic_error(); + return; } - UDBG("RAINBOW Web(self=%p) sucessfuly formatted file system %d/%d\n", self); + uint8 drive = atoi(_drive); + int i = 0; + self->clearFiles(drive); + std::string str_drive; + if (drive == 0) str_drive = "ESP Flash"; + else if (drive == 1) str_drive = "SD Card"; + UDBG("RAINBOW Web(self=%p) sucessfuly formatted file system %s\n", self, str_drive); // Return something webbrowser friendly send_message(200, "{\"success\":\"true\"}\n", "application/json"); @@ -1861,44 +2268,129 @@ void BrokeStudioFirmware::httpdEvent(mg_connection *nc, int ev, void *ev_data) { }else { char const* www_root = ::getenv("RAINBOW_WWW_ROOT"); if (www_root == NULL) { - std::string upload_form = R"-()-"; - upload_form += R"-(

Upload file to Rainbow:

)-"; - upload_form += R"-(
)-"; - upload_form += R"-(Path:
)-"; - upload_form += R"-(File:
"; - upload_form += R"-()-"; - upload_form += ""; - upload_form += ""; + std::string upload_form = R"""( + + + + + + Rainbow + FCEUX + + + +
+

Rainbow + FCEUX

+
+

About

+

+ The Rainbow mapper offers the possibility to store files on the ESP + embedded flash memory and/or the SD Card if present. +

+

+ This behaviour can be replicated with FCEUX by setting up some + environment variables and the Rainbow Webapp. +

+

Also, a webapp is provided to help you browse those files.

+
+
+

Web server

+

+ If you can read this, it means that the web server is already running + in FCEUX. +

+

Here's how you can change the port used for the web server:

+
    +
  1. + Create a environment variable called RAINBOW_WWW_PORT +
  2. +
  3. Set its value to the port you want to use
  4. +
  5. You may need to restart your computer and/or FCEUX
  6. +
+
+
+

File system

+

+ If you want to set up default value for your game server, you can + create two environment variables as follows. +

+
    +
  • + RAINBOW_ESP_FILESYSTEM_FILE defines the file used to save + ESP Flash content +
  • +
  • + RAINBOW_SD_FILESYSTEM_FILE defines the file used to save + SD card content +
  • +
+
+
+

Webapp

+
    +
  1. + Download the Webapp zipfile + here +
  2. +
  3. Unzip the file where you want
  4. +
  5. + Create a environment variable called RAINBOW_WWW_ROOT +
  6. +
  7. + Set its value to the absolute path to the folder containing the + files you unzipped +
  8. +
  9. You may need to restart your computer and/or FCEUX
  10. +
+
+
+

Game server

+

+ If you want to set up default values for your game server, you can + create two environment variables as follows. +

+
    +
  • + RAINBOW_SERVER_ADDR defines the server host/IP address +
  • +
  • RAINBOW_SERVER_PORT defines the server port
  • +
+
+ + © Broke Studio • Page + built with Pico + +
+ + +)"""; send_message(200, upload_form.c_str(), "text/html"); }else { // Translate url path to a file path on disk @@ -2041,8 +2533,8 @@ void BrokeStudioFirmware::downloadFile(std::string const& url, uint8 path, uint8 }else { UDBG("RAINBOW BrokeStudioFirmware download success\n"); // Store data - this->files[path][file] = data; - this->file_exists[path][file] = true; + std::string filename = this->getAutoFilename(path, file); + this->files.push_back(FileStruct({ 0, filename, data})); this->saveFiles(); // Write result message diff --git a/src/boards/rainbow_esp.h b/src/boards/rainbow_esp.h index 649f932f..a7fc842d 100644 --- a/src/boards/rainbow_esp.h +++ b/src/boards/rainbow_esp.h @@ -5,6 +5,7 @@ #include "RNBW/easywsclient.hpp" #include "RNBW/mongoose.h" +#include "RNBW/bootrom_chr.h" #define CURL_STATICLIB #include "curl/curl.h" @@ -22,6 +23,10 @@ static uint8 const NO_WORKING_FILE = 0xff; static uint8 const NUM_FILE_PATHS = 3; static uint8 const NUM_FILES = 64; + +static uint64 const ESP_FLASH_SIZE = 0x200000; // 2MiB - 0x200000 +static uint64 const SD_CARD_SIZE = 0x80000000; // 2GiB - 0x80000000 + static uint8 const NUM_NETWORKS = 3; static uint8 const NUM_FAKE_NETWORKS = 5; static uint8 const SSID_MAX_LENGTH = 32; @@ -39,6 +44,29 @@ struct NetworkInfo bool active; }; +struct FileConfig +{ + uint8 access_mode; + uint8 drive; +}; + +struct FileStruct +{ + uint8 drive; + std::string filename; + std::vector data; +}; + +struct WorkingFile +{ + bool active; + uint8 config; + uint8 auto_path; + uint8 auto_file; + uint32 offset; + FileStruct *file; +}; + class BrokeStudioFirmware: public EspFirmware { public: BrokeStudioFirmware(); @@ -60,6 +88,7 @@ private: BUFFER_CLEAR_RX_TX, BUFFER_DROP_FROM_ESP, ESP_GET_FIRMWARE_VERSION, + ESP_FACTORY_SETTINGS, ESP_RESTART, // WIFI CMDS @@ -84,9 +113,10 @@ private: SERVER_PING, SERVER_SET_PROTOCOL, SERVER_GET_SETTINGS, - SERVER_GET_CONFIG_SETTINGS, SERVER_SET_SETTINGS, - SERVER_RESTORE_SETTINGS, + SERVER_GET_SAVED_SETTINGS, + SERVER_SET_SAVED_SETTINGS, + SERVER_RESTORE_SAVED_SETTINGS, SERVER_CONNECT, SERVER_DISCONNECT, SERVER_SEND_MSG, @@ -113,6 +143,7 @@ private: FILE_COUNT, FILE_GET_LIST, FILE_GET_FREE_ID, + FILE_GET_FS_INFO, FILE_GET_INFO, FILE_DOWNLOAD, FILE_FORMAT, @@ -124,6 +155,7 @@ private: READY, DEBUG_LEVEL, ESP_FIRMWARE_VERSION, + ESP_FACTORY_RESET, // WIFI / AP CMDS WIFI_STATUS, @@ -155,10 +187,19 @@ private: FILE_DATA, FILE_COUNT, FILE_ID, + FILE_FS_INFO, FILE_INFO, FILE_DOWNLOAD, }; + // ESP factory reset result codes + enum class esp_factory_reset : uint8 { + SUCCESS = 0, + ERROR_WHILE_RESETTING_CONFIG = 1, + ERROR_WHILE_DELETING_TWEB = 2, + ERROR_WHILE_DELETING_WEB = 3 + }; + enum class server_protocol_t : uint8 { WEBSOCKET, WEBSOCKET_SECURED, @@ -176,9 +217,12 @@ private: // FILE_CONFIG enum class file_config_flags_t : uint8 { - ACCESS_MODE = 1, + ACCESS_MODE_MASK = 1, ACCESS_MODE_AUTO = 0, - ACCESS_MODE_MANUAL = 1 + ACCESS_MODE_MANUAL = 1, + DESTINATION_MASK = 2, + DESTINATION_ESP = 0, + DESTINATION_SD = 2, }; enum class file_delete_results_t : uint8 { @@ -212,12 +256,18 @@ private: }; void processBufferedMessage(); - void readFile(uint8 path, uint8 file, uint8 n, uint32 offset); + FileConfig BrokeStudioFirmware::parseFileConfig(uint8 config); + int findFile(uint8 drive, std::string filename); + int findPath(uint8 drive, std::string path); + std::string getAutoFilename(uint8 path, uint8 file); + void readFile(uint8 n); template - void writeFile(uint8 path, uint8 file, uint32 offset, I data_begin, I data_end); - uint8 getFreeFileId(uint8 path) const; - void saveFiles() const; + void writeFile(I data_begin, I data_end); + void saveFiles(); + void _saveFiles(uint8 drive, char const* filename); void loadFiles(); + void _loadFiles(uint8 drive, char const* filename); + void clearFiles(uint8 drive); template void sendMessageToServer(I begin, I end); @@ -248,12 +298,10 @@ private: std::deque tx_buffer; std::deque> tx_messages; - std::array, NUM_FILES>, NUM_FILE_PATHS> files; - std::array, NUM_FILE_PATHS> file_exists; - uint32 file_offset = 0; - uint8 working_file_config = 0; - uint8 working_path = 0; - uint8 working_file = NO_WORKING_FILE; + bool isEspFlashFilePresent = false; + bool isSdCardFilePresent = false; + WorkingFile working_file; + std::vector files; std::array networks; @@ -264,7 +312,7 @@ private: uint16_t server_settings_port = 0; uint8 debug_config = 0; - uint8 wifi_config = 3; + uint8 wifi_config = 1; easywsclient::WebSocket::pointer socket = nullptr; std::thread socket_close_thread; diff --git a/src/cart.h b/src/cart.h index ecc036d4..e0872838 100644 --- a/src/cart.h +++ b/src/cart.h @@ -52,6 +52,7 @@ struct CartInfo uint32 CRC32; // Should be set by the iNES/UNIF loading // code, used by mapper/board code, maybe // other code in the future. + int misc_roms; CartInfo(void) { @@ -77,6 +78,7 @@ struct CartInfo battery_vram_size = 0; memset( MD5, 0, sizeof(MD5)); CRC32 = 0; + misc_roms = 0; }; }; diff --git a/src/ines.cpp b/src/ines.cpp index 71249fd5..f8adb1e0 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -50,6 +50,7 @@ uint8 *trainerpoo = NULL; uint8 *ROM = NULL; uint8 *VROM = NULL; uint8 *ExtraNTARAM = NULL; +uint8 *MiscROMS = NULL; iNES_HEADER head; static CartInfo iNESCart; @@ -58,6 +59,7 @@ uint8 Mirroring = 0; uint8 MirroringAs2bits = 0; uint32 ROM_size = 0; uint32 VROM_size = 0; +uint32 MiscROMS_size = 0; char LoadedRomFName[4096]; //mbg merge 7/17/06 added char LoadedRomFNamePatchToUse[4096]; @@ -117,6 +119,10 @@ void iNESGI(GI h) { //bbit edited: removed static keyword FCEU_free(VROM); VROM = NULL; } + if (MiscROMS) { + FCEU_free(MiscROMS); + MiscROMS = NULL; + } if (trainerpoo) { free(trainerpoo); trainerpoo = NULL; @@ -798,8 +804,8 @@ BMAPPINGLocal bmap[] = { {"KONAMI QTAi Board", 547, QTAi_Init }, + {"RAINBOW2", 682, RAINBOW2_Init }, {"RAINBOW13", 3872, RAINBOW13_Init }, - {"RAINBOW2", 3873, RAINBOW2_Init }, {"", 0, NULL} }; @@ -826,6 +832,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { iNESCart.vram_size = (head.VRAM_size & 0x0F)?(64 << (head.VRAM_size & 0x0F)):0; iNESCart.battery_vram_size = (head.VRAM_size & 0xF0)?(64 << ((head.VRAM_size & 0xF0)>>4)):0; iNESCart.submapper = head.ROM_type3 >> 4; + iNESCart.misc_roms = head.misc_roms & 0x03; } MapperNo = (head.ROM_type >> 4); @@ -870,6 +877,10 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { VROM_size = ((1 << (head.VROM_size >> 2)) * ((head.VROM_size & 0b11) * 2 + 1)) >> 13; } + if (iNES2 && iNESCart.misc_roms != 0) { + MiscROMS_size = fp->size - (ROM_size * 0x4000 + VROM_size * 0x2000 + 0x10); + } + int round = true; for (int i = 0; i != sizeof(not_power2) / sizeof(not_power2[0]); ++i) { //for games not to the power of 2, so we just read enough @@ -956,6 +967,13 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { if (VROM_size) FCEU_fread(VROM, 0x2000, VROM_size, fp); + if (iNES2 && iNESCart.misc_roms != 0 && MiscROMS_size) + { + MiscROMS = (uint8*)FCEU_malloc(MiscROMS_size); + memset(MiscROMS, 0xFF, MiscROMS_size); + FCEU_fread(MiscROMS, MiscROMS_size, 1, fp); + } + md5_starts(&md5); md5_update(&md5, ROM, ROM_size << 14); diff --git a/src/ines.h b/src/ines.h index 6c95863a..a521b23b 100644 --- a/src/ines.h +++ b/src/ines.h @@ -42,8 +42,10 @@ public: //mbg merge 6/29/06 extern uint8 *ROM; extern uint8 *VROM; +extern uint8 *MiscROMS; extern uint32 VROM_size; extern uint32 ROM_size; +extern uint32 MiscROMS_size; extern uint8 *ExtraNTARAM; extern uint8 **VPageR; extern int iNesSave(void); //bbit Edited: line added