// https://docs.arduino.cc/built-in-examples/display/RowColumnScanning
// https://osoyoo.com/2017/07/15/8x8-led-matrix/#2.1
// https://github.com/dhepper/font8x8

// https://github.com/rene-d/fontino/blob/master/font8x8_ib8x8u.ino
//
// FACE_NAME "IBM BIOS 8x8"
//
// 0-31,127 : Code page 437, cf. https://en.wikipedia.org/wiki/Code_page_437
// 32-126   : ASCII
// 160-255  : ISO-8859-1, cf. https://en.wikipedia.org/wiki/ISO/IEC_8859-1

// const uint8_t font8x8_ib8x8u[224][8] PROGMEM = {
const uint8_t font8x8_ib8x8u[224][8] = {
    // ---------------------------  0-127 ---------------------------
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},  // 0000 (uni0000.dup1)
    {0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e},  // 0001 (uni0001)
    {0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e},  // 0002 (uni0002)
    {0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00},  // 0003 (uni0003)
    {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00},  // 0004 (uni0004)
    {0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c},  // 0005 (uni0005)
    {0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c},  // 0006 (uni0006)
    {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00},  // 0007 (uni0007)
    {0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff},  // 0008 (uni0008)
    {0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00},  // 0009 (uni0009)
    {0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff},  // 000a (uni000A)
    {0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78},  // 000b (uni000B)
    {0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18},  // 000c (uni000C)
    {0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0},  // 000d (uni000D)
    {0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0},  // 000e (uni000E)
    {0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99},  // 000f (uni000F)
    {0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00},  // 0010 (uni0010)
    {0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00},  // 0011 (uni0011)
    {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18},  // 0012 (uni0012)
    {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00},  // 0013 (uni0013)
    {0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00},  // 0014 (uni0014)
    {0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78},  // 0015 (uni0015)
    {0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00},  // 0016 (uni0016)
    {0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff},  // 0017 (uni0017)
    {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00},  // 0018 (uni0018)
    {0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00},  // 0019 (uni0019)
    {0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00},  // 001a (uni001A)
    {0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00},  // 001b (uni001B)
    {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00},  // 001c (uni001C)
    {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00},  // 001d (uni001D)
    {0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00},  // 001e (uni001E)
    {0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00},  // 001f (uni001F)
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},  // 0020 (space)
    {0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00},  // 0021 (exclam)
    {0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00},  // 0022 (quotedbl)
    {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00},  // 0023 (numbersign)
    {0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00},  // 0024 (dollar)
    {0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00},  // 0025 (percent)
    {0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00},  // 0026 (ampersand)
    {0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00},  // 0027 (quotesingle)
    {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00},  // 0028 (parenleft)
    {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00},  // 0029 (parenright)
    {0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00},  // 002a (asterisk)
    {0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00},  // 002b (plus)
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60},  // 002c (comma)
    {0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00},  // 002d (hyphen)
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00},  // 002e (period)
    {0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00},  // 002f (slash)
    {0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00},  // 0030 (zero)
    {0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00},  // 0031 (one)
    {0x78, 0xcc, 0x0c, 0x38, 0x60, 0xc4, 0xfc, 0x00},  // 0032 (two)
    {0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00},  // 0033 (three)
    {0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00},  // 0034 (four)
    {0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00},  // 0035 (five)
    {0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00},  // 0036 (six)
    {0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00},  // 0037 (seven)
    {0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00},  // 0038 (eight)
    {0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00},  // 0039 (nine)
    {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00},  // 003a (colon)
    {0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0x00},  // 003b (semicolon)
    {0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00},  // 003c (less)
    {0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00},  // 003d (equal)
    {0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00},  // 003e (greater)
    {0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00},  // 003f (question)
    {0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00},  // 0040 (at)
    {0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00},  // 0041 (A)
    {0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00},  // 0042 (B)
    {0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00},  // 0043 (C)
    {0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00},  // 0044 (D)
    {0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00},  // 0045 (E)
    {0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00},  // 0046 (F)
    {0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00},  // 0047 (G)
    {0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00},  // 0048 (H)
    {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},  // 0049 (I)
    {0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00},  // 004a (J)
    {0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00},  // 004b (K)
    {0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00},  // 004c (L)
    {0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00},  // 004d (M)
    {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00},  // 004e (N)
    {0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00},  // 004f (O)
    {0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00},  // 0050 (P)
    {0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00},  // 0051 (Q)
    {0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00},  // 0052 (R)
    {0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00},  // 0053 (S)
    {0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},  // 0054 (T)
    {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00},  // 0055 (U)
    {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},  // 0056 (V)
    {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00},  // 0057 (W)
    {0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00},  // 0058 (X)
    {0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00},  // 0059 (Y)
    {0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00},  // 005a (Z)
    {0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00},  // 005b (bracketleft)
    {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00},  // 005c (backslash)
    {0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00},  // 005d (bracketright)
    {0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00},  // 005e (asciicircum)
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},  // 005f (underscore)
    {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},  // 0060 (grave)
    {0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00},  // 0061 (a)
    {0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00},  // 0062 (b)
    {0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00},  // 0063 (c)
    {0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00},  // 0064 (d)
    {0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},  // 0065 (e)
    {0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00},  // 0066 (f)
    {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},  // 0067 (g)
    {0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00},  // 0068 (h)
    {0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},  // 0069 (i)
    {0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78},  // 006a (j)
    {0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00},  // 006b (k)
    {0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},  // 006c (l)
    {0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00},  // 006d (m)
    {0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00},  // 006e (n)
    {0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00},  // 006f (o)
    {0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0},  // 0070 (p)
    {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e},  // 0071 (q)
    {0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00},  // 0072 (r)
    {0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00},  // 0073 (s)
    {0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00},  // 0074 (t)
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00},  // 0075 (u)
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},  // 0076 (v)
    {0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00},  // 0077 (w)
    {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00},  // 0078 (x)
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},  // 0079 (y)
    {0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00},  // 007a (z)
    {0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00},  // 007b (braceleft)
    {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},  // 007c (bar)
    {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00},  // 007d (braceright)
    {0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},  // 007e (asciitilde)
    {0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00},  // 007f (uni007F)
    // ---------------------------  160-255 ---------------------------
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},  // 00a0 (uni00A0)
    {0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00},  // 00a1 (exclamdown)
    {0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18},  // 00a2 (cent)
    {0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00},  // 00a3 (sterling)
    {0x00, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0x00},  // 00a4 (currency)
    {0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30},  // 00a5 (yen)
    {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},  // 00a6 (brokenbar)
    {0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78},  // 00a7 (section)
    {0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},  // 00a8 (dieresis)
    {0x7e, 0x81, 0x9d, 0xa1, 0xa1, 0x9d, 0x81, 0x7e},  // 00a9 (copyright)
    {0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00},  // 00aa (ordfeminine)
    {0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00},  // 00ab (guillemotleft)
    {0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00},  // 00ac (logicalnot)
    {0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00},  // 00ad (uni00AD)
    {0x7e, 0x81, 0xb9, 0xa5, 0xb9, 0xa5, 0x81, 0x7e},  // 00ae (registered)
    {0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},  // 00af (macron)
    {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00},  // 00b0 (degree)
    {0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00},  // 00b1 (plusminus)
    {0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00},  // 00b2 (uni00B2)
    {0x70, 0x18, 0x30, 0x18, 0x70, 0x00, 0x00, 0x00},  // 00b3 (uni00B3)
    {0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00},  // 00b4 (acute)
    {0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0},  // 00b5 (mu)
    {0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00},  // 00b6 (paragraph)
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00},  // 00b7 (periodcentered)
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x38},  // 00b8 (cedilla)
    {0x30, 0x70, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00},  // 00b9 (uni00B9)
    {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00},  // 00ba (ordmasculine)
    {0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00},  // 00bb (guillemotright)
    {0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03},  // 00bc (onequarter)
    {0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f},  // 00bd (onehalf)
    {0xe0, 0x33, 0x66, 0x3c, 0xfb, 0x37, 0x6f, 0xc3},  // 00be (threequarters)
    {0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00},  // 00bf (questiondown)
    {0xc0, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00},  // 00c0 (Agrave)
    {0x06, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00},  // 00c1 (Aacute)
    {0x7c, 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00},  // 00c2 (Acircumflex)
    {0x76, 0xdc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00},  // 00c3 (Atilde)
    {0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00},  // 00c4 (Adieresis)
    {0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00},  // 00c5 (Aring)
    {0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00},  // 00c6 (AE)
    {0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78},  // 00c7 (Ccedilla)
    {0xe0, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00},  // 00c8 (Egrave)
    {0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00},  // 00c9 (Eacute)
    {0x78, 0xcc, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00},  // 00ca (Ecircumflex)
    {0xcc, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00},  // 00cb (Edieresis)
    {0xe0, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00},  // 00cc (Igrave)
    {0x1c, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00},  // 00cd (Iacute)
    {0x7e, 0xc3, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00},  // 00ce (Icircumflex)
    {0xcc, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00},  // 00cf (Idieresis)
    {0xf8, 0x6c, 0x66, 0xf6, 0x66, 0x6c, 0xf8, 0x00},  // 00d0 (Eth)
    {0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00},  // 00d1 (Ntilde)
    {0xc0, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x00},  // 00d2 (Ograve)
    {0x06, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x00},  // 00d3 (Oacute)
    {0x7c, 0xc6, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00},  // 00d4 (Ocircumflex)
    {0x76, 0xdc, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00},  // 00d5 (Otilde)
    {0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00},  // 00d6 (Odieresis)
    {0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00},  // 00d7 (multiply)
    {0x3a, 0x6c, 0xce, 0xd6, 0xe6, 0x6c, 0xb8, 0x00},  // 00d8 (Oslash)
    {0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00},  // 00d9 (Ugrave)
    {0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00},  // 00da (Uacute)
    {0x7c, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0x7c, 0x00},  // 00db (Ucircumflex)
    {0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00},  // 00dc (Udieresis)
    {0x1c, 0x00, 0xcc, 0xcc, 0x78, 0x30, 0x78, 0x00},  // 00dd (Yacute)
    {0xf0, 0x60, 0x7c, 0x66, 0x7c, 0x60, 0xf0, 0x00},  // 00de (Thorn)
    {0x78, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xcc, 0x00},  // 00df (germandbls)
    {0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},  // 00e0 (agrave)
    {0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},  // 00e1 (aacute)
    {0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00},  // 00e2 (acircumflex)
    {0x76, 0xdc, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},  // 00e3 (atilde)
    {0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},  // 00e4 (adieresis)
    {0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},  // 00e5 (aring)
    {0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00},  // 00e6 (ae)
    {0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38},  // 00e7 (ccedilla)
    {0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},  // 00e8 (egrave)
    {0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},  // 00e9 (eacute)
    {0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00},  // 00ea (ecircumflex)
    {0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},  // 00eb (edieresis)
    {0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},  // 00ec (igrave)
    {0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},  // 00ed (iacute)
    {0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00},  // 00ee (icircumflex)
    {0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},  // 00ef (idieresis)
    {0x30, 0x7e, 0x0c, 0x7c, 0xcc, 0xcc, 0x78, 0x00},  // 00f0 (eth)
    {0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00},  // 00f1 (ntilde)
    {0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},  // 00f2 (ograve)
    {0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},  // 00f3 (oacute)
    {0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},  // 00f4 (ocircumflex)
    {0x76, 0xdc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},  // 00f5 (otilde)
    {0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},  // 00f6 (odieresis)
    {0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00},  // 00f7 (divide)
    {0x00, 0x02, 0x7c, 0xce, 0xd6, 0xe6, 0x7c, 0x80},  // 00f8 (oslash)
    {0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},  // 00f9 (ugrave)
    {0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},  // 00fa (uacute)
    {0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},  // 00fb (ucircumflex)
    {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},  // 00fc (udieresis)
    {0x00, 0x1c, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0x78},  // 00fd (yacute)
    {0xe0, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0xf0},  // 00fe (thorn)
    {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},  // 00ff (ydieresis)
};

