a6cdebde62
- D-6 目录规范化:docs 根目录散落文档归入 UI设计/子系统设计/架构设计/审查记录/ 环境与部署/网络 等子目录,去掉目录名空格,重命名 嵌入式C语言代码规范_V1.0.md - D-7 三档一致性门禁:新增 scripts/check_doc_links.py(链接存在性)、 scripts/gen_task_table.py(FreeRTOS 任务表数值)、scripts/check_mem_numbers.py (内存/Flash 体积),均支持 --check/--write/--diff,pre-commit 钩子同步注册 - D-5 文档索引:新建 docs/README.md,新建 docs/文档规范.md 约束目录命名与链接写法 - D-1 芯片手册瘦身:删除 1069 张无引用孤儿图片(77.06 MB), docs/芯片手册 120 MB → 41 MB,已引用图片零断链 - 同步 C 源码注释中的文档路径引用(D-6 重组后),构建 0 错误 0 警告
139 lines
5.3 KiB
Python
139 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""生成 docs/images/物理分区布局.svg —— GD5F2GQ5UE 全片分区布局图(纯标准库)。
|
||
|
||
由 gen_frame_svg.py 复制而来(build() 与数据解耦,通用):协议帧图按"字节"计量
|
||
(字段宽 ∝ 字节数),本图按"MB"计量(分区宽 ∝ MB 数),其余约定一致——
|
||
分段矩形 + 偏移标尺 + 逐段标注,连续布局无假箭头。
|
||
|
||
用法(仓库根目录,任意 python3):
|
||
python tools/arch_diagram/gen_partition_svg.py
|
||
输出:
|
||
docs/images/物理分区布局.svg
|
||
改分区时:编辑本文件顶部的 FIELDS / TITLE / SUB / FOOT 后重跑。
|
||
"""
|
||
import html
|
||
import os
|
||
|
||
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
OUT = os.path.join(ROOT, "docs", "images", "物理分区布局.svg")
|
||
|
||
# ----------------------------- 画布与尺寸参数 -----------------------------
|
||
PAD = 40 # 左右留白
|
||
PX_PER_MB = 4 # 每 MB 像素宽(分区宽 ∝ MB 数)
|
||
BAR_Y = 116 # 分区盒顶 y(标题 / 副标题 / 偏移标尺在其上方)
|
||
BAR_H = 74 # 分区盒高
|
||
NAME_DY = 30 # 分区名在盒内的 y 偏移
|
||
SIZE_DY = 54 # 尺寸标注在盒内的 y 偏移
|
||
RULER_DY = 20 # 偏移标尺线在盒顶上方
|
||
|
||
TITLE_FONT = 20
|
||
SUB_FONT = 13
|
||
NAME_FONT = 15
|
||
SIZE_FONT = 12
|
||
RULER_FONT = 12
|
||
FOOT_FONT = 12
|
||
|
||
FONT = "Microsoft YaHei, Segoe UI, PingFang SC, sans-serif"
|
||
|
||
# ----------------------------- 分区数据(改这里) -----------------------------
|
||
# name=分区名 mb=MB 数(None=变长段,按 DATA_UNITS 画) label=尺寸标注 color/bg=配色
|
||
DATA_UNITS = 5 # 变长段的"代表宽度"(按 N MB 画,仅示意)
|
||
FIELDS = [
|
||
dict(name="ftl_fatfs", mb=256, label="256 MB · Block 0~2047", color="#2563eb", bg="#eff6ff"),
|
||
]
|
||
|
||
TITLE = "GD5F2GQ5UE 物理分区布局(256MB)"
|
||
SUB = "单分区:全片划给 FTL(无静态分区)· 块 = 128KB(64 页 × 2KB)· 共 2048 块"
|
||
FOOT = ("ftl_fatfs:dhara FTL + FatFS 占用全部 2048 块(偏移 0 ~ 256MB)· "
|
||
"详见 docs/架构设计/STM32F4-Base存储架构说明.md §1")
|
||
|
||
|
||
# ----------------------------- 工具函数 -----------------------------
|
||
def esc(s):
|
||
return html.escape(s, quote=True)
|
||
|
||
|
||
def field_w(f):
|
||
return (f["mb"] if f["mb"] is not None else DATA_UNITS) * PX_PER_MB
|
||
|
||
|
||
def offset_labels(fields):
|
||
"""按分区 MB 数累计边界偏移;偏移标注统一带 MB 单位。"""
|
||
labs, off = ["0"], 0
|
||
for f in fields:
|
||
off += f["mb"] if f["mb"] is not None else DATA_UNITS
|
||
labs.append("%d MB" % off)
|
||
return labs
|
||
|
||
|
||
# ----------------------------- 生成 -----------------------------
|
||
def build():
|
||
out = []
|
||
add = out.append
|
||
|
||
frame_w = sum(field_w(f) for f in FIELDS)
|
||
W = frame_w + 2 * PAD
|
||
|
||
# 预计算各分区 x / 宽
|
||
segs, x = [], PAD
|
||
for f in FIELDS:
|
||
w = field_w(f)
|
||
segs.append([f, x, w])
|
||
x += w
|
||
labels = offset_labels(FIELDS)
|
||
|
||
total_h = BAR_Y + BAR_H + 56
|
||
add('<rect x="0" y="0" width="%d" height="%d" fill="#ffffff"/>' % (W, total_h))
|
||
|
||
# 标题 + 副标题
|
||
add('<text x="%d" y="40" font-size="%d" font-weight="700" fill="#0f172a">%s</text>'
|
||
% (PAD, TITLE_FONT, esc(TITLE)))
|
||
add('<text x="%d" y="64" font-size="%d" fill="#64748b">%s</text>'
|
||
% (PAD, SUB_FONT, esc(SUB)))
|
||
|
||
# 偏移标尺(每个分区边界一个刻度 + 偏移标注)
|
||
ruler_y = BAR_Y - RULER_DY
|
||
add('<line x1="%d" y1="%d" x2="%d" y2="%d" stroke="#cbd5e1" stroke-width="1"/>'
|
||
% (PAD, ruler_y, PAD + frame_w, ruler_y))
|
||
bounds = [PAD] + [s[1] + s[2] for s in segs]
|
||
for i, bx in enumerate(bounds):
|
||
add('<line x1="%d" y1="%d" x2="%d" y2="%d" stroke="#94a3b8" stroke-width="1.5"/>'
|
||
% (bx, ruler_y - 4, bx, ruler_y + 4))
|
||
lab = labels[i] if i < len(labels) else "?"
|
||
add('<text x="%d" y="%d" font-size="%d" fill="#94a3b8" text-anchor="middle">%s</text>'
|
||
% (bx, ruler_y - 8, RULER_FONT, esc(lab)))
|
||
|
||
# 分区盒(名在上、尺寸在下)
|
||
for (f, bx, bw) in segs:
|
||
add('<rect x="%d" y="%d" width="%d" height="%d" fill="%s" stroke="%s" stroke-width="1.5"/>'
|
||
% (bx, BAR_Y, bw, BAR_H, f["bg"], f["color"]))
|
||
cx = bx + bw / 2.0
|
||
add('<text x="%.1f" y="%d" font-size="%d" font-weight="700" fill="#0f172a" '
|
||
'text-anchor="middle">%s</text>'
|
||
% (cx, BAR_Y + NAME_DY, NAME_FONT, esc(f["name"])))
|
||
add('<text x="%.1f" y="%d" font-size="%d" fill="%s" text-anchor="middle">%s</text>'
|
||
% (cx, BAR_Y + SIZE_DY, SIZE_FONT, f["color"], esc(f["label"])))
|
||
|
||
# 脚注
|
||
add('<text x="%d" y="%d" font-size="%d" fill="#94a3b8">%s</text>'
|
||
% (PAD, total_h - 16, FOOT_FONT, esc(FOOT)))
|
||
|
||
svg = ('<svg xmlns="http://www.w3.org/2000/svg" width="%d" height="%d" '
|
||
'viewBox="0 0 %d %d" font-family="%s">\n%s\n</svg>\n'
|
||
% (W, total_h, W, total_h, FONT, "\n".join(out)))
|
||
return svg, W, total_h
|
||
|
||
|
||
def main():
|
||
svg, W, h = build()
|
||
with open(OUT, "w", encoding="utf-8", newline="\n") as f:
|
||
f.write(svg)
|
||
import xml.etree.ElementTree as ET
|
||
ET.fromstring(svg)
|
||
print("OK %d bytes, canvas %dx%d -> %s" % (len(svg.encode("utf-8")), W, h, OUT))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|