2026-07-18 00:51:43 +08:00
|
|
|
{
|
|
|
|
|
"cells": [
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
2026-07-19 20:56:15 +08:00
|
|
|
"# RBPU16 Data Sheet",
|
|
|
|
|
"\n\nRun All -> self-contained HTML."
|
2026-07-18 00:51:43 +08:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
2026-07-19 20:56:15 +08:00
|
|
|
"import sys,os,re,base64,mimetypes,subprocess\n",
|
|
|
|
|
"from datetime import datetime as dt; from pathlib import Path; from html import escape as eh\n",
|
|
|
|
|
"try: import markdown\n",
|
|
|
|
|
"except: subprocess.check_call([sys.executable,'-m','pip','install','markdown','-q']); import markdown\n",
|
|
|
|
|
"B=Path(os.getcwd()).resolve(); os.chdir(str(B)); sys.path.insert(0,str(B))\n",
|
|
|
|
|
"from doc_builder import import_handler, image_extension, codeblock_extension\n",
|
|
|
|
|
"print(f' {B.name}')\n"
|
2026-07-18 00:51:43 +08:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## Build"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
2026-07-19 20:56:15 +08:00
|
|
|
"def pc(md_text):\n",
|
|
|
|
|
" md_text = import_handler.process_imports(md_text,B,pc)\n",
|
|
|
|
|
" md_text = codeblock_extension.render_code_blocks(md_text,B)\n",
|
|
|
|
|
" return markdown.markdown(md_text,extensions=[\n",
|
|
|
|
|
" 'tables','fenced_code','codehilite','nl2br','sane_lists',\n",
|
|
|
|
|
" image_extension.ImageRowProcessor(),\n",
|
|
|
|
|
" ],extension_configs={'codehilite':{'css_class':'highlight','guess_lang':False}})\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"cn=[]\n",
|
|
|
|
|
"with open(B/'project.yaml',encoding='utf-8') as f:\n",
|
|
|
|
|
" ic=False\n",
|
2026-07-18 00:51:43 +08:00
|
|
|
" for line in f:\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
" line=line.rstrip()\n",
|
|
|
|
|
" if line.startswith('chapters:'): ic=True; continue\n",
|
|
|
|
|
" if ic:\n",
|
|
|
|
|
" mx=re.match(r'^\\s*-\\s+(.+)$',line)\n",
|
|
|
|
|
" if mx: cn.append(mx.group(1).strip())\n",
|
|
|
|
|
" elif line and not line.startswith(' '): ic=False\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"print('Processing...')\n",
|
|
|
|
|
"chapters=[]\n",
|
|
|
|
|
"for i,n in enumerate(cn):\n",
|
|
|
|
|
" fp=B/'chapters'/n\n",
|
2026-07-18 00:51:43 +08:00
|
|
|
" if not fp.exists(): continue\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
" print(f' [{i+1}] {n}')\n",
|
|
|
|
|
" c=pc(fp.read_text(encoding='utf-8'))\n",
|
|
|
|
|
" mx=re.search(r'<h1[^>]*>(.*?)</h1>',c)\n",
|
|
|
|
|
" chapters.append(dict(id=f'ch{i+1}',number=str(i+1),title=mx.group(1) if mx else fp.stem,content=c))\n",
|
|
|
|
|
"apd=B/'chapters'/'appendix'\n",
|
2026-07-18 00:51:43 +08:00
|
|
|
"if apd.exists():\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
" for j,fp in enumerate(sorted(apd.glob('*.md'),key=lambda p:p.name)):\n",
|
|
|
|
|
" lb=chr(65+j)\n",
|
|
|
|
|
" c=pc(fp.read_text(encoding='utf-8'))\n",
|
|
|
|
|
" mx=re.search(r'<h1[^>]*>(.*?)</h1>',c)\n",
|
|
|
|
|
" chapters.append(dict(id=f'app{lb}',number=f'Appendix {lb}',title=mx.group(1) if mx else fp.stem,content=c))\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"CSS=(B/'doc_builder'/'themes'/'datasheet.css').read_text(encoding='utf-8')\n",
|
2026-07-19 21:40:24 +08:00
|
|
|
"\n",
|
|
|
|
|
"def _parse_yaml(path):\n",
|
|
|
|
|
" meta={}; features=[]; in_features=False\n",
|
|
|
|
|
" with open(path,encoding='utf-8') as f:\n",
|
|
|
|
|
" for line in f:\n",
|
|
|
|
|
" s=line.strip(); k=None\n",
|
|
|
|
|
" if s.startswith('features:'):\n",
|
|
|
|
|
" in_features=True; continue\n",
|
|
|
|
|
" if in_features:\n",
|
|
|
|
|
" if s.startswith('- '):\n",
|
|
|
|
|
" features.append(s[2:].strip()); continue\n",
|
|
|
|
|
" elif s and not line.startswith(' '):\n",
|
|
|
|
|
" in_features=False\n",
|
|
|
|
|
" if not in_features and ':' in s:\n",
|
|
|
|
|
" k,v=s.split(':',1)\n",
|
|
|
|
|
" meta[k.strip()]=v.strip()\n",
|
|
|
|
|
" meta['features']=features\n",
|
|
|
|
|
" return meta\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"meta=_parse_yaml(B/'project.yaml')\n",
|
|
|
|
|
"TITLE=meta.get('title','RBPU16')\n",
|
|
|
|
|
"SUBTITLE=meta.get('subtitle','数据手册')\n",
|
|
|
|
|
"AUTHOR=meta.get('author','郭成')\n",
|
|
|
|
|
"AU=AUTHOR\n",
|
|
|
|
|
"DATE=dt.now().strftime('%Y-%m-%d')\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"def _title_html(t):\n",
|
|
|
|
|
" parts=t.split(' ',1)\n",
|
|
|
|
|
" if len(parts)>1:\n",
|
|
|
|
|
" return f'<span class=\"model\">{eh(parts[0])}</span> <span class=\"zh-name\">{eh(parts[1])}</span>'\n",
|
|
|
|
|
" return eh(t)\n",
|
|
|
|
|
"_title=_title_html(TITLE)\n",
|
|
|
|
|
"\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
"COVER=''.join([\n",
|
2026-07-18 00:51:43 +08:00
|
|
|
" '<div class=\"cover-page\">',\n",
|
2026-07-19 21:40:24 +08:00
|
|
|
" '<div class=\"cover-top\"><div class=\"product-family\">READOUT BASEBAND PROCESSOR</div></div>',\n",
|
|
|
|
|
" '<div class=\"cover-body\">',\n",
|
|
|
|
|
" f'<h1>{_title}</h1>',\n",
|
|
|
|
|
" f'<div class=\"subtitle\">{eh(SUBTITLE)}</div>',\n",
|
|
|
|
|
" '</div>',\n",
|
|
|
|
|
" f'<div class=\"cover-bottom\"><span class=\"rev\">Rev 1.0 · {DATE}</span><span class=\"author\">{eh(AUTHOR)}</span></div>',\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
" '</div>',\n",
|
2026-07-18 00:51:43 +08:00
|
|
|
"])\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
"ch_html=chr(10).join(f'<div class=\"chapter\" id=\"{c[\"id\"]}\">{c[\"content\"]}</div>' for c in chapters)\n",
|
|
|
|
|
"FULL=chr(10).join([\n",
|
|
|
|
|
" '<!DOCTYPE html>','<html lang=\"zh-CN\">','<head>',\n",
|
|
|
|
|
" '<meta charset=\"utf-8\">','<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">',\n",
|
|
|
|
|
" f'<title>{TITLE} Data Sheet</title>',f'<meta name=\"author\" content=\"{AU}\">',\n",
|
|
|
|
|
" '<style>',CSS,'</style>','</head>','<body class=\"auto-numbering\">',\n",
|
|
|
|
|
" COVER,ch_html,\n",
|
|
|
|
|
" '<div class=\"page-break\"></div>','<h1>Revision History</h1>',\n",
|
2026-07-18 00:51:43 +08:00
|
|
|
" '<table class=\"revision compact\">',\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
" '<thead><tr><th>Rev</th><th>Date</th><th>Changes</th><th>Author</th></tr></thead>',\n",
|
|
|
|
|
" f'<tbody><tr><td>1.0</td><td>{DATE}</td><td>Initial</td><td>{AU}</td></tr></tbody>','</table>',\n",
|
|
|
|
|
" '</body>','</html>',\n",
|
2026-07-18 00:51:43 +08:00
|
|
|
"])\n",
|
2026-07-19 20:56:15 +08:00
|
|
|
"SR=re.compile(r'src=\"(assets/[^\"]+)\"'); mimetypes.init()\n",
|
|
|
|
|
"def em(m):\n",
|
|
|
|
|
" r=m.group(1); ip=(B/r).resolve()\n",
|
|
|
|
|
" if not ip.exists(): return m.group(0)\n",
|
|
|
|
|
" mt,_=mimetypes.guess_type(str(ip))\n",
|
|
|
|
|
" if not mt: mt='image/png'\n",
|
|
|
|
|
" with open(ip,'rb') as f: b64=base64.b64encode(f.read()).decode()\n",
|
|
|
|
|
" return f'src=\"data:{mt};base64,{b64}\"'\n",
|
|
|
|
|
"FULL=SR.sub(em,FULL)\n",
|
|
|
|
|
"out=B/'output'; out.mkdir(exist_ok=True)\n",
|
|
|
|
|
"hp=out/f'{TITLE}_Data_Sheet.html'; hp.write_text(FULL,encoding='utf-8')\n",
|
|
|
|
|
"print(f'\\n {hp.name} ({hp.stat().st_size/1024:.0f} KB) OK')\n"
|
2026-07-18 00:51:43 +08:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
2026-07-19 20:56:15 +08:00
|
|
|
"## Done",
|
|
|
|
|
"\n\nSelf-contained HTML in `output/`."
|
2026-07-18 00:51:43 +08:00
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"metadata": {
|
|
|
|
|
"kernelspec": {
|
|
|
|
|
"display_name": "Python 3",
|
|
|
|
|
"language": "python",
|
|
|
|
|
"name": "python3"
|
|
|
|
|
},
|
|
|
|
|
"language_info": {
|
|
|
|
|
"name": "python",
|
|
|
|
|
"version": "3.9.0"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"nbformat": 4,
|
|
|
|
|
"nbformat_minor": 4
|
|
|
|
|
}
|