const int output_pins[16] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1, A2, A3, A4};
const int R[] = {3, 4, 5, 6, 7, 8, 9, 10};
// const int R[] = {10, 9, 8, 7, 6, 5, 4, 3};
// const int C[] = {11, 12, 13, A0, A1, A2, A3, A4};
const int C[] = {A4, A3, A2, A1, A0, 13, 12, 11};

// {0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00},  // 002d (hyphen)
// {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00},  // 004e (N)
// {0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},  // 0054 (T)
// {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00},  // 0055 (U)
const int lookup[4] = {0x4e, 0x54, 0x54, 0x55};

const uint32_t nttu_letters_combined[8] = {0xc6fcfccc, 0xe6b4b4cc, 0xf63030cc, 0xde3030cc, 0xce3030cc, 0xc63030cc, 0xc67878fc, 0x00000000};

// const float sine_lookup_table[8] = {0.0, 0.43388374, 0.78183148, 0.97492791, 0.97492791, 0.78183148, 0.43388374, 0.0};
const int wait_times_lookup_table[8] = {10, 43, 78, 97, 97, 78, 43, 10};
// int wait_times_lookup_table[8] = {1, 4, 8, 10, 10, 8, 4, 1};

const byte interruptPin = 2;

void display0() {
  // All LEDs switched on
  for (int i=0; i<8; i++) {
    digitalWrite(R[i], HIGH);
    for (int j=0; j<8; j++) {
      digitalWrite(C[j], LOW);
    }
  }
}

