Skip to content

Instantly share code, notes, and snippets.

@lovyan03
Created January 9, 2024 01:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lovyan03/746d99c0072ce1a030942dd2d44f87cc to your computer and use it in GitHub Desktop.
Save lovyan03/746d99c0072ce1a030942dd2d44f87cc to your computer and use it in GitHub Desktop.
ESP32 S3 の I2S出力機能を使って NTSC信号を出力してみるテスト
// ESP32-S3 の I2S を使って NTSC を出力するサンプル
#include <sdkconfig.h>
#include <esp_log.h>
#include <driver/i2s.h>
#include <soc/i2s_periph.h>
#include <soc/i2s_struct.h>
#include <driver/gpio.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
// NTSC信号を出力するピン
#define PIN_OUTPUT GPIO_NUM_2
// フレームバッファ (RGB332形式。1ピクセルあたり1Byte)
#define FRAME_WIDTH 192
#define FRAME_HEIGHT 128
uint8_t framebuffer[FRAME_WIDTH * FRAME_HEIGHT];
// NTSC出力 1ラインあたりのサンプル数
#define NUM_LINE_SAMPLES 910 // 227.5 * 4
// NTSC出力 走査線数
#define NUM_LINES 525 // 走査線525本
// RGB332 カラーパレット (PDMデータテーブル)
uint32_t color_tbl[256];
static union {
uint32_t burst_tbl_raw;
uint8_t burst_tbl[4];
};
extern const uint16_t sushi[];
static void makeDmaBuffer(uint8_t* buf, size_t line_num)
{
static uint_fast8_t odd_burst = 0;
odd_burst = 2 ^ odd_burst;
size_t y = line_num * 2;
bool odd_frame = y > NUM_LINES;
if (odd_frame) {
y = y - NUM_LINES;
}
if (y < 20)
{
for (int i = 0; i < 2; ++i)
{
int sink_index = y + i;
if (sink_index < 2) continue;
bool long_sink = sink_index >= 8 && sink_index <= 13;
auto b = &buf[i * (NUM_LINE_SAMPLES / 2)];
int sink_len = 0;
if (sink_index < 20) {
sink_len = long_sink ? 390 : 32;
memset(b, 0, sink_len);
}
for (int j = sink_len; j < (NUM_LINE_SAMPLES / 2); ++j)
{
b[j] = (j&1) ? 0x42 : 0x10;
}
}
}
else
{
y = (y-20);
int sink_len = 68;
int active_start = 148;
int burst_start = 76;
memset(buf, 0, sink_len);
if (y < 18) { active_start = NUM_LINE_SAMPLES; }
for (int i = sink_len; i < active_start; ++i)
{
buf[i] = (i&1) ? 0x42 : 0x10;
}
buf[sink_len] = 0x60;
for (int i = burst_start; i < burst_start + 4 * 10; ++i)
{
// buf[i] = ((i + odd_burst) & 2) ? 0x08 : 0xAA;
buf[i] = burst_tbl[(i + odd_burst) & 3];
}
auto f = &framebuffer[(y>>2) * FRAME_WIDTH];
auto b = &buf[active_start];
for (int i = active_start; i < NUM_LINE_SAMPLES - 16; i+=4)
{
auto c = (const uint8_t*)(&color_tbl[*f++]);
b[0] = c[(odd_burst + 0) ];
b[1] = c[(odd_burst + 1) ];
b[2] = c[(odd_burst + 2) & 3];
b[3] = c[(odd_burst + 3) & 3];
b += 4;
}
}
}
// これは I2Sの tx_conf1.tx_bck_no_dly = 1 を指定した際の送信ビット順の異常を補正する処理。
// 各データの先頭ビットが前回のデータに置き換わってしまうため、事前に右に1ビットローテイトさせておく。
uint32_t workarround_esp32s3_i2s_bck_nodelay(uint32_t data)
{
uint32_t res = 0;
for (int i = 0; i < 4; ++i) {
uint8_t tmp = data >> (i * 8);
tmp = tmp >> 1 | tmp << 7;
res |= tmp << (i*8);
}
return res;
}
static uint32_t setup_palette_ntsc_inner(uint32_t rgb, uint32_t diff_level, uint32_t base_level, float satuation_base, float chroma_scale)
{
// static constexpr float BASE_RAD = (M_PI * 192) / 180; // 2.932153;
uint32_t r = rgb >> 16;
uint32_t g = (rgb >> 8) & 0xFF;
uint32_t b = rgb & 0xFF;
float y = r * 0.299f + g * 0.587f + b * 0.114f;
float i = (b - y) * -0.2680f + (r - y) * 0.7358f;
float q = (b - y) * 0.4127f + (r - y) * 0.4778f;
y = y * diff_level / 256 + base_level;
float phase_offset = atan2f(i, q); // + BASE_RAD;
float saturation = sqrtf(i * i + q * q) * chroma_scale;
saturation = saturation * satuation_base;
uint32_t work = 0;
int32_t current_value = 0;
for (int j = 0; j < 40; ++j) {
current_value -= ((int)(y + sinf(phase_offset + (float)M_PI / 16 * j) * saturation));
work <<= 1;
if (current_value < 0) {
current_value += 2560;
work += 1;
}
}
return workarround_esp32s3_i2s_bck_nodelay(__builtin_bswap32(work));
}
static void setup_palette_ntsc_332(uint32_t* palette, uint_fast16_t white_level, uint_fast16_t black_level, uint_fast8_t chroma_level)
{
float chroma_scale = chroma_level / 7168.0f;
float satuation_base = black_level / 2;
uint32_t diff_level = white_level - black_level;
for (int rgb332 = 0; rgb332 < 256; ++rgb332)
{
int r = (( rgb332 >> 5) * 0x49) >> 1;
int g = (((rgb332 >> 2) & 0x07) * 0x49) >> 1;
int b = (( rgb332 & 0x03) * 0x55);
palette[rgb332] = setup_palette_ntsc_inner(r<<16|g<<8|b, diff_level, black_level, satuation_base, chroma_scale);
}
burst_tbl_raw = setup_palette_ntsc_inner(0x707000u, diff_level, 0, satuation_base, chroma_scale);
}
static void task_i2sbuffer(void*) {
bool flip = false;
size_t scanline = 0;
uint8_t dma_buffer[(NUM_LINE_SAMPLES+3)&~3u];
for (;;) {
size_t writelen;
i2s_write(I2S_NUM_0, dma_buffer, NUM_LINE_SAMPLES, &writelen, portMAX_DELAY);
#if defined ( PIN_DEBUG_BUSY )
digitalWrite(PIN_DEBUG_BUSY, HIGH);
#endif
flip = !flip;
makeDmaBuffer(dma_buffer, scanline);
if (++scanline >= NUM_LINES) {
scanline = 0;
}
#if defined ( PIN_DEBUG_BUSY )
digitalWrite(PIN_DEBUG_BUSY, LOW);
#endif
}
}
void setup(void)
{
#if defined ( PIN_DEBUG_BUSY )
pinMode(PIN_DEBUG_BUSY, OUTPUT);
#endif
setup_palette_ntsc_332(color_tbl, 960*2, 286*2, 128);
i2s_config_t i2s_config;
memset(&i2s_config, 0, sizeof(i2s_config_t));
i2s_config.mode = (i2s_mode_t)( I2S_MODE_MASTER | I2S_MODE_TX );
i2s_config.sample_rate = 192000; // dummy setting
i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_8BIT;
i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
i2s_config.communication_format = (i2s_comm_format_t)( I2S_COMM_FORMAT_STAND_I2S );
i2s_config.tx_desc_auto_clear = false;
i2s_config.dma_buf_count = 2;
i2s_config.dma_buf_len = NUM_LINE_SAMPLES;
i2s_config.use_apll = false;
i2s_config.fixed_mclk = 0;
i2s_config.mclk_multiple = i2s_mclk_multiple_t::I2S_MCLK_MULTIPLE_DEFAULT;
i2s_pin_config_t pin_config;
memset(&pin_config, ~0u, sizeof(i2s_pin_config_t)); /// all pin set to I2S_PIN_NO_CHANGE
pin_config.data_out_num = PIN_OUTPUT;
i2s_driver_install(i2s_port_t::I2S_NUM_0, &i2s_config, 0, nullptr);
i2s_set_pin(i2s_port_t::I2S_NUM_0, &pin_config);
I2S0.tx_conf.tx_start = 0;
I2S0.tx_clkm_conf.tx_clk_active = false;
I2S0.tx_clkm_conf.tx_clk_sel = 1; // クロックソースの選択。 1 = 240MHz PLL_D2_CLOCK
I2S0.tx_clkm_conf.tx_clkm_div_num = 2; // 基準クロックからMCLKへ分周比
I2S0.tx_clkm_div_conf.tx_clkm_div_yn1 = 0;// クロック小数成分の指定
I2S0.tx_clkm_div_conf.tx_clkm_div_x = 9; // クロック小数成分の指定
I2S0.tx_clkm_div_conf.tx_clkm_div_y = 1; // クロック小数成分の指定
I2S0.tx_clkm_div_conf.tx_clkm_div_z = 2; // クロック小数成分の指定
I2S0.tx_conf1.tx_bck_div_num = 0; // MCLKからBCLKへの分周比
I2S0.tx_conf1.tx_bck_no_dly = 1; // BCLK遅延無し設定
/// 上記のクロック設定で 114.5454 MHzでの出力が可能になる。
/// つまり 4Byte (32bit)単位で3.579545 MHz = NTSCサブキャリア周波数が再現できる。
// tx_bck_div_num = 0 かつ tx_bck_no_dly=1 の場合、
// 送信するデータそれぞれの先頭ビットが ひとつ前のデータのものに変わってしまう。
// 対策としてはデータ生成時に右1ビットローテイトさせるしかない。
I2S0.tx_conf.tx_reset = true;
I2S0.tx_conf.tx_fifo_reset = true;
I2S0.tx_conf.tx_update = 1;
I2S0.rx_clkm_conf.mclk_sel = 0;
I2S0.tx_clkm_conf.clk_en = true;
I2S0.tx_clkm_conf.tx_clk_active = true;
xTaskCreatePinnedToCore(task_i2sbuffer, "tsk_i2s", 4096, nullptr, 2, nullptr, PRO_CPU_NUM);
vTaskDelay(1);
I2S0.tx_conf.tx_update = 0;
I2S0.tx_conf.tx_start = 1;
// カラーバー描画
for (size_t y = 0; y < FRAME_HEIGHT; ++y) {
size_t x = 100;
static constexpr const uint8_t colbar[] = {
0xFFu, 0xFCu, 0x1Fu, 0x1Cu, 0xE3u, 0xE0u, 0x03u, 0x00u
};
int baridx = 0;
uint8_t c = colbar[baridx];
for (int i = 0; i < FRAME_WIDTH; ++i)
{
if (++x >= 25) {
x = 0;
c = colbar[baridx&7];
++baridx;
}
framebuffer[i + y * FRAME_WIDTH] = c;
}
}
}
void loop(void)
{
vTaskDelay(16);
static uint32_t counter = 0;
++counter;
for (size_t y = 24; y < 72; ++y)
{
for (size_t x = 0; x < FRAME_WIDTH; ++x)
{
size_t idx = ((x+counter) % 48) + ((y+counter) % 48) * 48;
uint_fast16_t rgb565 = (sushi[idx]);
uint8_t r = (rgb565 >> 8) & 0xE0u;
uint8_t g = (rgb565 >> 6) & 0x1Cu;
uint8_t b = (rgb565 >> 3) & 0x03u;
framebuffer[x + y * FRAME_WIDTH] = r + g + b;
}
}
for (size_t y = 72; y < FRAME_HEIGHT; ++y)
{
for (size_t x = 0; x < FRAME_WIDTH; ++x)
{
uint8_t r = (x-counter)<<1;
uint8_t g = (y+counter)<<1;
uint8_t b = (((x+counter) & 0x80) + ((y-counter) & 0x100)) >> 1;
framebuffer[x + y * FRAME_WIDTH] = (r & 0xE0) + ((g >> 3) & 0x1C) + (b >> 6);
}
}
}
constexpr const uint16_t sushi[2304] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x1860, 0x69C5, 0x7A46, 0x82C8, 0x7B2B, 0x838C, 0x7BAE, 0x83AE, 0x7B2C, 0x5A07, 0x0821, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5143, 0xAB88,
0xFD2E, 0xFDD0, 0xFDF0, 0xFDF1, 0xFE32, 0xFEB5, 0xFF16, 0xFEF7, 0xFEF6, 0xFEF6, 0xFED5, 0xFED5, 0xFF17, 0xFED6, 0xE551, 0x934A,
0x5165, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7A65, 0xFDB0, 0xFE52, 0xFDD2,
0xFD92, 0xFD71, 0xFD30, 0xF590, 0xFDB1, 0xFD4E, 0xF52D, 0xFD6D, 0xFD8E, 0xF5AE, 0xFDCF, 0xF5F0, 0xF5F0, 0xF5D1, 0xFDF1, 0xFDF1,
0xFE12, 0xFE32, 0xCC2C, 0x5143, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFD6F, 0xFE74, 0xFD91, 0xFC8D, 0xFC2B,
0xFC4A, 0xF429, 0xFD0C, 0xF4CA, 0xFC88, 0xF4A9, 0xFCC9, 0xF4E9, 0xFD08, 0xFD09, 0xF509, 0xFD09, 0xF509, 0xFD2B, 0xF5AE, 0xF5AE,
0xF5B0, 0xF5D1, 0xFDF2, 0xFE12, 0xFCEE, 0x5143, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1840, 0xFEB3, 0xFE54, 0xFC8D, 0xFC4A, 0xFC89, 0xFC88,
0xFC86, 0xFDAD, 0xF528, 0xFD07, 0xFD27, 0xFD27, 0xFD47, 0xFD27, 0xF507, 0xFD07, 0xFCC6, 0xF54B, 0xFDAC, 0xF52A, 0xF4A7, 0xFCA8,
0xF4A8, 0xF4AA, 0xF50C, 0xF54E, 0xFDB1, 0xFDB0, 0xE40A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFE72, 0xFDF3, 0xFCA9, 0xFD08, 0xFD48, 0xFD66, 0xFE2B,
0xF60C, 0xFD46, 0xFD05, 0xFCE5, 0xFD05, 0xFCE5, 0xF4C5, 0xFD87, 0xFE4B, 0xF6B0, 0xFEAF, 0xFDC8, 0xFD26, 0xFCE7, 0xFCC7, 0xF4A8,
0xFC87, 0xF487, 0xFC68, 0xF489, 0xF4CB, 0xF56F, 0xFD70, 0xFD8E, 0x28C2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9B48, 0xFEB4, 0xFD68, 0xFDA8, 0xFD86, 0xFCA5, 0xFD09, 0xFB43,
0xFAE3, 0xFAA3, 0xFA62, 0xFA42, 0xFA62, 0xFB24, 0xFB86, 0xFAE3, 0xFAC1, 0xFAA0, 0xFB61, 0xFC85, 0xF5A8, 0xFE09, 0xFD87, 0xFD07,
0xF4C6, 0xFC87, 0xF467, 0xFC67, 0xFC48, 0xFC6A, 0xF4EC, 0xFD4F, 0xFDAF, 0x69A3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFF17, 0xFD46, 0xFCC5, 0xFB84, 0xFAC3, 0xFBC7, 0xF9C1, 0xF9A1,
0xF960, 0xF100, 0xE8E0, 0xF9E2, 0xE9A2, 0xF100, 0xF120, 0xE961, 0xF1A1, 0xFA02, 0xFA01, 0xFA01, 0xFA60, 0xFB41, 0xFCE5, 0xFE0B,
0xFDEB, 0xFD69, 0xFD29, 0xF50A, 0xF50B, 0xFD0C, 0xF56E, 0xFD2F, 0xF54F, 0xFDCF, 0x30C2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1841, 0xFD09, 0xFB23, 0xFA42, 0xF940, 0xFA42, 0xD101, 0xBA05, 0xAAE9,
0xABED, 0x93ED, 0x9C6F, 0x9CD1, 0xAD53, 0x9CF2, 0xACB1, 0xA40E, 0xB36D, 0xB288, 0xC902, 0xD8A0, 0xF161, 0xF263, 0xFB06, 0xFB22,
0xFCE4, 0xF608, 0xFD88, 0xFD06, 0xFCC8, 0xFCA9, 0xFC89, 0xF48B, 0xFCED, 0xFD6F, 0xFDAF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDA85, 0xE9C3, 0xC3AC, 0xB533, 0xBE57, 0xDFBD, 0xE77D, 0xC677,
0xDEFA, 0xD698, 0xE71B, 0xE6F9, 0xF77D, 0xE73B, 0xEF3B, 0xEF7D, 0xE71A, 0xD71A, 0xDF3B, 0xB594, 0xCCAF, 0xC102, 0xE060, 0xE940,
0xF9E2, 0xFB42, 0xFD86, 0xFE2A, 0xFD68, 0xFD29, 0xFD0A, 0xFCCB, 0xFCCC, 0xFD0E, 0xFE52, 0x3103, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3A8A, 0xD79B, 0xBE36, 0xEF9D, 0xE71A, 0xEF3C, 0xE71A, 0xEF3C,
0xE71A, 0xD6B9, 0xD678, 0xE73B, 0xDED9, 0xE71B, 0xE71A, 0xE6FA, 0xDEDA, 0xE71B, 0xE6FA, 0xE71B, 0xE73B, 0xCED9, 0xB553, 0xBA87,
0xE0A0, 0xF181, 0xF9C1, 0xFBE3, 0xFEAC, 0xFE4E, 0xFDEC, 0xFDAD, 0xFD6D, 0xFD4E, 0xFED4, 0x2924, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xAD54, 0xD6D8, 0xCE36, 0xE73B, 0xBE36, 0xD6D9, 0xD71A,
0xCED9, 0xDF3B, 0xD6D9, 0xDED9, 0xCE97, 0xD6D9, 0xD6D9, 0xD6B8, 0xDF3A, 0xDEFA, 0xDED9, 0xE6FA, 0xE6FA, 0xEF3B, 0xEF5B, 0xDF1B,
0x9511, 0xB1C5, 0xF1C2, 0xF223, 0xFA61, 0xFCE4, 0xFDE7, 0xFD8A, 0xFD6B, 0xFDAE, 0xFE90, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4227, 0x9D53, 0xADB4, 0xE699, 0xF679, 0xFDD6,
0xFD96, 0xFD55, 0xFD34, 0xFD34, 0xFD14, 0xFD14, 0xF514, 0xFDB6, 0xF618, 0xF658, 0xE698, 0xDEB9, 0xCEF9, 0xD6DA, 0xDEFA, 0xDEB9,
0xEF3B, 0xC698, 0x9C4E, 0xC880, 0xF141, 0xF161, 0xFB23, 0xFD65, 0xFDA8, 0xFD27, 0xAB08, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x41C7, 0xD514, 0xFDF7, 0xFD14, 0xFCB2, 0xF472,
0xF430, 0xF3CF, 0xF38E, 0xF30C, 0xEB6E, 0xF411, 0xEBAE, 0xF34E, 0xEB4D, 0xEB8E, 0xF410, 0xF4B3, 0xFD75, 0xFE38, 0xE6B9, 0xD6F9,
0xD6B9, 0xCE57, 0xF79D, 0xBE77, 0x9A47, 0xC8A0, 0xE8A0, 0xF120, 0xEA60, 0xD369, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF5D7, 0xFE38, 0xFD34, 0xF451, 0xF451, 0xEC31, 0xEC11,
0xF3CF, 0xEC11, 0xF4B3, 0xF493, 0xF3CF, 0xF2AB, 0xF2CC, 0xEACC, 0xF2AB, 0xF2AC, 0xEA8B, 0xEB2D, 0xF430, 0xEC72, 0xFD55, 0xFDF7,
0xEE57, 0xD697, 0xCED9, 0xE71B, 0xDF3A, 0xCEFA, 0xB552, 0xC5D5, 0xCEFB, 0xA5B5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2945, 0xFE9A, 0xFCD3, 0xF471, 0xF3D0, 0xEBAF, 0xEBF0, 0xEC51, 0xEC52,
0xF431, 0xEB6E, 0xEA6A, 0xEAAB, 0xEAAC, 0xEACC, 0xF2CB, 0xEACC, 0xF2AB, 0xF3AF, 0xF411, 0xF3AF, 0xEAAB, 0xF2EC, 0xEB2D, 0xF3CF,
0xF4D3, 0xFD96, 0xEDF6, 0xD697, 0xCEB8, 0xDEB9, 0xE73B, 0xD698, 0xFFFD, 0x62C9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2945, 0xFD55, 0xFC71, 0xF3CF, 0xEAEC, 0xF410, 0xF411, 0xF36E, 0xEB2D, 0xF32D,
0xEACC, 0xF2EC, 0xF34E, 0xF36E, 0xEB0D, 0xF30C, 0xF32E, 0xEB2D, 0xF3AF, 0xEA8B, 0xEA8A, 0xF2AC, 0xEB0C, 0xF30D, 0xEB2D, 0xF34D,
0xEB6E, 0xF3CF, 0xF4D3, 0xFD76, 0xEDF6, 0xC656, 0xD6B8, 0xF77B, 0x632B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFE18, 0xFB6E, 0xF2EC, 0xF2AB, 0xF493, 0xF30C, 0xEAEC, 0xEB4E, 0xEB4E, 0xEC32,
0xF4F4, 0xEBAF, 0xEA8B, 0xF24A, 0xEA4A, 0xEA4A, 0xEA4A, 0xF24A, 0xEA6A, 0xF26B, 0xEA6A, 0xEA6A, 0xEA4A, 0xEAAB, 0xF38F, 0xEBCF,
0xF431, 0xF431, 0xF431, 0xF472, 0xF534, 0xFE39, 0x83CD, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xA451, 0xFACB, 0xF2EC, 0xF28B, 0xF472, 0xF28B, 0xF30D, 0xF30D, 0xF2ED, 0xF515, 0xF493,
0xEBB0, 0xF36F, 0xF32E, 0xEACC, 0xEA4A, 0xF22A, 0xEA29, 0xEA2A, 0xEA09, 0xEA29, 0xF2CC, 0xF411, 0xF3F0, 0xF34E, 0xEA8B, 0xF28B,
0xEAEC, 0xEB2D, 0xF3AE, 0xEBF0, 0xF410, 0xF492, 0xFDF8, 0xE5F6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFD96, 0xFAAB, 0xF34D, 0xFC31, 0xFA8A, 0xF1E9, 0xF26A, 0xF4B3, 0xF492, 0xE9E8, 0xE9E8,
0xEA08, 0xEA08, 0xF1C8, 0xE9E8, 0xF2AB, 0xF2EC, 0xF2ED, 0xF32E, 0xF34E, 0xF32E, 0xEAEC, 0xEA09, 0xEA4A, 0xF2AB, 0xEAAB, 0xEA8B,
0xF28B, 0xEACC, 0xEB0D, 0xF36E, 0xF3EF, 0xF430, 0xF471, 0xFD34, 0xFE59, 0x1082, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x3186, 0xFBCF, 0xFC73, 0xF36E, 0xE166, 0xD1E8, 0xD36E, 0xCB2C, 0xC945, 0xC125, 0xC186, 0xC166,
0xC966, 0xC104, 0xCA6A, 0xD229, 0xD125, 0xD905, 0xE145, 0xE9A7, 0xF1C8, 0xF208, 0xF209, 0xEA0A, 0xEA4A, 0xEAAC, 0xF32E, 0xF30D,
0xEACC, 0xF2AB, 0xF2AB, 0xEAAB, 0xF34E, 0xEC11, 0xF492, 0xF4F4, 0xFD54, 0xFEBB, 0x10A2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x728A, 0xFB8E, 0xD0C3, 0xC125, 0xB905, 0xC1C7, 0xB842, 0xB822, 0xB042, 0xB082, 0xB041, 0xB882,
0xB862, 0xD2EB, 0xB8A2, 0xC0C3, 0xB0E4, 0xC124, 0xB925, 0xC145, 0xC945, 0xD125, 0xD905, 0xF249, 0xFBD0, 0xFBD0, 0xFCB3, 0xF515,
0xFCB3, 0xF431, 0xF3F0, 0xF3AF, 0xF32D, 0xF2CC, 0xF34D, 0xF3CF, 0xF472, 0xFCD2, 0xFDF8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x6B0B, 0xF946, 0xC8A4, 0xB082, 0xA186, 0xAB6C, 0x9CB0, 0xADF5, 0xB676, 0xAE15, 0xCEFA, 0xB615,
0xBDB5, 0xB532, 0xB450, 0xAB0A, 0xAA69, 0xA145, 0xA062, 0xB082, 0xC0C3, 0xC104, 0xCA8A, 0xC186, 0xC904, 0xD125, 0xD986, 0xEA8B,
0xF38F, 0xFC32, 0xF3D0, 0xF34E, 0xF30C, 0xF2CC, 0xF2EC, 0xF32D, 0xF3CF, 0xFC92, 0xFCF3, 0x5208, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xA470, 0xBDB4, 0xD79C, 0xDF9C, 0xEF9D, 0xEF7D, 0xF7BD, 0xEF5D, 0xEF7C, 0xEF7D, 0xEF7D,
0xE73B, 0xE75C, 0xDEFA, 0xE79D, 0xDF9C, 0xDFBD, 0xC719, 0xADD5, 0x9C0E, 0xA2CA, 0xA0A2, 0xB862, 0xC104, 0xC125, 0xC945, 0xC966,
0xD166, 0xE229, 0xFB4E, 0xFBF1, 0xFBD0, 0xF34D, 0xF2EC, 0xFAEC, 0xF32D, 0xF3CF, 0xFC71, 0x9B8E, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x634C, 0xEF7C, 0xF7BE, 0xEF9D, 0xF79D, 0xE75C, 0xDEFA, 0xE73B, 0xE71B, 0xEF5C, 0xE73B,
0xE71B, 0xEF9D, 0xF79D, 0xEF7D, 0xEF7D, 0xE6FA, 0xEF9D, 0xEF5B, 0xE75C, 0xDF3B, 0xE7FE, 0xAD94, 0xA32B, 0x9861, 0xC0A3, 0xC104,
0xC965, 0xD167, 0xD145, 0xE1A7, 0xFAEC, 0xFB8F, 0xFB0D, 0xF2CC, 0xFAEC, 0xF34D, 0xFC51, 0x9BCF, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x10A2, 0xFFFF, 0xDEFA, 0xDEFA, 0xEF5C, 0xE75B, 0xE73B, 0xE73B, 0xDEFA, 0xD6B9, 0xD6D9,
0xEF5C, 0xE71A, 0xDF1B, 0xE73B, 0xE73B, 0xE73B, 0xE73C, 0xEF5C, 0xEF7D, 0xEF7D, 0xEF7D, 0xEF9C, 0xEFBD, 0xDFBD, 0xA4F2, 0xA185,
0xB862, 0xC0E3, 0xCA29, 0xD2AB, 0xD1A7, 0xEA29, 0xFB4D, 0xFBAF, 0xFBAF, 0xFC72, 0xFB8E, 0x7B6D, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x630A, 0xE719, 0xD6D9, 0xDEDA, 0xC657, 0xD698, 0xD6B9, 0xD698, 0xD6B9, 0xE71B,
0xCE77, 0xDEFA, 0xDEDA, 0xD6B9, 0xE71B, 0xDF1B, 0xDEFA, 0xDF1A, 0xE73C, 0xEF7C, 0xEF7C, 0xF7BE, 0xEF7D, 0xEF9D, 0xE75B, 0xD75B,
0xA5B4, 0x91A6, 0xC125, 0xC0C3, 0xC925, 0xC8E5, 0xE105, 0xFA29, 0xFB4D, 0xFB8E, 0xFB6E, 0x4249, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x39C6, 0xBE15, 0xD677, 0xE73B, 0xDEFA, 0xDEDA, 0xD6D9, 0xD6D9, 0xCE78,
0xC657, 0xDEFA, 0xCE78, 0xCE77, 0xE71B, 0xCE98, 0xE71B, 0xDEFA, 0xDF1A, 0xDEFA, 0xEF5C, 0xE71B, 0xE73B, 0xE73C, 0xE71B, 0xF7BE,
0xEF7D, 0xE7DD, 0xA552, 0xA145, 0xB882, 0xC145, 0xC105, 0xD105, 0xE905, 0xF966, 0xFD35, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x18C2, 0x632B, 0xAD93, 0xF79C, 0xDED9, 0xCE57, 0xDED9,
0xD6B9, 0xCE57, 0xCE78, 0xDEFA, 0xDED9, 0xBDF5, 0xE71B, 0xDEFA, 0xD698, 0xE71A, 0xDF1A, 0xCE98, 0xDF1B, 0xDED9, 0xE73B, 0xE75C,
0xF79D, 0xE73B, 0xF7BE, 0xDFDD, 0xACD1, 0xA0C3, 0xA8A3, 0xA8E3, 0xB0E4, 0xE0C4, 0xA451, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3A07, 0x7BEE, 0xC616,
0xDEF9, 0xCE77, 0xD6B8, 0xCE98, 0xDEB9, 0xE73B, 0xDED9, 0xCE98, 0xEF3C, 0xCE98, 0xD6B9, 0xD6B9, 0xDED9, 0xDEDA, 0xCE77, 0xDEFB,
0xDEFA, 0xDF1A, 0xEF5C, 0xE71B, 0xEF9D, 0xD79C, 0xACB0, 0x9A28, 0xBA8A, 0xDD13, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x4227, 0x632B, 0x8C4F, 0xC636, 0xDEF9, 0xD698, 0xDEF9, 0xBE16, 0xD6B9, 0xD6B8, 0xC616, 0xBDD5, 0xCE77, 0xDEFA, 0xD698,
0xD6B9, 0xD698, 0xDF1B, 0xE71B, 0xDF1B, 0xEF7C, 0xD6FA, 0xEF9D, 0xADF5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2123, 0x7BCE, 0xDEF9, 0xCE97, 0xDED9, 0xE73A, 0xDF3B, 0xD6B9, 0xCE98, 0xD698,
0xD698, 0xD6B9, 0xC636, 0xE71B, 0xCE77, 0xD6B9, 0xF79D, 0xFFFE, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x39C6, 0x52A9, 0x5AA9, 0x8C4F, 0xD6B9,
0xD6D8, 0xDED9, 0xD6F9, 0xD6B8, 0xC616, 0xDED9, 0x9D11, 0x0861, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0840, 0x4A48, 0x52CA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment