Files
templates/doc/index.html

46 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ru"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Templates — переносимые библиотеки</title>
<style>
:root{color-scheme:dark;--bg:#07111f;--panel:#0d1b2c;--panel2:#12243a;--line:#263b54;--text:#e8f0f8;--muted:#9eb0c4;--brand:#55d6be;--blue:#8bc5ff;--warn:#fbbf24}*{box-sizing:border-box}body{margin:0;color:var(--text);background:radial-gradient(circle at 85% 5%,#143354 0,transparent 28%),var(--bg);font:15px/1.65 "Segoe UI",Arial,sans-serif}a{color:var(--blue);text-decoration:none}a:hover{text-decoration:underline}code,pre{font-family:Consolas,"Courier New",monospace}code{color:#b8f7e9}pre{overflow:auto;padding:16px;border:1px solid var(--line);border-radius:12px;background:#071521;color:#d6e5f3}.wrap{width:min(1180px,calc(100% - 32px));margin:auto}header{padding:64px 0 30px}.eyebrow{color:var(--brand);font-weight:800;letter-spacing:.12em;text-transform:uppercase;font-size:12px}h1{max-width:800px;margin:12px 0;font-size:clamp(36px,6vw,66px);line-height:1.05;letter-spacing:-.045em}h2{margin:0 0 8px;font-size:28px}h3{margin:0 0 7px;font-size:18px}.lead{max-width:850px;color:var(--muted);font-size:18px}.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:28px}.stat{padding:15px 18px;border:1px solid var(--line);border-radius:14px;background:#0d1b2ccc}.stat b{display:block;color:var(--brand);font-size:24px}.stat span,.card p,.head p{color:var(--muted)}.tabbar{position:sticky;top:0;z-index:10;border-block:1px solid var(--line);background:#07111fe8;backdrop-filter:blur(14px)}.tabs{display:flex;gap:6px;padding:10px 0;overflow-x:auto}.tab{border:0;border-radius:9px;padding:10px 15px;color:var(--muted);background:transparent;font:inherit;font-weight:700;white-space:nowrap;cursor:pointer}.tab:hover{color:var(--text);background:var(--panel)}.tab[aria-selected=true]{color:#07111f;background:var(--brand)}main{padding:34px 0 70px}.pane[hidden],.card[hidden]{display:none}.head{display:flex;justify-content:space-between;gap:24px;align-items:end;margin-bottom:22px}.head p{max-width:720px}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.card{min-width:0;padding:20px;border:1px solid var(--line);border-radius:16px;background:linear-gradient(145deg,#12243af0,#0d1b2ceb);box-shadow:0 18px 55px #00000047}.meta,.links{display:flex;flex-wrap:wrap;gap:8px}.meta{margin:14px 0}.tag{padding:3px 8px;border:1px solid #34516f;border-radius:999px;color:#bdd0e3;font-size:12px}.ready{border-color:#277463;color:#82e7d2}.links{padding-top:9px;border-top:1px solid var(--line)}.search{width:min(360px,100%);padding:11px 14px;border:1px solid var(--line);border-radius:10px;outline:0;color:var(--text);background:var(--panel);font:inherit}.search:focus{border-color:var(--brand)}.empty{display:none;padding:32px;text-align:center;color:var(--muted)}.callout{margin:18px 0;padding:17px 19px;border-left:4px solid var(--brand);border-radius:0 12px 12px 0;background:var(--panel)}.warning{border-left-color:var(--warn)}.steps{counter-reset:step;display:grid;gap:12px}.step{position:relative;padding:20px 20px 20px 70px;border:1px solid var(--line);border-radius:14px;background:var(--panel)}.step:before{counter-increment:step;content:counter(step);position:absolute;left:20px;top:20px;display:grid;place-items:center;width:32px;height:32px;border-radius:50%;color:#07111f;background:var(--brand);font-weight:900}table{width:100%;border-collapse:collapse;margin:18px 0}th,td{padding:11px 13px;border:1px solid var(--line);text-align:left;vertical-align:top}th{color:var(--brand);background:var(--panel2)}td{background:#0d1b2cad}footer{padding:25px 0 45px;color:var(--muted);border-top:1px solid var(--line)}@media(max-width:900px){.grid{grid-template-columns:repeat(2,1fr)}.stats{grid-template-columns:repeat(2,1fr)}}@media(max-width:620px){.grid{grid-template-columns:1fr}.head{display:block}.search{margin-top:12px}header{padding-top:40px}}
</style></head><body>
<header class="wrap"><div class="eyebrow">Embedded library catalog</div><h1>Переносимые библиотеки без привязки к плате</h1><p class="lead">Единый справочник по репозиторию <code>templates</code>: назначение модулей, границы платформенного кода и практический маршрут переноса на новый микроконтроллер.</p><div class="stats"><div class="stat"><b>11</b><span>библиотек C99</span></div><div class="stat"><b>1</b><span>Python-пакет</span></div><div class="stat"><b>0</b><span>обязательных HAL/OS</span></div><div class="stat"><b>3.9+</b><span>версия Python</span></div></div></header>
<nav class="tabbar" aria-label="Разделы"><div class="wrap tabs" role="tablist"><button class="tab" role="tab" aria-selected="true" aria-controls="overview">Обзор</button><button class="tab" role="tab" aria-selected="false" aria-controls="c-libs">Библиотеки C</button><button class="tab" role="tab" aria-selected="false" aria-controls="python">Python</button><button class="tab" role="tab" aria-selected="false" aria-controls="porting">Как портировать</button><button class="tab" role="tab" aria-selected="false" aria-controls="structure">Структура</button></div></nav>
<main class="wrap">
<section class="pane" id="overview" role="tabpanel"><div class="head"><div><h2>О репозитории</h2><p>Повторно используемый код прошивок и инструментов. Каждая библиотека подключается отдельно и хранит состояние у вызывающей стороны.</p></div></div><div class="grid"><article class="card"><h3>Ядро независимо</h3><p>В переносимом слое нет заголовков MCU, HAL, регистров, IRQ, ОС и динамической памяти.</p></article><article class="card"><h3>Порт узкий</h3><p>SPI, GPIO, I²C, UART, CAN, Flash и часы передаются через callbacks или небольшой файл порта.</p></article><article class="card"><h3>Подключение точечное</h3><p>В сборку добавляются только исходники выбранной библиотеки, include-каталог и нужный порт.</p></article></div><div class="callout"><strong>Главное правило:</strong> распиновка, частоты шин и периферия принадлежат плате. Они остаются в <code>board/</code> или <code>port/</code>, но не попадают в ядро.</div><h2>Как добавить в проект</h2><p>Для фиксируемой версии предпочтителен Git submodule:</p><pre><code>git submodule add https://git.rd12.ru/Andrey/templates.git lib/templates
git submodule update --init --recursive</code></pre><p>Если изменения регулярно возвращаются в библиотеку, используйте subtree:</p><pre><code>git subtree add --prefix lib/templates https://git.rd12.ru/Andrey/templates.git master --squash
git subtree pull --prefix lib/templates https://git.rd12.ru/Andrey/templates.git master --squash</code></pre><div class="callout warning">Не копируйте исходники вручную: копия быстро расходится с источником и перестаёт получать исправления.</div></section>
<section class="pane" id="c-libs" role="tabpanel" hidden><div class="head"><div><h2>Библиотеки C99</h2><p>Поиск работает по имени, интерфейсу и назначению. Метка «готовый порт» показывает уже реализованные платформы.</p></div><input class="search" id="search" type="search" placeholder="Поиск: CAN, дисплей, STM32…"></div><div class="grid" id="libs">
<article class="card" data-s="st7789 дисплей tft spi rgb565"><h3>st7789</h3><p>TFT ST7789V: окна, заливка, линии и текст без framebuffer.</p><div class="meta"><span class="tag">SPI</span><span class="tag">RGB565</span></div><p><b>Порт:</b> SPI write, DC, delay; опционально CS, RESET, backlight.</p><div class="links"><a href="../c/st7789/README.md">README</a><a href="../c/st7789/st7789.h">API</a></div></article>
<article class="card" data-s="keypad кнопки gpio антидребезг"><h3>keypad</h3><p>Шесть кнопок: антидребезг, удержание, автоповтор и очередь событий.</p><div class="meta"><span class="tag">GPIO</span><span class="tag">events</span></div><p><b>Порт:</b> чтение уровня и время в миллисекундах.</p><div class="links"><a href="../c/keypad/README.md">README</a><a href="../c/keypad/keypad.h">API</a></div></article>
<article class="card" data-s="menu меню экран painter ui"><h3>menu</h3><p>Стек экранов, курсор, прокрутка и тема для динамического меню.</p><div class="meta"><span class="tag">UI</span><span class="tag">painter</span></div><p><b>Порт:</b> fill_rect и draw_text.</p><div class="links"><a href="../c/menu/README.md">README</a><a href="../c/menu/menu.h">API</a></div></article>
<article class="card" data-s="eeprom ft24c256 i2c память"><h3>eeprom-ft24c256</h3><p>EEPROM 24Cxx с нарезкой записи по страницам.</p><div class="meta"><span class="tag">I²C</span><span class="tag">storage</span></div><p><b>Порт:</b> I²C write, write-read и delay.</p><div class="links"><a href="../c/eeprom-ft24c256/README.md">README</a><a href="../c/eeprom-ft24c256/ft24c256.h">API</a></div></article>
<article class="card" data-s="can sensor датчик rom"><h3>can-sensor</h3><p>Передача 64-битных ROM датчиков парой CAN-кадров.</p><div class="meta"><span class="tag">CAN</span><span class="tag">sensor</span></div><p><b>Порт:</b> CAN TX/RX.</p><div class="links"><a href="../c/can-sensor/README.md">README</a><a href="../c/can-sensor/can_sensor.h">API</a></div></article>
<article class="card" data-s="ds18b20 onewire температура stm32 f1 g4 f4"><h3>ds18b20</h3><p>1-Wire, CRC8, SEARCH ROM и несколько термометров.</p><div class="meta"><span class="tag">1-Wire</span><span class="tag ready">порты F1/G4/F4</span></div><p><b>Порт:</b> Init, DelayUs, Reset, WriteBit, ReadBit.</p><div class="links"><a href="../c/ds18b20/README.md">README</a><a href="../c/ds18b20/include/ds18b20.h">API</a></div></article>
<article class="card" data-s="protocan transport rs485 rs232 usb uart dma crc gas stm32f4"><h3>protocan-transport</h3><p>ProtoCAN над байтовым потоком: CRC16, ring, GAS и каталог GUI.</p><div class="meta"><span class="tag">UART/USB</span><span class="tag ready">порт STM32F4</span></div><p><b>Порт:</b> stream write и доступный объём TX.</p><div class="links"><a href="../c/protocan-transport/README.md">README</a><a href="../c/protocan-transport/docs/FRAME.md">Кадр</a><a href="../c/protocan-transport/docs/GAS.md">GAS</a></div></article>
<article class="card" data-s="protocan boot can flash firmware crc rollback"><h3>protocan-boot</h3><p>Прошивка по ProtoCAN: A/B-слоты, resume, CRC32, verify и rollback.</p><div class="meta"><span class="tag">CAN</span><span class="tag">firmware</span></div><p><b>Порт:</b> CAN TX, Flash, metadata, verify, reboot.</p><div class="links"><a href="../c/protocan-boot/README.md">README</a><a href="../c/protocan-boot/include/pcan_boot.h">API</a></div></article>
<article class="card" data-s="rs485 boot uart flash firmware stm32f103 stm32g474"><h3>rs485-boot</h3><p>SETGUI v1 firmware update: stream parser, CRC32 и resume.</p><div class="meta"><span class="tag">RS-485</span><span class="tag ready">порты F103/G474</span></div><p><b>Порт:</b> UART TX/RX, DE и Flash.</p><div class="links"><a href="../c/rs485-boot/README.md">README</a><a href="../c/rs485-boot/include/rs485_boot.h">API</a></div></article>
<article class="card" data-s="set protocol uart can usb ethernet tcp udp telemetry firmware"><h3>set-protocol</h3><p>SET v2: управление, телеметрия и прошивка через UART/CAN/USB/Ethernet.</p><div class="meta"><span class="tag">multi-transport</span><span class="tag">v2</span></div><p><b>Порт:</b> доставка кадров, часы, карта и firmware backend.</p><div class="links"><a href="../c/set-protocol/README.md">README</a><a href="../c/set-protocol/PROTOCOL.md">Протокол</a><a href="../c/set-protocol/PORTING.md">Перенос</a></div></article>
<article class="card" data-s="rtc часы backup k1921vk028"><h3>rtc-service</h3><p>RTC с резервным backup-томом и единым API времени.</p><div class="meta"><span class="tag">RTC</span><span class="tag ready">порт K1921VK028</span></div><p><b>Порт:</b> RTC и backup storage.</p><div class="links"><a href="../c/rtc-service/README.md">README</a><a href="../c/rtc-service/PORTING.md">Перенос</a><a href="../c/rtc-service/HELP.md">API</a></div></article>
</div><div class="empty" id="empty">Ничего не найдено.</div></section>
<section class="pane" id="python" role="tabpanel" hidden><div class="head"><div><h2>protocan для Python</h2><p>Хостовая сторона без Qt и pyserial: принимает и возвращает <code>bytes</code>, подходит GUI, скриптам и CI.</p></div></div><div class="grid"><article class="card"><h3>protocan.py</h3><p>29-битный CAN ID и тела сообщений. Зеркало <code>pcan_id.c</code>.</p></article><article class="card"><h3>transport.py</h3><p>Кадр <code>AA 55</code>, stream parser, ресинхронизация и CRC16.</p></article><article class="card"><h3>protocol + gas_catalog</h3><p>Кадр <code>A5 5A</code>, CRC32, каталог и подписка на значения.</p></article></div><pre><code>from protocan import protocan, transport
parser = transport.FrameParser()
for frame in parser.feed(port.read(256)):
print(protocan.decode(frame.can_id, frame.data).summary)</code></pre><p>Python 3.9+, только stdlib. <a href="../python/protocan/README.md">Полное README</a>.</p></section>
<section class="pane" id="porting" role="tabpanel" hidden><div class="head"><div><h2>Как портировать</h2><p>Маршрут для STM32, K1921, другого MCU или host-окружения.</p></div></div><div class="steps"><article class="step"><h3>Выберите библиотеку</h3><p>Найдите в README раздел «Что нужно от платформы» или «Контракт порта».</p></article><article class="step"><h3>Подключите ядро</h3><p>Добавьте переносимые <code>src/</code> и <code>include/</code>. CMSIS/HAL и IRQ оставьте в проекте.</p></article><article class="step"><h3>Проверьте готовый порт</h3><p>DS18B20: F1/G4/F4; ProtoCAN transport: F4; RS-485 boot: F103/G474; RTC: K1921.</p></article><article class="step"><h3>Реализуйте контракт</h3><p>Создайте callbacks для I/O, времени или Flash. Контекст передавайте через <code>void *</code>.</p></article><article class="step"><h3>Настройте плату</h3><p>Распиновку, clocks и адреса храните в <code>board/app_config.h</code> или config библиотеки.</p></article><article class="step"><h3>Проверьте</h3><p>Сначала host-тесты, затем smoke-test платы, границы памяти и аппаратные тайминги.</p></article></div><h2 style="margin-top:30px">Типовые контракты</h2><table><thead><tr><th>Класс</th><th>Реализует проект</th><th>Остаётся в ядре</th></tr></thead><tbody><tr><td>Дисплей</td><td>SPI, GPIO, delay</td><td>команды, геометрия, текст</td></tr><tr><td>Датчик</td><td>GPIO/open-drain, delay</td><td>поиск, CRC, данные</td></tr><tr><td>Поток</td><td>UART/USB/TCP RX/TX</td><td>кадры, CRC, parser</td></tr><tr><td>Загрузчик</td><td>Flash, metadata, verify</td><td>сессия, resume, state machine</td></tr></tbody></table><div class="callout warning">USB/TCP chunks не равны границам кадров; CAN router не вызывают из ISR; RS-485 DE снимают после физического TC; firmware backend пишет в неактивный слот и имеет rollback.</div><p><a href="../NEW_PROJECT.md">NEW_PROJECT.md</a> · <a href="../c/set-protocol/PORTING.md">SET PORTING</a> · <a href="../c/rtc-service/PORTING.md">RTC PORTING</a></p></section>
<section class="pane" id="structure" role="tabpanel" hidden><div class="head"><div><h2>Структура нового проекта</h2><p>При смене MCU заменяются <code>board/</code>, <code>port/</code>, startup и linker script; приложение и ядра остаются.</p></div></div><pre><code>my-device/
├── app/ логика изделия
├── board/app_config.h выводы, частоты, адреса
├── port/ адаптеры библиотек к SDK MCU
├── vendor/ CMSIS, startup, linker script
└── lib/templates/ git submodule
├── c/
└── python/</code></pre><h2>Пример: DS18B20 на STM32G474</h2><pre><code>lib/templates/c/ds18b20/src/onewire.c
lib/templates/c/ds18b20/src/ds18b20.c
lib/templates/c/ds18b20/ports/stm32g4/onewire_stm32g4.c
board/onewire_config.h</code></pre><p>Include paths: <code>c/ds18b20/include</code> и <code>board</code>. В конфигурации меняются GPIO, pin и clock.</p></section>
</main><footer><div class="wrap">Источник истины — README и нормативные Markdown-файлы рядом с кодом. HTML служит обзором и точкой входа.</div></footer>
<script>
const tabs=[...document.querySelectorAll('[role=tab]')],panes=[...document.querySelectorAll('[role=tabpanel]')];function show(id,hash=true){const t=tabs.find(x=>x.getAttribute('aria-controls')===id)||tabs[0];tabs.forEach(x=>x.setAttribute('aria-selected',x===t));panes.forEach(x=>x.hidden=x.id!==t.getAttribute('aria-controls'));if(hash)history.replaceState(null,'','#'+t.getAttribute('aria-controls'))}tabs.forEach((t,i)=>{t.onclick=()=>show(t.getAttribute('aria-controls'));t.onkeydown=e=>{if(e.key==='ArrowRight')show(tabs[(i+1)%tabs.length].getAttribute('aria-controls'));if(e.key==='ArrowLeft')show(tabs[(i-1+tabs.length)%tabs.length].getAttribute('aria-controls'))}});if(location.hash)show(location.hash.slice(1),false);const search=document.querySelector('#search'),cards=[...document.querySelectorAll('#libs .card')];search.oninput=()=>{const q=search.value.toLocaleLowerCase('ru').trim();let n=0;cards.forEach(c=>{const ok=!q||(c.dataset.s+' '+c.textContent).toLocaleLowerCase('ru').includes(q);c.hidden=!ok;n+=ok});document.querySelector('#empty').style.display=n?'none':'block'};
</script></body></html>