void display4(uint8_t *data) {
  // Display "N", "T", "T", "U" sequentially
  int time_outer = 0;
  int time_inner = 0;
  int period_outer = 1;
  int period_inner = 1;
  uint8_t bits[8] = {0};
  uint8_t mask = 1;

  for (int i=0; i<8; i++) {
    time_outer = millis();
    // Serial.println(*(data + i), BIN);
    digitalWrite(R[i], HIGH);
    // https://stackoverflow.com/questions/1682996/bytes-to-binary-in-c
    // bits[8] = {0};
    mask = 1;
    for (int j=0; j<8; j++) {
      time_inner = millis();
      // Mask each bit in the byte and store it
      bits[j] = !(*(data + i) & (mask << j));
      // Serial.println(bits[j], BIN);
      digitalWrite(C[j], bits[j]);
      while(millis() < time_inner + period_inner) {}
    }
    clearleds();
    while(millis() < time_outer + period_outer) {}
  }
}

void display5(uint32_t *data, uint8_t pos) {
  // Display horizontally scrolling "NTTU"
  int time_outer = 0;
  int time_inner = 0;
  int period_outer = 1;
  int period_inner = 1;
  uint8_t bits[32] = {0};
  uint32_t mask = 1;

  for (int i=0; i<8; i++) {
    time_outer = millis();
    digitalWrite(R[i], HIGH);
    mask = 1;
    for (int j=0; j<8; j++) {
      time_inner = millis();
      bits[j+pos] = !(*(data + i) & (mask << j+pos));
      digitalWrite(C[j], bits[j+pos]);
      while(millis() < time_inner + period_inner) {}
    }
    clearleds();
    while(millis() < time_outer + period_outer) {}
  }
}

