diff --git a/code/led3number/README.md b/code/led3number/README.md new file mode 100644 index 0000000..c8408a5 --- /dev/null +++ b/code/led3number/README.md @@ -0,0 +1,68 @@ +# LED 3 位数点阵显示工程(32×16) + +32×16 LED 点阵显示 3 位数字的布局调整工程。 + +## 需求背景 + +原布局:`2空 | 7亮 | 4空 | 7亮 | 4空 | 7亮 | 1空` = 32 列 +(最左 2 列不亮、数字间 4 列不亮、最右 1 列不亮) + +新布局:`1空 | [2空 + 7亮 + 1空] ×3 | 1空` = 32 列 +- LED 最左 / 最右各留 1 列边界不亮 +- 每个数字单元固定 10 列宽:左侧 2 列不亮 + 数字 7 列 + 右侧 1 列不亮 +- 数字本体位置:列 3-9 / 13-19 / 23-29 + +## 文件说明 + +| 文件 | 说明 | +|------|------| +| `led3number.c` | **修改后的完整代码**(可直接替换工程原文件) | +| `led3number_original.c` | 修改前的原始上传版本(对照用) | +| `led3number_sim.py` | Python 模拟器:复现填充+移位逻辑,可渲染 32×16 点阵图 | +| `led3number_test.c` | 独立 C 验证程序(gcc 编译,与模拟器输出逐列对照) | +| `gen_led3number.py` | 生成脚本:从原始文件生成修改后的 `led3number.c` | +| `gen_c_test.py` | 生成脚本:从原始文件生成 `led3number_test.c` | + +## 核心改动(read_code 函数内) + +原移位拼接循环 → 新布局移位逻辑: + +```c +// 数字本体(区域内列2-8, 7列) → 全局列 3-9 / 13-19 / 23-29 +for(i=0;i<16;i++) +{ + uint8_t s2 = code12_ram[2][i]; // 数字1 高字节 + uint8_t s3 = code12_ram[3][i]; // 数字1 低字节 + uint8_t s4 = code12_ram[4][i]; // 数字2 高字节 + uint8_t s5 = code12_ram[5][i]; // 数字2 低字节 + uint8_t s6 = code12_ram[6][i]; // 数字3 高字节 + uint8_t s7 = code12_ram[7][i]; // 数字3 低字节 + + code12_ram[2][i] = (s2 >> 1) & 0x1F; // 数字1 → 列3-7 + code12_ram[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) // 数字1 → 列8-9 + | ((s4 >> 3) & 0x07); // 数字2 → 列13-15 + code12_ram[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) // 数字2 → 列16-19 + | ((s6 >> 5) & 0x01); // 数字3 → 列23 + code12_ram[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5); // 数字3 → 列24-29 +} +``` + +另:移除已废弃的 `move_reg1/move_reg2` 声明(原移位逻辑专用)。 + +## 验证方法 + +```bash +# 1. Python 模拟(可看 32×16 点阵图) +python3 led3number_sim.py + +# 2. C 独立验证(gcc 编译,输出与模拟器逐列对照) +gcc -Wall -Wextra -O2 -o led3number_test led3number_test.c && ./led3number_test +``` + +已验证数字组合:123 / 456 / 888 / 000 / 999 / 111,布局全部正确。 + +## 注意事项 + +- 协议行为未改动:显示数据流后 3 个字符(第 1 个字符被丢弃,原逻辑如此) +- 空格字符处理未改动 +- 字库结构:每字符 16 位宽,数字本体 7 列位于区域内列 2-8,MSB 显示 diff --git a/code/led3number/gen_c_test.py b/code/led3number/gen_c_test.py new file mode 100644 index 0000000..ef1f1ca --- /dev/null +++ b/code/led3number/gen_c_test.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""生成 C 验证程序: 独立复刻填充+新移位逻辑, 输出点阵供与 Python 模拟对照""" +import re + +SRC = "/root/.openclaw/media/inbound/led3number---69efe51a-567a-4354-a1b8-6c796c184183.txt" +text = open(SRC, encoding="utf-8", errors="replace").read().replace("\r\n", "\n") +m = re.search(r"Code_Number_16_12\[17\]\[32\]\s*=\s*\{(.*?)\n\};", text, re.S) +entries = re.findall(r"\{([^{}]*)\}", m.group(1)) +fonts = [] +for e in entries: + fonts.append([int(x, 16) for x in re.findall(r"0[xX][0-9A-Fa-f]+", e)]) +# 补到 17 个(未初始化的补 0) +while len(fonts) < 17: + fonts.append([0]*32) + +# 生成 C 字库 +rows = [] +for idx, f in enumerate(fonts): + vals = ", ".join(f"0x{v:02X}" for v in f) + rows.append(f" /* {idx} */ {{ {vals} }}") +font_tbl = ",\n".join(rows) + +c_code = f'''#include +#include +#include + +static const unsigned char Code_Number_16_12[17][32] = {{ +{font_tbl} +}}; + +/* 模拟: 填充 + 新移位 (照抄 led3number_new.c 逻辑) */ +static void process(const uint8_t chars[4], uint8_t out[4][16]) +{{ + uint8_t code12[8][16]; + int roll, i; + memset(code12, 0, sizeof(code12)); + for (roll = 0; roll < 4; roll++) {{ + uint8_t cc = chars[roll]; + for (i = 0; i < 16; i++) {{ + if (cc == 0x20) {{ + code12[roll*2][i] = Code_Number_16_12[10][i*2]; + code12[roll*2+1][i] = Code_Number_16_12[10][i*2+1]; + }} else {{ + code12[roll*2][i] = Code_Number_16_12[cc-0x30][i*2]; + code12[roll*2+1][i] = (uint8_t)(Code_Number_16_12[cc-0x30][i*2+1] << 6); + }} + }} + }} + for (i = 0; i < 16; i++) {{ + uint8_t s2 = code12[2][i]; + uint8_t s3 = code12[3][i]; + uint8_t s4 = code12[4][i]; + uint8_t s5 = code12[5][i]; + uint8_t s6 = code12[6][i]; + uint8_t s7 = code12[7][i]; + + code12[2][i] = (uint8_t)((s2 >> 1) & 0x1F); + code12[3][i] = (uint8_t)(((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) | ((s4 >> 3) & 0x07)); + code12[4][i] = (uint8_t)(((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) | ((s6 >> 5) & 0x01)); + code12[5][i] = (uint8_t)(((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5)); + }} + memcpy(out, &code12[2][0], 64); +}} + +static void render(const char *name, const uint8_t out[4][16]) +{{ + int r, c; + printf("=== %s ===\\n", name); + printf("col: "); + for (c = 0; c < 32; c++) printf("%d", c % 10); + printf("\\n"); + for (r = 0; r < 16; r++) {{ + printf("%2d ", r); + for (c = 0; c < 32; c++) {{ + uint8_t byte = out[c/8][r]; + int bit = (byte >> (7 - (c % 8))) & 1; + putchar(bit ? '#' : '.'); + }} + printf("\\n"); + }} +}} + +int main(void) +{{ + uint8_t out[4][16]; + /* 字符: 第1个被丢弃(协议), 后3个显示; 0x20=空格 */ + process((uint8_t[]){{'1','2','3','0'}}, out); render("NEW 123+0", out); + process((uint8_t[]){{' ','4','5','6'}}, out); render("NEW 456+7", out); + process((uint8_t[]){{'8','8','8','8'}}, out); render("NEW 888+8", out); + return 0; +}} +''' +open("/root/.openclaw/workspace/led3number_test.c", "w").write(c_code) +print("已生成 led3number_test.c") diff --git a/code/led3number/gen_led3number.py b/code/led3number/gen_led3number.py new file mode 100644 index 0000000..45f8d4a --- /dev/null +++ b/code/led3number/gen_led3number.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""生成修改后的 led3number.c: 替换移位拼接段为新布局逻辑""" +import re + +SRC = "/root/.openclaw/media/inbound/led3number---69efe51a-567a-4354-a1b8-6c796c184183.txt" +OUT = "/root/.openclaw/workspace/led3number_new.c" +text = open(SRC, encoding="utf-8", errors="replace").read().replace("\r\n", "\n") + +# 定位原移位段: 第二个 for(i=0;i<16;i++) 循环 (move_reg1 = code12_ram[5][i] 开头) +pat = re.compile(r"for\(i=0;i<16;i\+\+\)\s*\{\s*move_reg1 = code12_ram\[5\]\[i\];") +m = pat.search(text) +assert m, "移位段起始未找到" +start = m.start() +end = text.find("memcpy(&CodeRAM[32- Screen.Uart.Receive_ID_Number*4][0]") +assert end != -1, "memcpy 未找到" +# TODO 注释行在 memcpy 之前 +todo_end = text.rfind("// TODO", start, end) +assert todo_end != -1 +# 找到 TODO 行结尾 +nl = text.find("\n", todo_end) +seg_end = nl + 1 + +new_seg = """\t// ========== 新布局: 32列 = 1空 | [2空 + 7数字 + 1空]x3 | 1空 ==========\n\ +\t// 数字本体(区域内列2-8, 7列) → 全局列 3-9 / 13-19 / 23-29\n\ +\t// 左边界1列 + 每数字左2右1空 + 右边界1列, 数字间空隙3列\n\ +\tfor(i=0;i<16;i++)\n\ +\t{\n\ +\t\tuint8_t s2 = code12_ram[2][i]; // 数字1 高字节(区域内列0-7)\n\ +\t\tuint8_t s3 = code12_ram[3][i]; // 数字1 低字节(区域内列8-15)\n\ +\t\tuint8_t s4 = code12_ram[4][i]; // 数字2 高字节\n\ +\t\tuint8_t s5 = code12_ram[5][i]; // 数字2 低字节\n\ +\t\tuint8_t s6 = code12_ram[6][i]; // 数字3 高字节\n\ +\t\tuint8_t s7 = code12_ram[7][i]; // 数字3 低字节\n\ +\n\ +\t\tcode12_ram[2][i] = (s2 >> 1) & 0x1F; // 数字1 → 列3-7\n\ +\t\tcode12_ram[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) // 数字1 → 列8-9\n\ +\t\t | ((s4 >> 3) & 0x07); // 数字2 → 列13-15\n\ +\t\tcode12_ram[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) // 数字2 → 列16-19\n\ +\t\t | ((s6 >> 5) & 0x01); // 数字3 → 列23\n\ +\t\tcode12_ram[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5); // 数字3 → 列24-29\n\ +\t}\n\ +\n\ +""" + +new_text = text[:start] + new_seg + text[seg_end:] +open(OUT, "w", encoding="utf-8").write(new_text) +print("已生成:", OUT) +print("原始文件长度:", len(text), "→ 新文件长度:", len(new_text)) diff --git a/code/led3number/led3number.c b/code/led3number/led3number.c new file mode 100644 index 0000000..5e02d9c --- /dev/null +++ b/code/led3number/led3number.c @@ -0,0 +1,275 @@ + + +const unsigned char Code_Number_16_12[17][32]={ //16点阵高,12点阵宽 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //0 +{0x00, 0x00, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x00, 0x00}, //1 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //2 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //3 +{0x00, 0x00, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x00, 0x00}, //4 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //5 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //6 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x00, 0x00}, //7 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //8 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //9 +{0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00 +}, //空格 +}; + + + +void read_code(void) +{ + static uint16_t roll; + uint8_t i,j; + uint8_t cc,cd; + static uint16_t ROW_8BIT = 0; + static uint8_t code12_ram[48][16]; + // 注: 原 move_reg1/move_reg2 已随旧移位逻辑移除 + + ROW_8BIT = 0; + if(Screen.Uart.First_Receive_Data) + { + if(Screen.Set.High==16 || Screen.DisplayMode.Work_Mode==2) + { + if(Screen.Para.Data_LEN%(Screen.Set.Width/8)) + { + Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/8))+1; // + } + else + Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/8); + } + else + { + if((Screen.Para.Data_LEN)%(Screen.Set.Width/16)) + { + Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/16))+1; // + } + else + Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/16); + } + } + else + { + Screen.Para.Num = 1; + } + if(Screen.Para.Num == 1) + { + Screen.Para.Single_Line_Direct_Display_Flag = 0; + } + + + if(!Screen.Uart.First_Receive_Data) + { + for(roll=0;roll> 1) & 0x1F; // 数字1 → 列3-7 + code12_ram[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) // 数字1 → 列8-9 + | ((s4 >> 3) & 0x07); // 数字2 → 列13-15 + code12_ram[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) // 数字2 → 列16-19 + | ((s6 >> 5) & 0x01); // 数字3 → 列23 + code12_ram[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5); // 数字3 → 列24-29 + } + + + memcpy(&CodeRAM[32- Screen.Uart.Receive_ID_Number*4][0],&code12_ram[2][0],64); + } + memcpy(CodeRAM_Display,CodeRAM,sizeof(CodeRAM)); + memcpy(CodeRAM2_Display,CodeRAM2,sizeof(CodeRAM2)); +} + + + diff --git a/code/led3number/led3number_original.c b/code/led3number/led3number_original.c new file mode 100644 index 0000000..27b28c3 --- /dev/null +++ b/code/led3number/led3number_original.c @@ -0,0 +1,276 @@ + + +const unsigned char Code_Number_16_12[17][32]={ //16点阵高,12点阵宽 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //0 +{0x00, 0x00, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x00, 0x00}, //1 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //2 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //3 +{0x00, 0x00, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x00, 0x00}, //4 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //5 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x30, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //6 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x00, 0x00}, //7 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //8 +{0x00, 0x00, +0x3F, 0x02, +0x3F, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x31, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x01, 0x02, +0x3F, 0x02, +0x3F, 0x02, +0x00, 0x00}, //9 +{0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00 +}, //空格 +}; + + + +void read_code(void) +{ + static uint16_t roll; + uint8_t i,j; + uint8_t cc,cd; + static uint16_t ROW_8BIT = 0; + static uint8_t code12_ram[48][16]; + uint8_t move_reg1 = 0; + uint8_t move_reg2 = 0; + + ROW_8BIT = 0; + if(Screen.Uart.First_Receive_Data) + { + if(Screen.Set.High==16 || Screen.DisplayMode.Work_Mode==2) + { + if(Screen.Para.Data_LEN%(Screen.Set.Width/8)) + { + Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/8))+1; // + } + else + Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/8); + } + else + { + if((Screen.Para.Data_LEN)%(Screen.Set.Width/16)) + { + Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/16))+1; // + } + else + Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/16); + } + } + else + { + Screen.Para.Num = 1; + } + if(Screen.Para.Num == 1) + { + Screen.Para.Single_Line_Direct_Display_Flag = 0; + } + + + if(!Screen.Uart.First_Receive_Data) + { + for(roll=0;roll>7); + code12_ram[5][i]=code12_ram[5][i]<<1; //第二个数左移一位 + + move_reg1 = code12_ram[4][i]; + code12_ram[3][i]=code12_ram[3][i] | (move_reg1>>4); + + move_reg1 = code12_ram[4][i]; + move_reg2 = code12_ram[5][i]; + code12_ram[4][i]= move_reg1<<4 | move_reg2>>4; + + move_reg1 = code12_ram[6][i]; + code12_ram[4][i] |= move_reg1>>6; + move_reg1 = code12_ram[6][i]; + code12_ram[5][i] = (move_reg1<<2) | (code12_ram[7][i]>>6); + } + + // TODO: 新的移位要求 LED最左边和最右边的一列不亮;每个数字 左边有两列不亮,右侧一列不亮,也就是说 每个数字单元有10个点阵宽,左侧有两列不亮,右侧有一列不亮。 + + memcpy(&CodeRAM[32- Screen.Uart.Receive_ID_Number*4][0],&code12_ram[2][0],64); + } + memcpy(CodeRAM_Display,CodeRAM,sizeof(CodeRAM)); + memcpy(CodeRAM2_Display,CodeRAM2,sizeof(CodeRAM2)); +} + + + diff --git a/code/led3number/led3number_sim.py b/code/led3number/led3number_sim.py new file mode 100644 index 0000000..b382903 --- /dev/null +++ b/code/led3number/led3number_sim.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""led3number.c 移位逻辑模拟器 — 用于精确理解/验证 32x16 点阵数字布局""" +import re, sys + +SRC = "/root/.openclaw/media/inbound/led3number---69efe51a-567a-4354-a1b8-6c796c184183.txt" +text = open(SRC, encoding="utf-8", errors="replace").read() + +# ---------- 1. 解析字库 Code_Number_16_12[17][32] ---------- +m = re.search(r"Code_Number_16_12\[17\]\[32\]\s*=\s*\{(.*?)\n\};", text, re.S) +assert m, "字库未找到" +body = m.group(1) +# 按 { ... }, //n 拆成 17 个字符 +entries = re.findall(r"\{([^{}]*)\}", body) +assert len(entries) >= 11, f"字库条目数 {len(entries)} < 11" +fonts = [] +for e in entries: + vals = [int(x, 16) for x in re.findall(r"0[xX][0-9A-Fa-f]+", e)] + assert len(vals) == 32, f"条目字节数 {len(vals)} != 32" + fonts.append(vals) +print(f"[字库] 解析 OK: 17 个字符 x 32 字节") + +# ---------- 2. 模拟填充 + 移位(完全照抄 C 逻辑, uint8 语义) ---------- +def simulate(chars_idx, new_layout=False): + """chars_idx: 4 个字符索引, 0-9=数字, 16=空格(Code_Number_16_12[10]=空格索引10, 但调用处用 0x20 判断)""" + code12 = [[0]*16 for _ in range(8)] # 8 槽 x 16 行, uint8 + for roll in range(4): + cc = chars_idx[roll] + for i in range(16): + if cc == 0x20 or cc == 16: # 空格 + code12[roll*2][i] = fonts[10][i*2] + code12[roll*2+1][i] = fonts[10][i*2+1] + else: + code12[roll*2][i] = fonts[cc][i*2] + code12[roll*2+1][i] = (fonts[cc][i*2+1] << 6) & 0xFF + if not new_layout: + # ---- 原移位拼接(TODO 所在处, 原样模拟) ---- + for i in range(16): + m1 = code12[5][i] + code12[4][i] = ((code12[4][i] << 1) | (m1 >> 7)) & 0xFF + code12[5][i] = (code12[5][i] << 1) & 0xFF + + m1 = code12[4][i] + code12[3][i] = (code12[3][i] | (m1 >> 4)) & 0xFF + + m1 = code12[4][i] + m2 = code12[5][i] + code12[4][i] = ((m1 << 4) | (m2 >> 4)) & 0xFF + + m1 = code12[6][i] + code12[4][i] = (code12[4][i] | (m1 >> 6)) & 0xFF + m1 = code12[6][i] + code12[5][i] = ((m1 << 2) | (code12[7][i] >> 6)) & 0xFF + else: + # ---- 新布局: 1空 | [2空 7数字 1空]x3 | 1空 = 32列 ---- + # 数字1(槽2,3) 区域内列2-8 → 全局列3-9 + # 数字2(槽4,5) 区域内列2-8 → 全局列13-19 + # 数字3(槽6,7) 区域内列2-8 → 全局列23-29 + for i in range(16): + s2 = code12[2][i]; s3 = code12[3][i] + s4 = code12[4][i]; s5 = code12[5][i] + s6 = code12[6][i]; s7 = code12[7][i] + code12[2][i] = (s2 >> 1) & 0x1F # 数字1: 列3-7 + code12[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) \ + | ((s4 >> 3) & 0x07) # 数字1列8-9 | 数字2列13-15 + code12[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) \ + | ((s6 >> 5) & 0x01) # 数字2列16-19 | 数字3列23 + code12[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5) # 数字3列24-29 + # memcpy 输出: 槽 2,3,4,5 → 每行 4 字节 = 32 列 + out = [code12[s][i] for i in range(16) for s in (2,3,4,5)] + return out + +def render(out, title): + print(f"\n=== {title} ===") + print("col: " + "".join(str(c % 10) for c in range(32))) + for row in range(16): + line = "" + for c in range(32): + byte = out[row*4 + c//8] + bit = (byte >> (7 - (c % 8))) & 1 # MSB first: bit7=列左 + line += "#" if bit else "." + print(f"{row:2d} {line}") + # 每列统计 + colsum = [0]*32 + for row in range(16): + for c in range(32): + byte = out[row*4 + c//8] + colsum[c] += (byte >> (7 - (c % 8))) & 1 + print("col#: " + "".join(str(colsum[c]) for c in range(32))) + # 亮列区间 + lit = [c for c in range(32) if colsum[c] > 0] + print("亮列:", lit) + +# ---------- 3. 测试几种字符组合 ---------- +import itertools +# 原布局 +for name, chars in [("OLD 123+0", [1,2,3,0]), ("OLD 456+7", [4,5,6,7]), ("OLD 888+8", [8,8,8,8])]: + render(simulate(chars), name) +# 新布局 +for name, chars in [("NEW 123+0", [1,2,3,0]), ("NEW 456+7", [4,5,6,7]), ("NEW 888+8", [8,8,8,8]), + ("NEW 000+0", [0,0,0,0]), ("NEW 999+9", [9,9,9,9]), ("NEW 111+1", [1,1,1,1])]: + render(simulate(chars, new_layout=True), name) diff --git a/code/led3number/led3number_test.c b/code/led3number/led3number_test.c new file mode 100644 index 0000000..f2ba285 --- /dev/null +++ b/code/led3number/led3number_test.c @@ -0,0 +1,85 @@ +#include +#include +#include + +static const unsigned char Code_Number_16_12[17][32] = { + /* 0 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 }, + /* 1 */ { 0x00, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00 }, + /* 2 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 }, + /* 3 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 }, + /* 4 */ { 0x00, 0x00, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00 }, + /* 5 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 }, + /* 6 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 }, + /* 7 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00 }, + /* 8 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 }, + /* 9 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 }, + /* 10 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 11 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 12 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 13 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 14 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 15 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 16 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +/* 模拟: 填充 + 新移位 (照抄 led3number_new.c 逻辑) */ +static void process(const uint8_t chars[4], uint8_t out[4][16]) +{ + uint8_t code12[8][16]; + int roll, i; + memset(code12, 0, sizeof(code12)); + for (roll = 0; roll < 4; roll++) { + uint8_t cc = chars[roll]; + for (i = 0; i < 16; i++) { + if (cc == 0x20) { + code12[roll*2][i] = Code_Number_16_12[10][i*2]; + code12[roll*2+1][i] = Code_Number_16_12[10][i*2+1]; + } else { + code12[roll*2][i] = Code_Number_16_12[cc-0x30][i*2]; + code12[roll*2+1][i] = (uint8_t)(Code_Number_16_12[cc-0x30][i*2+1] << 6); + } + } + } + for (i = 0; i < 16; i++) { + uint8_t s2 = code12[2][i]; + uint8_t s3 = code12[3][i]; + uint8_t s4 = code12[4][i]; + uint8_t s5 = code12[5][i]; + uint8_t s6 = code12[6][i]; + uint8_t s7 = code12[7][i]; + + code12[2][i] = (uint8_t)((s2 >> 1) & 0x1F); + code12[3][i] = (uint8_t)(((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) | ((s4 >> 3) & 0x07)); + code12[4][i] = (uint8_t)(((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) | ((s6 >> 5) & 0x01)); + code12[5][i] = (uint8_t)(((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5)); + } + memcpy(out, &code12[2][0], 64); +} + +static void render(const char *name, const uint8_t out[4][16]) +{ + int r, c; + printf("=== %s ===\n", name); + printf("col: "); + for (c = 0; c < 32; c++) printf("%d", c % 10); + printf("\n"); + for (r = 0; r < 16; r++) { + printf("%2d ", r); + for (c = 0; c < 32; c++) { + uint8_t byte = out[c/8][r]; + int bit = (byte >> (7 - (c % 8))) & 1; + putchar(bit ? '#' : '.'); + } + printf("\n"); + } +} + +int main(void) +{ + uint8_t out[4][16]; + /* 字符: 第1个被丢弃(协议), 后3个显示; 0x20=空格 */ + process((uint8_t[]){'1','2','3','0'}, out); render("NEW 123+0", out); + process((uint8_t[]){' ','4','5','6'}, out); render("NEW 456+7", out); + process((uint8_t[]){'8','8','8','8'}, out); render("NEW 888+8", out); + return 0; +} diff --git a/memory/2026-08-19.md b/memory/2026-08-19.md new file mode 100644 index 0000000..55bb452 --- /dev/null +++ b/memory/2026-08-19.md @@ -0,0 +1,9 @@ + +## 2026-08-19 15:35 — Gitea 禁用自助注册 +- 需求:禁用 git.szdego.cn 自助注册,只允许管理员后台分配账户 +- 架构发现:Gitea 跑在阿里云 8.155.27.249 的 Docker 容器(镜像 docker.gitea.com/gitea:latest,容器名 gitea),挂载 宿主机 /root/gitea/gitea → 容器 /data +- 运行配置:/root/gitea/gitea/gitea/conf/app.ini(容器内 /data/gitea/conf/app.ini) +- 修改项:[service] DISABLE_REGISTRATION=true、SHOW_REGISTRATION_BUTTON=false、ENABLE_OPENID_SIGNUP=false +- 备份:/root/gitea/gitea/gitea/conf/app.ini.bak-20260819 +- 重启:docker restart gitea;验证 /user/sign_up 显示 "Registration is disabled." +- SSH:root@8.155.27.249(本机已装 sshpass,公钥 openclaw-xde@dg-RH1288-V3 已生成但尚未加入远程 authorized_keys)