46 lines
19 KiB
HTML
46 lines
19 KiB
HTML
<!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>
|