void display6() {
  // Display vertically moving line
  int time_outer = 0;
  int time_inner = 0;
  int period_outer = 100;
  int period_inner = 1;
  uint8_t bits[8] = {0};
  uint8_t mask = 1;
  
  for (int i=0; i<8; i++) {
    time_outer = millis();
    digitalWrite(R[i], HIGH);
    for (int j=0; j<8; j++) {
      time_inner = millis();
      digitalWrite(C[j], LOW);
      while(millis() < time_inner + period_inner) {}
      // while(millis() < time_inner + wait_times_lookup_table[j]) {}
    }
    clearleds();
    // while(millis() < time_outer + period_outer) {}
    while(millis() < time_outer + wait_times_lookup_table[i]) {}
  }
  for (int i=8; i>0; i--) {
    time_outer = millis();
    digitalWrite(R[i], HIGH);
    for (int j=0; j<8; j++) {
      time_inner = millis();
      digitalWrite(C[j], LOW);
      while(millis() < time_inner + period_inner) {}
      // while(millis() < time_inner + wait_times_lookup_table[j]) {}
    }
    clearleds();
    // while(millis() < time_outer + period_outer) {}
    while(millis() < time_outer + wait_times_lookup_table[i]) {}
  }
}

void clearleds() {
  for (int i=0; i<8; i++) {
    digitalWrite(R[i], LOW);
    for (int j=0; j<8; j++) {
      digitalWrite(C[j], HIGH);
    }
  }
}

