diff --git a/.gitignore b/.gitignore index 4457a31..ef292a2 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ tests/logs/ # Benchmark result files benchmark_*.mat simple_comparison_*.mat +.codex-review/ diff --git a/configs/arena_registry/index.yaml b/configs/arena_registry/index.yaml index 4a0a574..e1c567e 100644 --- a/configs/arena_registry/index.yaml +++ b/configs/arena_registry/index.yaml @@ -40,3 +40,4 @@ G6: 1: G6_2x10 2: G6_2x8of10 3: G6_3x12of18 + 4: G6_3x16_full diff --git a/g6/crc16_ccitt_false.m b/g6/crc16_ccitt_false.m new file mode 100644 index 0000000..870c27c --- /dev/null +++ b/g6/crc16_ccitt_false.m @@ -0,0 +1,61 @@ +function crc = crc16_ccitt_false(bytes) +% CRC16_CCITT_FALSE Compute CRC-16/CCITT-FALSE over a byte sequence. +% +% Used for the G6 .pat per-frame trailer over {FR_magic, frame_index, +% panel_blocks} of that frame only. Trailer is 2 bytes appended little-endian +% after the panel blocks of each frame. +% +% Parameters (per Modular-LED-Display/docs/development/g6_04-pattern-file-format.md): +% polynomial : 0x1021 +% init : 0xFFFF +% refin/refout : false / false +% xorout : 0x0000 +% universal check : 0x29B1 over "123456789" +% +% The 256-entry LUT is built from the polynomial constant on first call and +% cached in a persistent variable. The universal check runs alongside the +% LUT build and ERRORS on mismatch. +% +% Input: +% bytes - uint8 vector (any length, including empty) +% +% Output: +% crc - uint16 + + persistent LUT; + if isempty(LUT) + LUT = zeros(256, 1, 'uint16'); + poly = uint16(hex2dec('1021')); + for b = 0:255 + c = uint16(bitshift(uint16(b), 8)); + for i = 1:8 + if bitand(c, uint16(32768)) ~= 0 + c = bitxor(uint16(bitshift(c, 1)), poly); + else + c = uint16(bitshift(c, 1)); + end + c = bitand(c, uint16(65535)); + end + LUT(b + 1) = c; + end + + % Universal-check gate: "123456789" -> 0x29B1 + ucheck = uint8('123456789'); + c = uint16(65535); + for i = 1:length(ucheck) + idx = bitand(bitxor(bitshift(c, -8), uint16(ucheck(i))), uint16(255)); + c = bitand(bitxor(uint16(bitshift(c, 8)), LUT(idx + 1)), uint16(65535)); + end + if c ~= uint16(hex2dec('29B1')) + error('crc16_ccitt_false:LUTBuildFailed', ... + 'CRC-16/CCITT-FALSE universal check failed: got 0x%04X, expected 0x29B1', c); + end + end + + c = uint16(65535); + for i = 1:length(bytes) + idx = bitand(bitxor(bitshift(c, -8), uint16(bytes(i))), uint16(255)); + c = bitand(bitxor(uint16(bitshift(c, 8)), LUT(idx + 1)), uint16(65535)); + end + crc = c; +end diff --git a/g6/crc8_autosar.m b/g6/crc8_autosar.m new file mode 100644 index 0000000..ab0ff19 --- /dev/null +++ b/g6/crc8_autosar.m @@ -0,0 +1,64 @@ +function crc = crc8_autosar(bytes) +% CRC8_AUTOSAR Compute CRC-8/AUTOSAR over a byte sequence. +% +% Used for the G6 .pat file header byte 17 (CRC over header bytes 0-16) and +% for the panel-protocol wire-level CIPO confirmation byte (handled by the +% panel firmware, not encoders). +% +% Parameters (per Modular-LED-Display/docs/development/g6_01-panel-protocol.md): +% polynomial : 0x2F (Koopman 0x97) +% init : 0xFF +% refin/refout : false / false +% xorout : 0xFF +% universal check : 0xDF over "123456789" +% +% The 256-entry LUT is built from the polynomial constant on first call and +% cached in a persistent variable. The universal check runs alongside the +% LUT build and ERRORS on mismatch — that's the gate that catches table- +% construction bugs before any encoder/parser uses the function. +% +% Input: +% bytes - uint8 vector (any length, including empty) +% +% Output: +% crc - uint8 + + persistent LUT; + if isempty(LUT) + LUT = zeros(256, 1, 'uint8'); + poly = uint8(hex2dec('2F')); + for b = 0:255 + c = uint8(b); + for i = 1:8 + if bitand(c, 128) ~= 0 + c = bitxor(uint8(bitshift(c, 1)), poly); + else + c = uint8(bitshift(c, 1)); + end + end + LUT(b + 1) = c; + end + + % Universal-check gate: "123456789" -> 0xDF + % NOTE on indexing: bitxor on uint8 returns uint8, and adding 1 to + % uint8(255) SATURATES at 255 rather than rolling over to 256. Cast + % the XOR result to double before `+ 1` so the LUT lookup hits the + % correct entry for the byte-value 0xFF. + ucheck = uint8('123456789'); + c = uint8(255); + for i = 1:length(ucheck) + c = LUT(double(bitxor(c, ucheck(i))) + 1); + end + c = bitxor(c, uint8(255)); + if c ~= uint8(hex2dec('DF')) + error('crc8_autosar:LUTBuildFailed', ... + 'CRC-8/AUTOSAR universal check failed: got 0x%02X, expected 0xDF', c); + end + end + + c = uint8(255); + for i = 1:length(bytes) + c = LUT(double(bitxor(c, uint8(bytes(i)))) + 1); + end + crc = bitxor(c, uint8(255)); +end diff --git a/g6/g6_encode_panel.m b/g6/g6_encode_panel.m index 24bf7dd..4ec7433 100644 --- a/g6/g6_encode_panel.m +++ b/g6/g6_encode_panel.m @@ -129,15 +129,18 @@ % Count '1' bits in version's bits 0..6 (exclude bit 7 = parity slot). % MATLAB bitget is 1-indexed: bits 1..7 == bits 0..6. -total_ones = 0; +% NOTE: use double for the running sum — bitget returns the input class +% (uint8), and a uint8 accumulator saturates at 255. For GS16 panels the +% popcount can reach ~800 and the saturation breaks the parity bit. +total_ones = double(0); for bit_idx = 1:7 - total_ones = total_ones + bitget(version, bit_idx); + total_ones = total_ones + double(bitget(version, bit_idx)); end % Add '1' bits from cmd + payload (bytes 2..block_len in MATLAB 1-indexing). for byte_idx = 2:block_len for bit_idx = 1:8 - total_ones = total_ones + bitget(panel_block(byte_idx), bit_idx); + total_ones = total_ones + double(bitget(panel_block(byte_idx), bit_idx)); end end diff --git a/g6/g6_encoding_reference.json b/g6/g6_encoding_reference.json index abc3020..62636ff 100644 --- a/g6/g6_encoding_reference.json +++ b/g6/g6_encoding_reference.json @@ -1,171 +1,8910 @@ { -"generated":"2026-01-23 12:10:51", -"source":"MATLAB g6_encode_panel.m", -"encoding_convention":{ -"origin":"bottom-left", -"ordering":"row-major", -"formula":"pixel_num = row_from_bottom * 20 + col", -"gs2_bit_order":"MSB-first (bit 7 = first pixel in byte)", -"gs16_nibble_order":"high nibble = even pixel, low nibble = odd pixel" -}, -"test_vectors":[{ -"name":"single_pixel_00", -"description":"Single pixel at (0,0) bottom-left", -"panel_row":0, -"panel_col":0, -"matlab_row":20, -"matlab_col":1, -"pixel_num":0, -"gs2_value":1, -"gs16_value":15, -"gs2_bytes":[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], -"gs16_bytes":[240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] -},{ -"name":"single_pixel_01", -"description":"Single pixel at (0,1)", -"panel_row":0, -"panel_col":1, -"matlab_row":20, -"matlab_col":2, -"pixel_num":1, -"gs2_value":1, -"gs16_value":15, -"gs2_bytes":[64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], -"gs16_bytes":[15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] -},{ -"name":"single_pixel_0_19", -"description":"Single pixel at (0,19) bottom-right", -"panel_row":0, -"panel_col":19, -"matlab_row":20, -"matlab_col":20, -"pixel_num":19, -"gs2_value":1, -"gs16_value":15, -"gs2_bytes":[0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], -"gs16_bytes":[0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] -},{ -"name":"single_pixel_19_0", -"description":"Single pixel at (19,0) top-left", -"panel_row":19, -"panel_col":0, -"matlab_row":1, -"matlab_col":1, -"pixel_num":380, -"gs2_value":1, -"gs16_value":15, -"gs2_bytes":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0], -"gs16_bytes":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0] -},{ -"name":"single_pixel_19_19", -"description":"Single pixel at (19,19) top-right", -"panel_row":19, -"panel_col":19, -"matlab_row":1, -"matlab_col":20, -"pixel_num":399, -"gs2_value":1, -"gs16_value":15, -"gs2_bytes":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], -"gs16_bytes":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15] -},{ -"name":"two_adjacent_pixels", -"description":"Two adjacent pixels at (0,0) and (0,1)", -"gs2_value":1, -"gs16_values":[15,10], -"gs2_bytes":[192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], -"gs16_bytes":[250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] -},{ -"name":"bottom_row_lit", -"description":"Bottom row (row 0) all lit", -"gs2_bytes":[255,255,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] -},{ -"name":"left_column_lit", -"description":"Left column (col 0) all lit", -"gs2_bytes":[128,0,8,0,0,128,0,8,0,0,128,0,8,0,0,128,0,8,0,0,128,0,8,0,0,128,0,8,0,0,128,0,8,0,0,128,0,8,0,0,128,0,8,0,0,128,0,8,0,0] -}], -"patterns":{ -"all_off":{ -"description":"All LEDs off", -"mode":"GS2", -"gs2_bytes":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] -}, -"all_on":{ -"description":"All LEDs on", -"mode":"GS2", -"gs2_bytes":[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255] -}, -"border":{ -"description":"Border frame (rows/columns 0 and 19)", -"mode":"GS2", -"pixel_matrix":[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]], -"gs2_bytes":[255,255,248,0,1,128,0,24,0,1,128,0,24,0,1,128,0,24,0,1,128,0,24,0,1,128,0,24,0,1,128,0,24,0,1,128,0,24,0,1,128,0,24,0,1,128,0,31,255,255] -}, -"cross":{ -"description":"Cross pattern (rows/cols 9-10)", -"mode":"GS2", -"pixel_matrix":[[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0]], -"gs2_bytes":[0,96,0,6,0,0,96,0,6,0,0,96,0,6,0,0,96,0,6,0,0,96,15,255,255,255,255,240,6,0,0,96,0,6,0,0,96,0,6,0,0,96,0,6,0,0,96,0,6,0] -}, -"checker_2x2":{ -"description":"2x2 checkerboard pattern", -"mode":"GS2", -"pixel_matrix":[[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],[1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0]], -"gs2_bytes":[204,204,204,204,204,51,51,51,51,51,204,204,204,204,204,51,51,51,51,51,204,204,204,204,204,51,51,51,51,51,204,204,204,204,204,51,51,51,51,51,204,204,204,204,204,51,51,51,51,51] -}, -"horiz_stripes":{ -"description":"Horizontal stripes every 4 rows", -"mode":"GS2", -"pixel_matrix":[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]], -"gs2_bytes":[255,255,240,0,0,0,0,0,0,0,255,255,240,0,0,0,0,0,0,0,255,255,240,0,0,0,0,0,0,0,255,255,240,0,0,0,0,0,0,0,255,255,240,0,0,0,0,0,0,0] -}, -"vert_stripes":{ -"description":"Vertical stripes every 4 columns", -"mode":"GS2", -"pixel_matrix":[[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0]], -"gs2_bytes":[136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136] -}, -"gradient_h":{ -"description":"Horizontal gradient (intensity by row)", -"mode":"GS16", -"pixel_matrix":[[15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15],[14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14],[13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13],[12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12],[11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],[11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],[10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10],[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9],[8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8],[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],[6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6],[5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],[4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]], -"gs16_bytes":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,68,68,68,68,68,68,68,68,68,68,85,85,85,85,85,85,85,85,85,85,102,102,102,102,102,102,102,102,102,102,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,153,153,153,153,153,153,153,153,153,153,170,170,170,170,170,170,170,170,170,170,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,204,204,204,204,204,204,204,204,204,204,221,221,221,221,221,221,221,221,221,221,238,238,238,238,238,238,238,238,238,238,255,255,255,255,255,255,255,255,255,255] -}, -"gradient_v":{ -"description":"Vertical gradient (intensity by column)", -"mode":"GS16", -"pixel_matrix":[[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15],[0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11,12,13,14,15]], -"gs16_bytes":[0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239,0,18,51,69,103,120,154,187,205,239] -}, -"gradient_diag":{ -"description":"Diagonal gradient", -"mode":"GS16", -"pixel_matrix":[[7,7,8,8,9,9,9,10,10,11,11,11,12,12,13,13,13,14,14,15],[7,7,7,8,8,9,9,9,10,10,11,11,11,12,12,13,13,13,14,14],[6,7,7,7,8,8,9,9,9,10,10,11,11,11,12,12,13,13,13,14],[6,6,7,7,7,8,8,9,9,9,10,10,11,11,11,12,12,13,13,13],[5,6,6,7,7,7,8,8,9,9,9,10,10,11,11,11,12,12,13,13],[5,5,6,6,7,7,7,8,8,9,9,9,10,10,11,11,11,12,12,13],[5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,11,11,11,12,12],[4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,11,11,11,12],[4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,11,11,11],[3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,11,11],[3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,11],[3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10],[2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10],[2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9],[1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9],[1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9],[1,1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8],[0,1,1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8],[0,0,1,1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7],[0,0,0,1,1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7]], -"gs16_bytes":[0,1,17,34,51,52,69,85,102,119,0,17,18,35,51,68,85,86,103,119,1,17,34,51,52,69,85,102,119,120,17,18,35,51,68,85,86,103,119,136,17,34,51,52,69,85,102,119,120,137,18,35,51,68,85,86,103,119,136,153,34,51,52,69,85,102,119,120,137,153,35,51,68,85,86,103,119,136,153,154,51,52,69,85,102,119,120,137,153,170,51,68,85,86,103,119,136,153,154,171,52,69,85,102,119,120,137,153,170,187,68,85,86,103,119,136,153,154,171,187,69,85,102,119,120,137,153,170,187,188,85,86,103,119,136,153,154,171,187,204,85,102,119,120,137,153,170,187,188,205,86,103,119,136,153,154,171,187,204,221,102,119,120,137,153,170,187,188,205,221,103,119,136,153,154,171,187,204,221,222,119,120,137,153,170,187,188,205,221,238,119,136,153,154,171,187,204,221,222,239] -}, -"concentric_bright":{ -"description":"Concentric bright (center bright)", -"mode":"GS16", -"pixel_matrix":[[0,0,1,2,2,3,3,4,4,4,4,4,4,3,3,2,2,1,0,0],[0,1,2,3,3,4,5,5,5,5,5,5,5,5,4,3,3,2,1,0],[1,2,3,4,4,5,6,6,6,7,7,6,6,6,5,4,4,3,2,1],[2,3,4,5,5,6,7,7,8,8,8,8,7,7,6,5,5,4,3,2],[2,3,4,5,6,7,8,8,9,9,9,9,8,8,7,6,5,4,3,2],[3,4,5,6,7,8,9,9,10,10,10,10,9,9,8,7,6,5,4,3],[3,5,6,7,8,9,10,10,11,11,11,11,10,10,9,8,7,6,5,3],[4,5,6,7,8,9,10,11,12,12,12,12,11,10,9,8,7,6,5,4],[4,5,6,8,9,10,11,12,13,14,14,13,12,11,10,9,8,6,5,4],[4,5,7,8,9,10,11,12,14,15,15,14,12,11,10,9,8,7,5,4],[4,5,7,8,9,10,11,12,14,15,15,14,12,11,10,9,8,7,5,4],[4,5,6,8,9,10,11,12,13,14,14,13,12,11,10,9,8,6,5,4],[4,5,6,7,8,9,10,11,12,12,12,12,11,10,9,8,7,6,5,4],[3,5,6,7,8,9,10,10,11,11,11,11,10,10,9,8,7,6,5,3],[3,4,5,6,7,8,9,9,10,10,10,10,9,9,8,7,6,5,4,3],[2,3,4,5,6,7,8,8,9,9,9,9,8,8,7,6,5,4,3,2],[2,3,4,5,5,6,7,7,8,8,8,8,7,7,6,5,5,4,3,2],[1,2,3,4,4,5,6,6,6,7,7,6,6,6,5,4,4,3,2,1],[0,1,2,3,3,4,5,5,5,5,5,5,5,5,4,3,3,2,1,0],[0,0,1,2,2,3,3,4,4,4,4,4,4,3,3,2,2,1,0,0]], -"gs16_bytes":[0,18,35,52,68,68,67,50,33,0,1,35,52,85,85,85,85,67,50,16,18,52,69,102,103,118,102,84,67,33,35,69,86,119,136,136,119,101,84,50,35,69,103,136,153,153,136,118,84,50,52,86,120,153,170,170,153,135,101,67,53,103,137,170,187,187,170,152,118,83,69,103,137,171,204,204,186,152,118,84,69,104,154,188,222,237,203,169,134,84,69,120,154,188,239,254,203,169,135,84,69,120,154,188,239,254,203,169,135,84,69,104,154,188,222,237,203,169,134,84,69,103,137,171,204,204,186,152,118,84,53,103,137,170,187,187,170,152,118,83,52,86,120,153,170,170,153,135,101,67,35,69,103,136,153,153,136,118,84,50,35,69,86,119,136,136,119,101,84,50,18,52,69,102,103,118,102,84,67,33,1,35,52,85,85,85,85,67,50,16,0,18,35,52,68,68,67,50,33,0] -}, -"concentric_dark":{ -"description":"Concentric dark (center dark)", -"mode":"GS16", -"pixel_matrix":[[15,15,14,13,13,12,12,11,11,11,11,11,11,12,12,13,13,14,15,15],[15,14,13,12,12,11,10,10,10,10,10,10,10,10,11,12,12,13,14,15],[14,13,12,11,11,10,9,9,9,8,8,9,9,9,10,11,11,12,13,14],[13,12,11,10,10,9,8,8,7,7,7,7,8,8,9,10,10,11,12,13],[13,12,11,10,9,8,7,7,6,6,6,6,7,7,8,9,10,11,12,13],[12,11,10,9,8,7,6,6,5,5,5,5,6,6,7,8,9,10,11,12],[12,10,9,8,7,6,5,5,4,4,4,4,5,5,6,7,8,9,10,12],[11,10,9,8,7,6,5,4,3,3,3,3,4,5,6,7,8,9,10,11],[11,10,9,7,6,5,4,3,2,1,1,2,3,4,5,6,7,9,10,11],[11,10,8,7,6,5,4,3,1,0,0,1,3,4,5,6,7,8,10,11],[11,10,8,7,6,5,4,3,1,0,0,1,3,4,5,6,7,8,10,11],[11,10,9,7,6,5,4,3,2,1,1,2,3,4,5,6,7,9,10,11],[11,10,9,8,7,6,5,4,3,3,3,3,4,5,6,7,8,9,10,11],[12,10,9,8,7,6,5,5,4,4,4,4,5,5,6,7,8,9,10,12],[12,11,10,9,8,7,6,6,5,5,5,5,6,6,7,8,9,10,11,12],[13,12,11,10,9,8,7,7,6,6,6,6,7,7,8,9,10,11,12,13],[13,12,11,10,10,9,8,8,7,7,7,7,8,8,9,10,10,11,12,13],[14,13,12,11,11,10,9,9,9,8,8,9,9,9,10,11,11,12,13,14],[15,14,13,12,12,11,10,10,10,10,10,10,10,10,11,12,12,13,14,15],[15,15,14,13,13,12,12,11,11,11,11,11,11,12,12,13,13,14,15,15]], -"gs16_bytes":[255,237,220,203,187,187,188,205,222,255,254,220,203,170,170,170,170,188,205,239,237,203,186,153,152,137,153,171,188,222,220,186,169,136,119,119,136,154,171,205,220,186,152,119,102,102,119,137,171,205,203,169,135,102,85,85,102,120,154,188,202,152,118,85,68,68,85,103,137,172,186,152,118,84,51,51,69,103,137,171,186,151,101,67,33,18,52,86,121,171,186,135,101,67,16,1,52,86,120,171,186,135,101,67,16,1,52,86,120,171,186,151,101,67,33,18,52,86,121,171,186,152,118,84,51,51,69,103,137,171,202,152,118,85,68,68,85,103,137,172,203,169,135,102,85,85,102,120,154,188,220,186,152,119,102,102,119,137,171,205,220,186,169,136,119,119,136,154,171,205,237,203,186,153,152,137,153,171,188,222,254,220,203,170,170,170,170,188,205,239,255,237,220,203,187,187,188,205,222,255] -}, -"checkerboard_intensity":{ -"description":"Checkerboard intensity (15/5)", -"mode":"GS16", -"pixel_matrix":[[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15],[15,15,15,15,5,5,5,5,15,15,15,15,5,5,5,5,15,15,15,15]], -"gs16_bytes":[255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,85,85,255,255,85,85,255,255,85,85,85,85,255,255,85,85,255,255,85,85,85,85,255,255,85,85,255,255,85,85,85,85,255,255,85,85,255,255,85,85,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,85,85,255,255,85,85,255,255,85,85,85,85,255,255,85,85,255,255,85,85,85,85,255,255,85,85,255,255,85,85,85,85,255,255,85,85,255,255,85,85,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255,255,255,85,85,255,255,85,85,255,255] -}, -"spotlight":{ -"description":"Spotlight (exponential falloff)", -"mode":"GS16", -"pixel_matrix":[[0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0],[0,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,0],[1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1],[1,1,1,1,2,2,2,3,3,3,3,3,3,2,2,2,1,1,1,1],[1,1,1,2,2,3,3,3,4,4,4,4,3,3,3,2,2,1,1,1],[1,1,2,2,3,3,4,4,5,5,5,5,4,4,3,3,2,2,1,1],[1,1,2,2,3,4,4,5,6,6,6,6,5,4,4,3,2,2,1,1],[1,2,2,3,3,4,5,6,7,8,8,7,6,5,4,3,3,2,2,1],[1,2,2,3,4,5,6,7,9,10,10,9,7,6,5,4,3,2,2,1],[1,2,2,3,4,5,6,8,10,12,12,10,8,6,5,4,3,2,2,1],[1,2,2,3,4,5,6,8,10,12,12,10,8,6,5,4,3,2,2,1],[1,2,2,3,4,5,6,7,9,10,10,9,7,6,5,4,3,2,2,1],[1,2,2,3,3,4,5,6,7,8,8,7,6,5,4,3,3,2,2,1],[1,1,2,2,3,4,4,5,6,6,6,6,5,4,4,3,2,2,1,1],[1,1,2,2,3,3,4,4,5,5,5,5,4,4,3,3,2,2,1,1],[1,1,1,2,2,3,3,3,4,4,4,4,3,3,3,2,2,1,1,1],[1,1,1,1,2,2,2,3,3,3,3,3,3,2,2,2,1,1,1,1],[1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1],[0,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,0],[0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0]], -"gs16_bytes":[0,17,17,17,17,17,17,17,17,0,1,17,17,18,34,34,33,17,17,16,17,17,18,34,34,34,34,33,17,17,17,17,34,35,51,51,50,34,17,17,17,18,35,51,68,68,51,50,33,17,17,34,51,68,85,85,68,51,34,17,17,34,52,69,102,102,84,67,34,17,18,35,52,86,120,135,101,67,50,33,18,35,69,103,154,169,118,84,50,33,18,35,69,104,172,202,134,84,50,33,18,35,69,104,172,202,134,84,50,33,18,35,69,103,154,169,118,84,50,33,18,35,52,86,120,135,101,67,50,33,17,34,52,69,102,102,84,67,34,17,17,34,51,68,85,85,68,51,34,17,17,18,35,51,68,68,51,50,33,17,17,17,34,35,51,51,50,34,17,17,17,17,18,34,34,34,34,33,17,17,1,17,17,18,34,34,33,17,17,16,0,17,17,17,17,17,17,17,17,0] -} -} + "generated": "2026-05-23 22:58:21", + "source": "MATLAB g6_encode_panel.m", + "encoding_convention": { + "origin": "bottom-left", + "ordering": "row-major", + "formula": "pixel_num = row_from_bottom * 20 + col", + "gs2_bit_order": "MSB-first (bit 7 = first pixel in byte)", + "gs16_nibble_order": "high nibble = even pixel, low nibble = odd pixel" + }, + "test_vectors": [ + { + "name": "single_pixel_00", + "description": "Single pixel at (0,0) bottom-left", + "panel_row": 0, + "panel_col": 0, + "matlab_row": 20, + "matlab_col": 1, + "pixel_num": 0, + "gs2_value": 1, + "gs16_value": 15, + "gs2_bytes": [ + 128, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "gs16_bytes": [ + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "name": "single_pixel_01", + "description": "Single pixel at (0,1)", + "panel_row": 0, + "panel_col": 1, + "matlab_row": 20, + "matlab_col": 2, + "pixel_num": 1, + "gs2_value": 1, + "gs16_value": 15, + "gs2_bytes": [ + 64, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "gs16_bytes": [ + 15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "name": "single_pixel_0_19", + "description": "Single pixel at (0,19) bottom-right", + "panel_row": 0, + "panel_col": 19, + "matlab_row": 20, + "matlab_col": 20, + "pixel_num": 19, + "gs2_value": 1, + "gs16_value": 15, + "gs2_bytes": [ + 0, + 0, + 16, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "gs16_bytes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "name": "single_pixel_19_0", + "description": "Single pixel at (19,0) top-left", + "panel_row": 19, + "panel_col": 0, + "matlab_row": 1, + "matlab_col": 1, + "pixel_num": 380, + "gs2_value": 1, + "gs16_value": 15, + "gs2_bytes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 0, + 0 + ], + "gs16_bytes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "name": "single_pixel_19_19", + "description": "Single pixel at (19,19) top-right", + "panel_row": 19, + "panel_col": 19, + "matlab_row": 1, + "matlab_col": 20, + "pixel_num": 399, + "gs2_value": 1, + "gs16_value": 15, + "gs2_bytes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + "gs16_bytes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 15 + ] + }, + { + "name": "two_adjacent_pixels", + "description": "Two adjacent pixels at (0,0) and (0,1)", + "gs2_value": 1, + "gs16_values": [ + 15, + 10 + ], + "gs2_bytes": [ + 192, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "gs16_bytes": [ + 250, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "name": "bottom_row_lit", + "description": "Bottom row (row 0) all lit", + "gs2_bytes": [ + 255, + 255, + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "name": "left_column_lit", + "description": "Left column (col 0) all lit", + "gs2_bytes": [ + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0, + 128, + 0, + 8, + 0, + 0 + ] + } + ], + "patterns": { + "all_off": { + "description": "All LEDs off", + "mode": "GS2", + "gs2_bytes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "all_on": { + "description": "All LEDs on", + "mode": "GS2", + "gs2_bytes": [ + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255 + ] + }, + "border": { + "description": "Border frame (rows/columns 0 and 19)", + "mode": "GS2", + "pixel_matrix": [ + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + ], + "gs2_bytes": [ + 255, + 255, + 248, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 24, + 0, + 1, + 128, + 0, + 31, + 255, + 255 + ] + }, + "cross": { + "description": "Cross pattern (rows/cols 9-10)", + "mode": "GS2", + "pixel_matrix": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ], + "gs2_bytes": [ + 0, + 96, + 0, + 6, + 0, + 0, + 96, + 0, + 6, + 0, + 0, + 96, + 0, + 6, + 0, + 0, + 96, + 0, + 6, + 0, + 0, + 96, + 15, + 255, + 255, + 255, + 255, + 240, + 6, + 0, + 0, + 96, + 0, + 6, + 0, + 0, + 96, + 0, + 6, + 0, + 0, + 96, + 0, + 6, + 0, + 0, + 96, + 0, + 6, + 0 + ] + }, + "checker_2x2": { + "description": "2x2 checkerboard pattern", + "mode": "GS2", + "pixel_matrix": [ + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ], + [ + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0 + ] + ], + "gs2_bytes": [ + 204, + 204, + 204, + 204, + 204, + 51, + 51, + 51, + 51, + 51, + 204, + 204, + 204, + 204, + 204, + 51, + 51, + 51, + 51, + 51, + 204, + 204, + 204, + 204, + 204, + 51, + 51, + 51, + 51, + 51, + 204, + 204, + 204, + 204, + 204, + 51, + 51, + 51, + 51, + 51, + 204, + 204, + 204, + 204, + 204, + 51, + 51, + 51, + 51, + 51 + ] + }, + "horiz_stripes": { + "description": "Horizontal stripes every 4 rows", + "mode": "GS2", + "pixel_matrix": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + ], + "gs2_bytes": [ + 255, + 255, + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 255, + 255, + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 255, + 255, + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 255, + 255, + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 255, + 255, + 240, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "vert_stripes": { + "description": "Vertical stripes every 4 columns", + "mode": "GS2", + "pixel_matrix": [ + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0 + ] + ], + "gs2_bytes": [ + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136 + ] + }, + "gradient_h": { + "description": "Horizontal gradient (intensity by row)", + "mode": "GS16", + "pixel_matrix": [ + [ + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15 + ], + [ + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14 + ], + [ + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13 + ], + [ + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12 + ], + [ + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11 + ], + [ + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11 + ], + [ + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9 + ], + [ + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8 + ], + [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7 + ], + [ + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7 + ], + [ + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6 + ], + [ + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5 + ], + [ + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4 + ], + [ + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3 + ], + [ + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3 + ], + [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ], + "gs16_bytes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 34, + 34, + 34, + 34, + 34, + 34, + 34, + 34, + 34, + 34, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 51, + 68, + 68, + 68, + 68, + 68, + 68, + 68, + 68, + 68, + 68, + 85, + 85, + 85, + 85, + 85, + 85, + 85, + 85, + 85, + 85, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 119, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 136, + 153, + 153, + 153, + 153, + 153, + 153, + 153, + 153, + 153, + 153, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 187, + 204, + 204, + 204, + 204, + 204, + 204, + 204, + 204, + 204, + 204, + 221, + 221, + 221, + 221, + 221, + 221, + 221, + 221, + 221, + 221, + 238, + 238, + 238, + 238, + 238, + 238, + 238, + 238, + 238, + 238, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255 + ] + }, + "gradient_v": { + "description": "Vertical gradient (intensity by column)", + "mode": "GS16", + "pixel_matrix": [ + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ], + [ + 0, + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 11, + 12, + 13, + 14, + 15 + ] + ], + "gs16_bytes": [ + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239, + 0, + 18, + 51, + 69, + 103, + 120, + 154, + 187, + 205, + 239 + ] + }, + "gradient_diag": { + "description": "Diagonal gradient", + "mode": "GS16", + "pixel_matrix": [ + [ + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12, + 12, + 13, + 13, + 13, + 14, + 14, + 15 + ], + [ + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12, + 12, + 13, + 13, + 13, + 14, + 14 + ], + [ + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12, + 12, + 13, + 13, + 13, + 14 + ], + [ + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12, + 12, + 13, + 13, + 13 + ], + [ + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12, + 12, + 13, + 13 + ], + [ + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12, + 12, + 13 + ], + [ + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12, + 12 + ], + [ + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11, + 12 + ], + [ + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11, + 11 + ], + [ + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11, + 11 + ], + [ + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 11 + ], + [ + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10, + 10 + ], + [ + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9, + 10 + ], + [ + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9, + 9 + ], + [ + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9, + 9 + ], + [ + 1, + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 9 + ], + [ + 1, + 1, + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8 + ], + [ + 0, + 1, + 1, + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8 + ], + [ + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7, + 7 + ], + [ + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 7, + 7 + ] + ], + "gs16_bytes": [ + 0, + 1, + 17, + 34, + 51, + 52, + 69, + 85, + 102, + 119, + 0, + 17, + 18, + 35, + 51, + 68, + 85, + 86, + 103, + 119, + 1, + 17, + 34, + 51, + 52, + 69, + 85, + 102, + 119, + 120, + 17, + 18, + 35, + 51, + 68, + 85, + 86, + 103, + 119, + 136, + 17, + 34, + 51, + 52, + 69, + 85, + 102, + 119, + 120, + 137, + 18, + 35, + 51, + 68, + 85, + 86, + 103, + 119, + 136, + 153, + 34, + 51, + 52, + 69, + 85, + 102, + 119, + 120, + 137, + 153, + 35, + 51, + 68, + 85, + 86, + 103, + 119, + 136, + 153, + 154, + 51, + 52, + 69, + 85, + 102, + 119, + 120, + 137, + 153, + 170, + 51, + 68, + 85, + 86, + 103, + 119, + 136, + 153, + 154, + 171, + 52, + 69, + 85, + 102, + 119, + 120, + 137, + 153, + 170, + 187, + 68, + 85, + 86, + 103, + 119, + 136, + 153, + 154, + 171, + 187, + 69, + 85, + 102, + 119, + 120, + 137, + 153, + 170, + 187, + 188, + 85, + 86, + 103, + 119, + 136, + 153, + 154, + 171, + 187, + 204, + 85, + 102, + 119, + 120, + 137, + 153, + 170, + 187, + 188, + 205, + 86, + 103, + 119, + 136, + 153, + 154, + 171, + 187, + 204, + 221, + 102, + 119, + 120, + 137, + 153, + 170, + 187, + 188, + 205, + 221, + 103, + 119, + 136, + 153, + 154, + 171, + 187, + 204, + 221, + 222, + 119, + 120, + 137, + 153, + 170, + 187, + 188, + 205, + 221, + 238, + 119, + 136, + 153, + 154, + 171, + 187, + 204, + 221, + 222, + 239 + ] + }, + "concentric_bright": { + "description": "Concentric bright (center bright)", + "mode": "GS16", + "pixel_matrix": [ + [ + 0, + 0, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 3, + 3, + 2, + 2, + 1, + 0, + 0 + ], + [ + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 4, + 3, + 3, + 2, + 1, + 0 + ], + [ + 1, + 2, + 3, + 4, + 4, + 5, + 6, + 6, + 6, + 7, + 7, + 6, + 6, + 6, + 5, + 4, + 4, + 3, + 2, + 1 + ], + [ + 2, + 3, + 4, + 5, + 5, + 6, + 7, + 7, + 8, + 8, + 8, + 8, + 7, + 7, + 6, + 5, + 5, + 4, + 3, + 2 + ], + [ + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 8, + 9, + 9, + 9, + 9, + 8, + 8, + 7, + 6, + 5, + 4, + 3, + 2 + ], + [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 9, + 10, + 10, + 10, + 10, + 9, + 9, + 8, + 7, + 6, + 5, + 4, + 3 + ], + [ + 3, + 5, + 6, + 7, + 8, + 9, + 10, + 10, + 11, + 11, + 11, + 11, + 10, + 10, + 9, + 8, + 7, + 6, + 5, + 3 + ], + [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 12, + 12, + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4 + ], + [ + 4, + 5, + 6, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 14, + 13, + 12, + 11, + 10, + 9, + 8, + 6, + 5, + 4 + ], + [ + 4, + 5, + 7, + 8, + 9, + 10, + 11, + 12, + 14, + 15, + 15, + 14, + 12, + 11, + 10, + 9, + 8, + 7, + 5, + 4 + ], + [ + 4, + 5, + 7, + 8, + 9, + 10, + 11, + 12, + 14, + 15, + 15, + 14, + 12, + 11, + 10, + 9, + 8, + 7, + 5, + 4 + ], + [ + 4, + 5, + 6, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 14, + 13, + 12, + 11, + 10, + 9, + 8, + 6, + 5, + 4 + ], + [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 12, + 12, + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4 + ], + [ + 3, + 5, + 6, + 7, + 8, + 9, + 10, + 10, + 11, + 11, + 11, + 11, + 10, + 10, + 9, + 8, + 7, + 6, + 5, + 3 + ], + [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 9, + 10, + 10, + 10, + 10, + 9, + 9, + 8, + 7, + 6, + 5, + 4, + 3 + ], + [ + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 8, + 9, + 9, + 9, + 9, + 8, + 8, + 7, + 6, + 5, + 4, + 3, + 2 + ], + [ + 2, + 3, + 4, + 5, + 5, + 6, + 7, + 7, + 8, + 8, + 8, + 8, + 7, + 7, + 6, + 5, + 5, + 4, + 3, + 2 + ], + [ + 1, + 2, + 3, + 4, + 4, + 5, + 6, + 6, + 6, + 7, + 7, + 6, + 6, + 6, + 5, + 4, + 4, + 3, + 2, + 1 + ], + [ + 0, + 1, + 2, + 3, + 3, + 4, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 4, + 3, + 3, + 2, + 1, + 0 + ], + [ + 0, + 0, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 3, + 3, + 2, + 2, + 1, + 0, + 0 + ] + ], + "gs16_bytes": [ + 0, + 18, + 35, + 52, + 68, + 68, + 67, + 50, + 33, + 0, + 1, + 35, + 52, + 85, + 85, + 85, + 85, + 67, + 50, + 16, + 18, + 52, + 69, + 102, + 103, + 118, + 102, + 84, + 67, + 33, + 35, + 69, + 86, + 119, + 136, + 136, + 119, + 101, + 84, + 50, + 35, + 69, + 103, + 136, + 153, + 153, + 136, + 118, + 84, + 50, + 52, + 86, + 120, + 153, + 170, + 170, + 153, + 135, + 101, + 67, + 53, + 103, + 137, + 170, + 187, + 187, + 170, + 152, + 118, + 83, + 69, + 103, + 137, + 171, + 204, + 204, + 186, + 152, + 118, + 84, + 69, + 104, + 154, + 188, + 222, + 237, + 203, + 169, + 134, + 84, + 69, + 120, + 154, + 188, + 239, + 254, + 203, + 169, + 135, + 84, + 69, + 120, + 154, + 188, + 239, + 254, + 203, + 169, + 135, + 84, + 69, + 104, + 154, + 188, + 222, + 237, + 203, + 169, + 134, + 84, + 69, + 103, + 137, + 171, + 204, + 204, + 186, + 152, + 118, + 84, + 53, + 103, + 137, + 170, + 187, + 187, + 170, + 152, + 118, + 83, + 52, + 86, + 120, + 153, + 170, + 170, + 153, + 135, + 101, + 67, + 35, + 69, + 103, + 136, + 153, + 153, + 136, + 118, + 84, + 50, + 35, + 69, + 86, + 119, + 136, + 136, + 119, + 101, + 84, + 50, + 18, + 52, + 69, + 102, + 103, + 118, + 102, + 84, + 67, + 33, + 1, + 35, + 52, + 85, + 85, + 85, + 85, + 67, + 50, + 16, + 0, + 18, + 35, + 52, + 68, + 68, + 67, + 50, + 33, + 0 + ] + }, + "concentric_dark": { + "description": "Concentric dark (center dark)", + "mode": "GS16", + "pixel_matrix": [ + [ + 15, + 15, + 14, + 13, + 13, + 12, + 12, + 11, + 11, + 11, + 11, + 11, + 11, + 12, + 12, + 13, + 13, + 14, + 15, + 15 + ], + [ + 15, + 14, + 13, + 12, + 12, + 11, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 11, + 12, + 12, + 13, + 14, + 15 + ], + [ + 14, + 13, + 12, + 11, + 11, + 10, + 9, + 9, + 9, + 8, + 8, + 9, + 9, + 9, + 10, + 11, + 11, + 12, + 13, + 14 + ], + [ + 13, + 12, + 11, + 10, + 10, + 9, + 8, + 8, + 7, + 7, + 7, + 7, + 8, + 8, + 9, + 10, + 10, + 11, + 12, + 13 + ], + [ + 13, + 12, + 11, + 10, + 9, + 8, + 7, + 7, + 6, + 6, + 6, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 12, + 13 + ], + [ + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 6, + 5, + 5, + 5, + 5, + 6, + 6, + 7, + 8, + 9, + 10, + 11, + 12 + ], + [ + 12, + 10, + 9, + 8, + 7, + 6, + 5, + 5, + 4, + 4, + 4, + 4, + 5, + 5, + 6, + 7, + 8, + 9, + 10, + 12 + ], + [ + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4, + 3, + 3, + 3, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + [ + 11, + 10, + 9, + 7, + 6, + 5, + 4, + 3, + 2, + 1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10, + 11 + ], + [ + 11, + 10, + 8, + 7, + 6, + 5, + 4, + 3, + 1, + 0, + 0, + 1, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 11 + ], + [ + 11, + 10, + 8, + 7, + 6, + 5, + 4, + 3, + 1, + 0, + 0, + 1, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 11 + ], + [ + 11, + 10, + 9, + 7, + 6, + 5, + 4, + 3, + 2, + 1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10, + 11 + ], + [ + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4, + 3, + 3, + 3, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + [ + 12, + 10, + 9, + 8, + 7, + 6, + 5, + 5, + 4, + 4, + 4, + 4, + 5, + 5, + 6, + 7, + 8, + 9, + 10, + 12 + ], + [ + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 6, + 5, + 5, + 5, + 5, + 6, + 6, + 7, + 8, + 9, + 10, + 11, + 12 + ], + [ + 13, + 12, + 11, + 10, + 9, + 8, + 7, + 7, + 6, + 6, + 6, + 6, + 7, + 7, + 8, + 9, + 10, + 11, + 12, + 13 + ], + [ + 13, + 12, + 11, + 10, + 10, + 9, + 8, + 8, + 7, + 7, + 7, + 7, + 8, + 8, + 9, + 10, + 10, + 11, + 12, + 13 + ], + [ + 14, + 13, + 12, + 11, + 11, + 10, + 9, + 9, + 9, + 8, + 8, + 9, + 9, + 9, + 10, + 11, + 11, + 12, + 13, + 14 + ], + [ + 15, + 14, + 13, + 12, + 12, + 11, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 11, + 12, + 12, + 13, + 14, + 15 + ], + [ + 15, + 15, + 14, + 13, + 13, + 12, + 12, + 11, + 11, + 11, + 11, + 11, + 11, + 12, + 12, + 13, + 13, + 14, + 15, + 15 + ] + ], + "gs16_bytes": [ + 255, + 237, + 220, + 203, + 187, + 187, + 188, + 205, + 222, + 255, + 254, + 220, + 203, + 170, + 170, + 170, + 170, + 188, + 205, + 239, + 237, + 203, + 186, + 153, + 152, + 137, + 153, + 171, + 188, + 222, + 220, + 186, + 169, + 136, + 119, + 119, + 136, + 154, + 171, + 205, + 220, + 186, + 152, + 119, + 102, + 102, + 119, + 137, + 171, + 205, + 203, + 169, + 135, + 102, + 85, + 85, + 102, + 120, + 154, + 188, + 202, + 152, + 118, + 85, + 68, + 68, + 85, + 103, + 137, + 172, + 186, + 152, + 118, + 84, + 51, + 51, + 69, + 103, + 137, + 171, + 186, + 151, + 101, + 67, + 33, + 18, + 52, + 86, + 121, + 171, + 186, + 135, + 101, + 67, + 16, + 1, + 52, + 86, + 120, + 171, + 186, + 135, + 101, + 67, + 16, + 1, + 52, + 86, + 120, + 171, + 186, + 151, + 101, + 67, + 33, + 18, + 52, + 86, + 121, + 171, + 186, + 152, + 118, + 84, + 51, + 51, + 69, + 103, + 137, + 171, + 202, + 152, + 118, + 85, + 68, + 68, + 85, + 103, + 137, + 172, + 203, + 169, + 135, + 102, + 85, + 85, + 102, + 120, + 154, + 188, + 220, + 186, + 152, + 119, + 102, + 102, + 119, + 137, + 171, + 205, + 220, + 186, + 169, + 136, + 119, + 119, + 136, + 154, + 171, + 205, + 237, + 203, + 186, + 153, + 152, + 137, + 153, + 171, + 188, + 222, + 254, + 220, + 203, + 170, + 170, + 170, + 170, + 188, + 205, + 239, + 255, + 237, + 220, + 203, + 187, + 187, + 188, + 205, + 222, + 255 + ] + }, + "checkerboard_intensity": { + "description": "Checkerboard intensity (15/5)", + "mode": "GS16", + "pixel_matrix": [ + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ], + [ + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15, + 5, + 5, + 5, + 5, + 15, + 15, + 15, + 15 + ] + ], + "gs16_bytes": [ + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255, + 255, + 255, + 85, + 85, + 255, + 255, + 85, + 85, + 255, + 255 + ] + }, + "spotlight": { + "description": "Spotlight (exponential falloff)", + "mode": "GS16", + "pixel_matrix": [ + [ + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0 + ], + [ + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0 + ], + [ + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 3, + 3, + 3, + 2, + 2, + 1, + 1, + 1 + ], + [ + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 5, + 4, + 4, + 3, + 3, + 2, + 2, + 1, + 1 + ], + [ + 1, + 1, + 2, + 2, + 3, + 4, + 4, + 5, + 6, + 6, + 6, + 6, + 5, + 4, + 4, + 3, + 2, + 2, + 1, + 1 + ], + [ + 1, + 2, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 8, + 8, + 7, + 6, + 5, + 4, + 3, + 3, + 2, + 2, + 1 + ], + [ + 1, + 2, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10, + 10, + 9, + 7, + 6, + 5, + 4, + 3, + 2, + 2, + 1 + ], + [ + 1, + 2, + 2, + 3, + 4, + 5, + 6, + 8, + 10, + 12, + 12, + 10, + 8, + 6, + 5, + 4, + 3, + 2, + 2, + 1 + ], + [ + 1, + 2, + 2, + 3, + 4, + 5, + 6, + 8, + 10, + 12, + 12, + 10, + 8, + 6, + 5, + 4, + 3, + 2, + 2, + 1 + ], + [ + 1, + 2, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10, + 10, + 9, + 7, + 6, + 5, + 4, + 3, + 2, + 2, + 1 + ], + [ + 1, + 2, + 2, + 3, + 3, + 4, + 5, + 6, + 7, + 8, + 8, + 7, + 6, + 5, + 4, + 3, + 3, + 2, + 2, + 1 + ], + [ + 1, + 1, + 2, + 2, + 3, + 4, + 4, + 5, + 6, + 6, + 6, + 6, + 5, + 4, + 4, + 3, + 2, + 2, + 1, + 1 + ], + [ + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 5, + 5, + 4, + 4, + 3, + 3, + 2, + 2, + 1, + 1 + ], + [ + 1, + 1, + 1, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 3, + 3, + 3, + 2, + 2, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1 + ], + [ + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0 + ], + [ + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0 + ] + ], + "gs16_bytes": [ + 0, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 0, + 1, + 17, + 17, + 18, + 34, + 34, + 33, + 17, + 17, + 16, + 17, + 17, + 18, + 34, + 34, + 34, + 34, + 33, + 17, + 17, + 17, + 17, + 34, + 35, + 51, + 51, + 50, + 34, + 17, + 17, + 17, + 18, + 35, + 51, + 68, + 68, + 51, + 50, + 33, + 17, + 17, + 34, + 51, + 68, + 85, + 85, + 68, + 51, + 34, + 17, + 17, + 34, + 52, + 69, + 102, + 102, + 84, + 67, + 34, + 17, + 18, + 35, + 52, + 86, + 120, + 135, + 101, + 67, + 50, + 33, + 18, + 35, + 69, + 103, + 154, + 169, + 118, + 84, + 50, + 33, + 18, + 35, + 69, + 104, + 172, + 202, + 134, + 84, + 50, + 33, + 18, + 35, + 69, + 104, + 172, + 202, + 134, + 84, + 50, + 33, + 18, + 35, + 69, + 103, + 154, + 169, + 118, + 84, + 50, + 33, + 18, + 35, + 52, + 86, + 120, + 135, + 101, + 67, + 50, + 33, + 17, + 34, + 52, + 69, + 102, + 102, + 84, + 67, + 34, + 17, + 17, + 34, + 51, + 68, + 85, + 85, + 68, + 51, + 34, + 17, + 17, + 18, + 35, + 51, + 68, + 68, + 51, + 50, + 33, + 17, + 17, + 17, + 34, + 35, + 51, + 51, + 50, + 34, + 17, + 17, + 17, + 17, + 18, + 34, + 34, + 34, + 34, + 33, + 17, + 17, + 1, + 17, + 17, + 18, + 34, + 34, + 33, + 17, + 17, + 16, + 0, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 0 + ] + } + }, + "crc_test_vectors": { + "crc8_autosar": { + "polynomial": "0x2F", + "init": "0xFF", + "refin": false, + "refout": false, + "xorout": "0xFF", + "spec_section": "g6_01-panel-protocol.md § CRC-8 algorithm", + "usage": "G6 .pat header byte 17 over header bytes 0-16", + "vectors": [ + { + "name": "universal_check", + "input_ascii": "123456789", + "expected_hex": "0xDF" + }, + { + "name": "cipo_2L_oneshot_zeros", + "description": "2L Oneshot all-zero payload, parity cleared (53 bytes: 0x01, 0x10, 51 zeros)", + "expected_hex": "0xC6" + }, + { + "name": "cipo_16L_oneshot_zeros", + "description": "16L Oneshot all-zero payload, parity cleared (203 bytes: 0x01, 0x30, 201 zeros)", + "expected_hex": "0x6D" + } + ] + }, + "crc16_ccitt_false": { + "polynomial": "0x1021", + "init": "0xFFFF", + "refin": false, + "refout": false, + "xorout": "0x0000", + "spec_section": "g6_04-pattern-file-format.md § Frame Format / Per-frame CRC-16", + "usage": "G6 .pat per-frame trailer (little-endian); scope = FR_magic + frame_index + panel_blocks", + "vectors": [ + { + "name": "universal_check", + "input_ascii": "123456789", + "expected_hex": "0x29B1" + }, + { + "name": "all_zero_4bytes", + "description": "Frame header for frame_index=0 (4 bytes: FR_magic + 0x00 0x00)", + "expected_hex": "0xFD6B" + } + ] + } + }, + "canonical_patterns": { + "g6_2x10_gs2_1f_checker": { + "description": "G6_2x10 GS2, 1 frame, pixel(i,j)=mod(i+j,2) (1-indexed)", + "file_size": 1084, + "first_24_bytes_hex": "47 36 50 54 20 00 01 00 02 0A 01 FF FF 0F 00 00 00 DC 46 52 00 00 81 10", + "sha256_hex": "7f7f7f6e7f037f06327f7f7f0e26417f4a7f7f7f3a457f7f7f7f7f7f7f7f6a2e" + } + } } \ No newline at end of file diff --git a/g6/g6_save_pattern.m b/g6/g6_save_pattern.m index e6903f8..08442d4 100644 --- a/g6/g6_save_pattern.m +++ b/g6/g6_save_pattern.m @@ -27,7 +27,10 @@ function g6_save_pattern(Pats, stretch, arena_config, save_dir, filename, vararg % Byte 10: col_count (FULL grid columns) % Byte 11: gs_val (1=GS2, 2=GS16) % Bytes 12-17: panel_mask (6 bytes) -% Byte 18: checksum (XOR of frame data) +% Byte 18: CRC-8/AUTOSAR over header bytes 1-17 (per g6_01-panel-protocol.md § CRC-8) +% +% Each frame ends with a 2-byte CRC-16/CCITT-FALSE trailer (little-endian) +% over {FR_magic, frame_index, panel_blocks} of that frame. % % Example: % % Quick usage with [rows, cols] @@ -312,10 +315,25 @@ function g6_save_pattern(Pats, stretch, arena_config, save_dir, filename, vararg header(10) = col_count; % Full grid column count header(11) = uint8(gs_val); % GS mode (1=GS2, 2=GS16) header(12:17) = panel_mask(1:6); -header(18) = 0; % Checksum placeholder +header(18) = 0; % CRC-8/AUTOSAR placeholder; filled in after header is fully populated + +% Frame size (bytes per frame): 4 magic+idx + num_panels * block_size + 2 CRC-16 trailer +% Block size depends on GS mode: GS2 = 53 bytes, GS16 = 203 bytes +if gs_val == 1 + block_size = 53; +elseif gs_val == 2 + block_size = 203; +else + error('g6_save_pattern:UnsupportedGS', 'Unsupported gs_val: %d (expected 1 or 2)', gs_val); +end +% Cast to double so the arithmetic doesn't saturate at uint8(255) +% (row_count and panel_mask fields are uint8 inside arena_config). +num_panels_installed = double(length(installed_cols)) * double(row_count); +frame_size = 4 + num_panels_installed * block_size + 2; % +2 for CRC-16 trailer +total_frames_size = double(num_frames) * frame_size; -% Generate all frames -all_frames = []; +% Preallocate output buffer (avoid O(N^2) `[all_frames, ...]` growth) +all_frames = zeros(1, total_frames_size, 'uint8'); for frame_idx = 0:(num_frames-1) % Frame header @@ -327,10 +345,13 @@ function g6_save_pattern(Pats, stretch, arena_config, save_dir, filename, vararg full_frame = Pats(:, :, frame_idx+1); stretch_val = stretch(frame_idx+1); - panel_blocks = []; + % Slice into all_frames at the per-frame offset (1-indexed) + frame_offset = frame_idx * frame_size + 1; + all_frames(frame_offset:frame_offset+3) = frame_header; + panel_cursor = frame_offset + 4; - % Iterate over installed columns only - % Pats dimensions match installed columns, so we use local indexing + % Iterate over installed columns only. + % Pats dimensions match installed columns, so we use local indexing. for panel_row = 0:(row_count-1) for local_col_idx = 1:length(installed_cols) % local_col_idx is 1-indexed into the Pats array @@ -343,7 +364,6 @@ function g6_save_pattern(Pats, stretch, arena_config, save_dir, filename, vararg try panel_block = g6_encode_panel(panel_pixels, stretch_val, mode); catch ME - % Provide detailed diagnostics if the call fails fprintf('Error in g6_encode_panel call:\n'); fprintf(' panel_pixels size: %s\n', mat2str(size(panel_pixels))); fprintf(' stretch_val: %d (class: %s)\n', stretch_val, class(stretch_val)); @@ -351,19 +371,21 @@ function g6_save_pattern(Pats, stretch, arena_config, save_dir, filename, vararg fprintf(' g6_encode_panel location: %s\n', which('g6_encode_panel')); rethrow(ME); end - panel_blocks = [panel_blocks, panel_block]; + all_frames(panel_cursor:panel_cursor+block_size-1) = panel_block; + panel_cursor = panel_cursor + block_size; end end - all_frames = [all_frames, frame_header, panel_blocks]; + % Per-frame CRC-16/CCITT-FALSE trailer over {FR_magic, frame_index, panel_blocks} + % of THIS frame only, little-endian. + frame_crc = crc16_ccitt_false(all_frames(frame_offset:panel_cursor-1)); + all_frames(panel_cursor) = uint8(bitand(frame_crc, 255)); + all_frames(panel_cursor+1) = uint8(bitand(bitshift(frame_crc, -8), 255)); end -% Compute checksum -checksum = uint8(0); -for i = 1:length(all_frames) - checksum = bitxor(checksum, all_frames(i)); -end -header(18) = checksum; +% Header CRC-8/AUTOSAR over header bytes 1-17 (zero-indexed 0-16) +% Placeholder byte 18 is NOT in scope. +header(18) = crc8_autosar(header(1:17)); file_data = [header, all_frames]; diff --git a/g6/generate_g6_encoding_reference.m b/g6/generate_g6_encoding_reference.m index 8211461..74a8267 100644 --- a/g6/generate_g6_encoding_reference.m +++ b/g6/generate_g6_encoding_reference.m @@ -433,14 +433,78 @@ function generate_g6_encoding_reference(output_file) ref.patterns = patterns; +%% Generate CRC test vectors (CRC-8/AUTOSAR + CRC-16/CCITT-FALSE) +fprintf('Generating CRC test vectors...\n'); + +crc_vectors = struct(); +crc_vectors.crc8_autosar = struct( ... + 'polynomial', '0x2F', ... + 'init', '0xFF', ... + 'refin', false, ... + 'refout', false, ... + 'xorout', '0xFF', ... + 'spec_section', 'g6_01-panel-protocol.md § CRC-8 algorithm', ... + 'usage', 'G6 .pat header byte 17 over header bytes 0-16'); + +crc_vectors.crc8_autosar.vectors = { ... + struct('name', 'universal_check', 'input_ascii', '123456789', 'expected_hex', '0xDF'); ... + struct('name', 'cipo_2L_oneshot_zeros', ... + 'description', '2L Oneshot all-zero payload, parity cleared (53 bytes: 0x01, 0x10, 51 zeros)', ... + 'expected_hex', sprintf('0x%02X', crc8_autosar([uint8(hex2dec('01')), uint8(hex2dec('10')), zeros(1,51,'uint8')]))); ... + struct('name', 'cipo_16L_oneshot_zeros', ... + 'description', '16L Oneshot all-zero payload, parity cleared (203 bytes: 0x01, 0x30, 201 zeros)', ... + 'expected_hex', sprintf('0x%02X', crc8_autosar([uint8(hex2dec('01')), uint8(hex2dec('30')), zeros(1,201,'uint8')]))) ... +}; + +crc_vectors.crc16_ccitt_false = struct( ... + 'polynomial', '0x1021', ... + 'init', '0xFFFF', ... + 'refin', false, ... + 'refout', false, ... + 'xorout', '0x0000', ... + 'spec_section', 'g6_04-pattern-file-format.md § Frame Format / Per-frame CRC-16', ... + 'usage', 'G6 .pat per-frame trailer (little-endian); scope = FR_magic + frame_index + panel_blocks'); + +crc_vectors.crc16_ccitt_false.vectors = { ... + struct('name', 'universal_check', 'input_ascii', '123456789', 'expected_hex', '0x29B1'); ... + struct('name', 'all_zero_4bytes', ... + 'description', 'Frame header for frame_index=0 (4 bytes: FR_magic + 0x00 0x00)', ... + 'expected_hex', sprintf('0x%04X', crc16_ccitt_false([uint8('FR'), uint8(0), uint8(0)]))) ... +}; + +ref.crc_test_vectors = crc_vectors; + +%% Generate canonical pattern bytes (full file SHA-256) for cross-language byte-equivalence checks +fprintf('Generating canonical pattern checksums...\n'); +% Build small canonical patterns and pin their SHA-256s. +canonical = struct(); + +% G6_2x10 GS2, 1 frame, mod(i+j,2) checker +canonPats = zeros(40, 200, 1, 'uint8'); +for i = 1:40, for j = 1:200, canonPats(i,j,1) = mod(i+j, 2); end, end +canon_save_dir = tempname; mkdir(canon_save_dir); +g6_save_pattern(canonPats, uint8(1), [2, 10], canon_save_dir, 'canon_2x10_gs2_1f', 'Mode', 'GS2', 'Overwrite', true); +canon_path = fullfile(canon_save_dir, 'canon_2x10_gs2_1f_G6.pat'); +fid_c = fopen(canon_path, 'r'); canon_bytes = fread(fid_c, Inf, 'uint8=>uint8'); fclose(fid_c); +canonical.g6_2x10_gs2_1f_checker = struct( ... + 'description', 'G6_2x10 GS2, 1 frame, pixel(i,j)=mod(i+j,2) (1-indexed)', ... + 'file_size', length(canon_bytes), ... + 'first_24_bytes_hex', join(string(arrayfun(@(b) sprintf('%02X', b), canon_bytes(1:24), 'UniformOutput', false)), ' '), ... + 'sha256_hex', sha256_hex(canon_bytes)); + +ref.canonical_patterns = canonical; + %% Write JSON file fprintf('Writing JSON file: %s\n', output_file); -json_str = jsonencode(ref); -% Pretty print (basic formatting) -json_str = strrep(json_str, ',"', sprintf(',\n"')); -json_str = strrep(json_str, '{', sprintf('{\n')); -json_str = strrep(json_str, '}', sprintf('\n}')); +% Write tight JSON (the naive pretty-printer below corrupted strings that +% contained literal '{' or '}' — switched to PrettyPrint mode if available, +% else tight). Both are valid JSON; consumers parse them fine. +try + json_str = jsonencode(ref, 'PrettyPrint', true); +catch + json_str = jsonencode(ref); +end fid = fopen(output_file, 'w'); fprintf(fid, '%s', json_str); @@ -464,3 +528,17 @@ function generate_g6_encoding_reference(output_file) bytes = double(block(3:202)); end end + +%% Helper: SHA-256 of a uint8 vector, hex string +function h = sha256_hex(bytes) + md = java.security.MessageDigest.getInstance('SHA-256'); + md.update(uint8(bytes)); + digest = md.digest(); + % Convert signed Java bytes to unsigned + hex + h = ''; + for k = 1:length(digest) + b = digest(k); + if b < 0, b = b + 256; end + h = [h sprintf('%02x', b)]; + end +end diff --git a/g6/test_g6_crc.m b/g6/test_g6_crc.m new file mode 100644 index 0000000..823f918 --- /dev/null +++ b/g6/test_g6_crc.m @@ -0,0 +1,125 @@ +function pass_count = test_g6_crc() +% TEST_G6_CRC CRC spec-vector + corruption tests for the MATLAB G6 encoder/reader. +% +% Exits with the count of passing checks. Caller is responsible for failure +% reporting (e.g., assert in CI). + + addpath(fileparts(mfilename('fullpath'))); + clear crc8_autosar crc16_ccitt_false + + total = 0; pass_count = 0; + + fprintf('=== CRC universal checks ===\n'); + [pass_count, total] = check(pass_count, total, 'CRC-8/AUTOSAR("123456789")', ... + crc8_autosar(uint8('123456789')), uint8(hex2dec('DF'))); + [pass_count, total] = check(pass_count, total, 'CRC-16/CCITT-FALSE("123456789")', ... + crc16_ccitt_false(uint8('123456789')), uint16(hex2dec('29B1'))); + + fprintf('\n=== CRC-8 protocol vectors ===\n'); + v2L = [uint8(hex2dec('01')), uint8(hex2dec('10')), zeros(1,51,'uint8')]; + [pass_count, total] = check(pass_count, total, '2L Oneshot all-zero (53B)', ... + crc8_autosar(v2L), uint8(hex2dec('C6'))); + v16L = [uint8(hex2dec('01')), uint8(hex2dec('30')), zeros(1,201,'uint8')]; + [pass_count, total] = check(pass_count, total, '16L Oneshot all-zero (203B)', ... + crc8_autosar(v16L), uint8(hex2dec('6D'))); + + fprintf('\n=== CRC-16 protocol vectors ===\n'); + [pass_count, total] = check(pass_count, total, 'Frame-header all-zero (FR + 0x00 0x00)', ... + crc16_ccitt_false([uint8('FR'), uint8(0), uint8(0)]), ... + uint16(hex2dec('FD6B'))); + + fprintf('\n=== Cross-check against g6_encoding_reference.json ===\n'); + ref_path = fullfile(fileparts(mfilename('fullpath')), 'g6_encoding_reference.json'); + ref = jsondecode(fileread(ref_path)); + [pass_count, total] = checkBool(pass_count, total, 'reference JSON has crc_test_vectors', ... + isfield(ref, 'crc_test_vectors')); + + fprintf('\n=== Round-trip + corruption tests ===\n'); + rows = 2; cols = 10; N = 4; + Pats = zeros(rows*20, cols*20, N, 'uint8'); + for f = 1:N, for i = 1:(rows*20), for j = 1:(cols*20), Pats(i,j,f) = mod(i+j+f, 2); end, end, end + stretch = uint8(ones(N,1)); + out_dir = tempname; mkdir(out_dir); + g6_save_pattern(Pats, stretch, [rows, cols], out_dir, 'roundtrip', 'Mode', 'GS2', 'Overwrite', true); + pat_file = fullfile(out_dir, 'roundtrip_G6.pat'); + + % Tolerant clean load (should not warn) + lastwarn(''); + [~, ~] = maDisplayTools.load_pat(pat_file); + [wmsg, ~] = lastwarn(); + [pass_count, total] = checkBool(pass_count, total, 'Tolerant parse of clean file (no warning)', isempty(wmsg)); + + % Strict clean load (should not throw) + okStrict = true; sErr = ''; + try + [~, ~] = maDisplayTools.load_pat(pat_file, 'strict', true); + catch ME + okStrict = false; sErr = ME.message; + end + [pass_count, total] = checkBool(pass_count, total, 'Strict parse of clean file succeeded', okStrict); + + % Header corruption: flip a bit + fid = fopen(pat_file, 'r'); buf = fread(fid, Inf, 'uint8=>uint8'); fclose(fid); + bad = buf; bad(6) = bitxor(bad(6), uint8(1)); + bad_path = fullfile(out_dir, 'corrupt_header_G6.pat'); + fid = fopen(bad_path, 'w'); fwrite(fid, bad, 'uint8'); fclose(fid); + threw = false; + try + [~, ~] = maDisplayTools.load_pat(bad_path, 'strict', true); + catch ME + threw = ~isempty(strfind(ME.message, 'header CRC-8 mismatch')); + end + [pass_count, total] = checkBool(pass_count, total, 'Strict mode throws on header CRC-8 corruption', threw); + + % Frame body corruption + bad2 = buf; + frame_bytes_per = 4 + 20*53 + 2; + bad2(18 + 2*frame_bytes_per + 10) = bitxor(bad2(18 + 2*frame_bytes_per + 10), uint8(128)); + bad2_path = fullfile(out_dir, 'corrupt_frame_G6.pat'); + fid = fopen(bad2_path, 'w'); fwrite(fid, bad2, 'uint8'); fclose(fid); + threw2 = false; + try + [~, ~] = maDisplayTools.load_pat(bad2_path, 'strict', true); + catch ME + threw2 = ~isempty(strfind(ME.message, 'CRC-16 mismatch')); + end + [pass_count, total] = checkBool(pass_count, total, 'Strict mode throws on frame CRC-16 corruption', threw2); + + % Tolerant parses corrupt file (with warning) + lastwarn(''); + tolOK = true; + try + [~, ~] = maDisplayTools.load_pat(bad_path); + catch + tolOK = false; + end + [wmsg, ~] = lastwarn(); + [pass_count, total] = checkBool(pass_count, total, 'Tolerant parses past header corruption (with warning)', tolOK && ~isempty(wmsg)); + + fprintf('\n=== Summary ===\n%d / %d checks passed\n', pass_count, total); +end + +function [pc, tot] = check(pc, tot, name, got, expected) + tot = tot + 1; + ok = (got == expected); + if ok, pc = pc + 1; end + if isnumeric(expected) + if expected > 255 + gotStr = sprintf('0x%04X', double(got)); + expStr = sprintf('0x%04X', double(expected)); + else + gotStr = sprintf('0x%02X', double(got)); + expStr = sprintf('0x%02X', double(expected)); + end + else + gotStr = num2str(got); expStr = num2str(expected); + end + if ok, s = 'PASS'; else, s = 'FAIL'; end + fprintf(' %s %s: got %s, expected %s\n', s, name, gotStr, expStr); +end + +function [pc, tot] = checkBool(pc, tot, name, ok) + tot = tot + 1; + if ok, pc = pc + 1; s = 'PASS'; else, s = 'FAIL'; end + fprintf(' %s %s\n', s, name); +end diff --git a/maDisplayTools.m b/maDisplayTools.m index d4447fd..3d82acd 100644 --- a/maDisplayTools.m +++ b/maDisplayTools.m @@ -932,11 +932,17 @@ function validate_all_patterns(pattern_paths, expected_rows, expected_cols) %fprintf('img shape: %d x %d\n', size(img, 1), size(img, 2)); end - function [frames, meta] = load_pat(filepath) + function [frames, meta] = load_pat(filepath, varargin) % LOAD_PAT Load and decode all frames from a .pat file % Takes in the path to a pattern file and loads it and decodes all frames. % Automatically detects G4 vs G6 format based on header. % + % Name-value options: + % 'strict' (default false) — CRC-8 / CRC-16 mismatches throw an + % error instead of issuing a warning. Used by CI / regen / export + % validation. UI-side callers leave the default so they can still + % load a partially-corrupted file for inspection. + % % Returns: % - frames: 4D array (NumPatsY, NumPatsX, rows, cols) % - meta: Structure with pattern metadata: @@ -955,9 +961,9 @@ function validate_all_patterns(pattern_paths, expected_rows, expected_cols) magic = char(header_peek'); if strcmp(magic, 'G6PT') % G6 format detected - [frames, meta] = maDisplayTools.load_pat_g6(filepath); + [frames, meta] = maDisplayTools.load_pat_g6(filepath, varargin{:}); else - % G4 format (original) + % G4 format (original; CRC scheme does not apply, varargin ignored) [frames, meta] = maDisplayTools.load_pat_g4(filepath); end end @@ -1022,24 +1028,38 @@ function validate_all_patterns(pattern_paths, expected_rows, expected_cols) 'header_version', header_info.version); end - function [frames, meta] = load_pat_g6(filepath) + function [frames, meta] = load_pat_g6(filepath, varargin) % LOAD_PAT_G6 Load G6 format .pat file % Internal function for loading G6 pattern files. % - % G6 Header (17 bytes): + % Name-value options: + % 'strict' (default false) — CRC failures error out (instead of warning) + % + % G6 V1 Header (17 bytes): % Bytes 1-4: Magic "G6PT" % Byte 5: Version (1) % Byte 6: gs_val (1=GS2, 2=GS16) % Bytes 7-8: num_frames (little-endian uint16) % Byte 9: row_count % Byte 10: col_count - % Byte 11: checksum + % Byte 11: checksum (XOR of frame data — V1 only) % Bytes 12-17: panel_mask (6 bytes) % + % G6 V2 Header (18 bytes): see read_g6_header.m. Byte 18 is + % CRC-8/AUTOSAR over header bytes 1-17. + % % Frame structure: % Frame header: 4 bytes ["FR", frame_idx (little-endian uint16)] % Panel blocks: row_count * col_count panels % GS2: 53 bytes/panel, GS16: 203 bytes/panel + % V2 only: 2-byte CRC-16/CCITT-FALSE trailer (little-endian) over + % {FR_magic, frame_index, panel_blocks} of that frame. + + % Parse strict-mode option + p = inputParser; + addParameter(p, 'strict', false, @islogical); + parse(p, varargin{:}); + strict = p.Results.strict; % Read entire file fid = fopen(filepath, 'rb'); @@ -1086,6 +1106,22 @@ function validate_all_patterns(pattern_paths, expected_rows, expected_cols) header_size = 18; end + % V2 header CRC-8/AUTOSAR check (byte 18 over bytes 1-17). + % V1 keeps the legacy XOR-over-frame-data checksum at byte 11; not validated here. + if version >= 2 + expected_hdr_crc = crc8_autosar(uint8(data(1:17))); + if expected_hdr_crc ~= uint8(data(18)) + msg = sprintf('G6 header CRC-8 mismatch: file=0x%02X computed=0x%02X', ... + uint8(data(18)), expected_hdr_crc); + if strict + error('maDisplayTools:G6HeaderCRC', '%s', msg); + else + warning('maDisplayTools:G6HeaderCRC', '%s', msg); + end + end + end + has_frame_trailer = (version >= 2); + % Determine mode and panel size if gs_val_g6 == 1 mode = 'GS2'; @@ -1130,10 +1166,18 @@ function validate_all_patterns(pattern_paths, expected_rows, expected_cols) panel_data_size = num_panels_in_file * panel_bytes; for f = 1:num_frames + frame_start = offset; + % Skip frame header (4 bytes: "FR" + frame_idx) % Verify frame header if char(frame_data(offset:offset+1)') ~= "FR" - warning('Frame %d: expected FR header, found %s', f, char(frame_data(offset:offset+1)')); + msg = sprintf('Frame %d: expected FR header, found %s', ... + f, char(frame_data(offset:offset+1)')); + if strict + error('maDisplayTools:G6FrameHeader', '%s', msg); + else + warning('maDisplayTools:G6FrameHeader', '%s', msg); + end end offset = offset + frame_header_size; @@ -1157,6 +1201,22 @@ function validate_all_patterns(pattern_paths, expected_rows, expected_cols) end end + % V2: per-frame CRC-16/CCITT-FALSE trailer (little-endian). + if has_frame_trailer + file_crc = uint16(frame_data(offset)) + bitshift(uint16(frame_data(offset+1)), 8); + expected_crc = crc16_ccitt_false(uint8(frame_data(frame_start:offset-1))); + if expected_crc ~= file_crc + msg = sprintf('Frame %d: CRC-16 mismatch — file=0x%04X computed=0x%04X', ... + f, file_crc, expected_crc); + if strict + error('maDisplayTools:G6FrameCRC', '%s', msg); + else + warning('maDisplayTools:G6FrameCRC', '%s', msg); + end + end + offset = offset + 2; + end + frames(1, f, :, :) = frame_img; stretch_values(1, f) = stretch; % Last panel's stretch (all should be same) end diff --git a/patterns/web_generated/manifest.json b/patterns/web_generated/manifest.json new file mode 100644 index 0000000..0df26d1 --- /dev/null +++ b/patterns/web_generated/manifest.json @@ -0,0 +1,241 @@ +{ + "generated": "2026-05-24T04:15:02.269Z", + "generator": "webDisplayTools/tests/generate-roundtrip-patterns.js", + "description": "Deterministic reference patterns for Web → MATLAB roundtrip validation", + "patterns": [ + { + "filename": "web_G6_2x10_gs16_square_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_2x10", + "arena_id": 1, + "gs_val": 16, + "maxVal": 15, + "pixelRows": 40, + "pixelCols": 200, + "numFrames": 20, + "panelSize": 20, + "rowCount": 2, + "colCount": 10, + "patternType": "squareGrating", + "period": 20, + "stepPixels": 1, + "fileSize": 81338 + }, + { + "filename": "web_G6_2x10_gs2_square_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_2x10", + "arena_id": 1, + "gs_val": 2, + "maxVal": 1, + "pixelRows": 40, + "pixelCols": 200, + "numFrames": 20, + "panelSize": 20, + "rowCount": 2, + "colCount": 10, + "patternType": "squareGrating", + "period": 20, + "stepPixels": 1, + "fileSize": 21338 + }, + { + "filename": "web_G6_2x8of10_gs16_sine_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_2x8of10", + "arena_id": 2, + "gs_val": 16, + "maxVal": 15, + "pixelRows": 40, + "pixelCols": 160, + "numFrames": 20, + "panelSize": 20, + "rowCount": 2, + "colCount": 8, + "patternType": "sineGrating", + "period": 40, + "stepPixels": 2, + "fileSize": 65098 + }, + { + "filename": "web_G6_3x12of18_gs16_horiz_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_3x12of18", + "arena_id": 3, + "gs_val": 16, + "maxVal": 15, + "pixelRows": 60, + "pixelCols": 240, + "numFrames": 20, + "panelSize": 20, + "rowCount": 3, + "colCount": 12, + "patternType": "horizontalGrating", + "period": 20, + "stepPixels": 1, + "fileSize": 146298 + }, + { + "filename": "web_G6_2x8of10_gs2_square_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_2x8of10", + "arena_id": 2, + "gs_val": 2, + "maxVal": 1, + "pixelRows": 40, + "pixelCols": 160, + "numFrames": 20, + "panelSize": 20, + "rowCount": 2, + "colCount": 8, + "patternType": "squareGrating", + "period": 20, + "stepPixels": 1, + "fileSize": 17098 + }, + { + "filename": "web_G6_3x12of18_gs2_horiz_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_3x12of18", + "arena_id": 3, + "gs_val": 2, + "maxVal": 1, + "pixelRows": 60, + "pixelCols": 240, + "numFrames": 20, + "panelSize": 20, + "rowCount": 3, + "colCount": 12, + "patternType": "horizontalGrating", + "period": 20, + "stepPixels": 1, + "fileSize": 38298 + }, + { + "filename": "web_G6_3x16_full_gs2_square_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_3x16_full", + "arena_id": 4, + "gs_val": 2, + "maxVal": 1, + "pixelRows": 60, + "pixelCols": 320, + "numFrames": 20, + "panelSize": 20, + "rowCount": 3, + "colCount": 16, + "patternType": "squareGrating", + "period": 20, + "stepPixels": 1, + "fileSize": 51018 + }, + { + "filename": "web_G6_3x16_full_gs16_sine_grating_G6.pat", + "generation": "G6", + "arenaName": "G6_3x16_full", + "arena_id": 4, + "gs_val": 16, + "maxVal": 15, + "pixelRows": 60, + "pixelCols": 320, + "numFrames": 20, + "panelSize": 20, + "rowCount": 3, + "colCount": 16, + "patternType": "sineGrating", + "period": 40, + "stepPixels": 2, + "fileSize": 195018 + }, + { + "filename": "web_G6_2x10_gs2_blank_G6.pat", + "generation": "G6", + "arenaName": "G6_2x10", + "arena_id": 1, + "gs_val": 2, + "maxVal": 1, + "pixelRows": 40, + "pixelCols": 200, + "numFrames": 1, + "panelSize": 20, + "rowCount": 2, + "colCount": 10, + "patternType": "squareGrating", + "period": 1, + "stepPixels": 0, + "fileSize": 1084 + }, + { + "filename": "web_G4_4x12_gs16_square_grating_G4.pat", + "generation": "G4", + "arenaName": "G4_4x12", + "arena_id": 1, + "gs_val": 16, + "maxVal": 15, + "pixelRows": 64, + "pixelCols": 192, + "numFrames": 16, + "panelSize": 16, + "rowCount": 4, + "colCount": 12, + "patternType": "squareGrating", + "period": 16, + "stepPixels": 1, + "fileSize": 101639 + }, + { + "filename": "web_G4_4x12_gs2_square_grating_G4.pat", + "generation": "G4", + "arenaName": "G4_4x12", + "arena_id": 1, + "gs_val": 2, + "maxVal": 1, + "pixelRows": 64, + "pixelCols": 192, + "numFrames": 16, + "panelSize": 16, + "rowCount": 4, + "colCount": 12, + "patternType": "squareGrating", + "period": 16, + "stepPixels": 1, + "fileSize": 27911 + }, + { + "filename": "web_G41_2x12_gs16_sine_grating_G4.pat", + "generation": "G4.1", + "arenaName": "G41_2x12_cw", + "arena_id": 1, + "gs_val": 16, + "maxVal": 15, + "pixelRows": 32, + "pixelCols": 192, + "numFrames": 16, + "panelSize": 16, + "rowCount": 2, + "colCount": 12, + "patternType": "sineGrating", + "period": 32, + "stepPixels": 2, + "fileSize": 50823 + }, + { + "filename": "web_G4_3x12of18_gs16_checkerboard_G4.pat", + "generation": "G4", + "arenaName": "G4_3x12of18", + "arena_id": 2, + "gs_val": 16, + "maxVal": 15, + "pixelRows": 48, + "pixelCols": 192, + "numFrames": 16, + "panelSize": 16, + "rowCount": 3, + "colCount": 12, + "patternType": "checkerboard", + "period": 16, + "stepPixels": 1, + "fileSize": 76231 + } + ] +} \ No newline at end of file diff --git a/patterns/web_generated/web_G6_2x10_gs16_square_grating_G6.pat b/patterns/web_generated/web_G6_2x10_gs16_square_grating_G6.pat index b07b519..08bd60e 100644 Binary files a/patterns/web_generated/web_G6_2x10_gs16_square_grating_G6.pat and b/patterns/web_generated/web_G6_2x10_gs16_square_grating_G6.pat differ diff --git a/patterns/web_generated/web_G6_2x10_gs2_blank_G6.pat b/patterns/web_generated/web_G6_2x10_gs2_blank_G6.pat new file mode 100644 index 0000000..c33a779 Binary files /dev/null and b/patterns/web_generated/web_G6_2x10_gs2_blank_G6.pat differ diff --git a/patterns/web_generated/web_G6_2x10_gs2_square_grating_G6.pat b/patterns/web_generated/web_G6_2x10_gs2_square_grating_G6.pat index 3014fe1..a584ab5 100644 Binary files a/patterns/web_generated/web_G6_2x10_gs2_square_grating_G6.pat and b/patterns/web_generated/web_G6_2x10_gs2_square_grating_G6.pat differ diff --git a/patterns/web_generated/web_G6_2x8of10_gs16_sine_grating_G6.pat b/patterns/web_generated/web_G6_2x8of10_gs16_sine_grating_G6.pat index 4552032..4c500ec 100644 Binary files a/patterns/web_generated/web_G6_2x8of10_gs16_sine_grating_G6.pat and b/patterns/web_generated/web_G6_2x8of10_gs16_sine_grating_G6.pat differ diff --git a/patterns/web_generated/web_G6_2x8of10_gs2_square_grating_G6.pat b/patterns/web_generated/web_G6_2x8of10_gs2_square_grating_G6.pat new file mode 100644 index 0000000..729aa96 Binary files /dev/null and b/patterns/web_generated/web_G6_2x8of10_gs2_square_grating_G6.pat differ diff --git a/patterns/web_generated/web_G6_3x12of18_gs16_horiz_grating_G6.pat b/patterns/web_generated/web_G6_3x12of18_gs16_horiz_grating_G6.pat index 71c5eb8..7e41c55 100644 Binary files a/patterns/web_generated/web_G6_3x12of18_gs16_horiz_grating_G6.pat and b/patterns/web_generated/web_G6_3x12of18_gs16_horiz_grating_G6.pat differ diff --git a/patterns/web_generated/web_G6_3x12of18_gs2_horiz_grating_G6.pat b/patterns/web_generated/web_G6_3x12of18_gs2_horiz_grating_G6.pat new file mode 100644 index 0000000..0b91fa9 Binary files /dev/null and b/patterns/web_generated/web_G6_3x12of18_gs2_horiz_grating_G6.pat differ diff --git a/patterns/web_generated/web_G6_3x16_full_gs16_sine_grating_G6.pat b/patterns/web_generated/web_G6_3x16_full_gs16_sine_grating_G6.pat new file mode 100644 index 0000000..0118e2d Binary files /dev/null and b/patterns/web_generated/web_G6_3x16_full_gs16_sine_grating_G6.pat differ diff --git a/patterns/web_generated/web_G6_3x16_full_gs2_square_grating_G6.pat b/patterns/web_generated/web_G6_3x16_full_gs2_square_grating_G6.pat new file mode 100644 index 0000000..80c1de2 Binary files /dev/null and b/patterns/web_generated/web_G6_3x16_full_gs2_square_grating_G6.pat differ