int button_mode = 2;
void switch_press() {
  button_mode++;
  if (button_mode == 4) {
    button_mode = 0;
  }
}

void setup() {
  for (int i=0; i<16; i++) {
    pinMode(output_pins[i], OUTPUT);
  }

  // https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
  pinMode(interruptPin, INPUT_PULLUP);
  // Wokwi simulates button bouncing by default. You can disable bouncing simulation by setting the "bounce" attr to "0": { "bounce": "0" }
  attachInterrupt(digitalPinToInterrupt(interruptPin), switch_press, CHANGE);
  // https://arduino.stackexchange.com/questions/41658/can-i-cause-breaking-the-main-loop-from-an-interrupt  
}

int time_now = millis();
const int period_wait = 100;

void loop() {
  switch (button_mode) {
    case 0:
      display0();
      break;
    case 1:
      for (int i=0; i<4; i++) {
        display4(font8x8_ib8x8u[lookup[i]]);
        clearleds();
        time_now = millis();
        while(millis() < time_now + period_wait) {}
      }
      break;
    case 2:
      for (int pos=24; pos>1; pos--) {
        display5(nttu_letters_combined, pos);
        clearleds();
        time_now = millis();
        while(millis() < time_now + period_wait) {}
      }
      for (int pos=1; pos<24; pos++) {
        display5(nttu_letters_combined, pos);
        clearleds();
        time_now = millis();
        while(millis() < time_now + period_wait) {}
      }
      break;
    case 3:
      display6();
      clearleds();
      time_now = millis();
      while(millis() < time_now + period_wait) {}
      break;
  }
}
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
led8:A
led8:C
led9:A
led9:C
led10:A
led10:C
led11:A
led11:C
led12:A
led12:C
led13:A
led13:C
led14:A
led14:C
led15:A
led15:C
led16:A
led16:C
led17:A
led17:C
led18:A
led18:C
led19:A
led19:C
led20:A
led20:C
led21:A
led21:C
led22:A
led22:C
led23:A
led23:C
led24:A
led24:C
led25:A
led25:C
led26:A
led26:C
led27:A
led27:C
led28:A
led28:C
led29:A
led29:C
led30:A
led30:C
led31:A
led31:C
led32:A
led32:C
led33:A
led33:C
led34:A
led34:C
led35:A
led35:C
led36:A
led36:C
led37:A
led37:C
led38:A
led38:C
led39:A
led39:C
led40:A
led40:C
led41:A
led41:C
led42:A
led42:C
led43:A
led43:C
led44:A
led44:C
led45:A
led45:C
led46:A
led46:C
led47:A
led47:C
led48:A
led48:C
led49:A
led49:C
led50:A
led50:C
led51:A
led51:C
led52:A
led52:C
led53:A
led53:C
led54:A
led54:C
led55:A
led55:C
led56:A
led56:C
led57:A
led57:C
led58:A
led58:C
led59:A
led59:C
led60:A
led60:C
led61:A
led61:C
led62:A
led62:C
led63:A
led63:C
led64:A
led64:C
r1:1
r1:2
r2:1
r2:2
r3:1
r3:2
r4:1
r4:2
r5:1
r5:2
r6:1
r6:2
r7:1
r7:2
r8:1
r8:2
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r