Автономный LTE роутер своими руками | Часть 3 – Uboot & OpenWRT

db23a3989b645c5f280adf7bf2574c1b.png

Привет, Хабр! Эта статья посвящена программной части собственного роутера, сегодня будем: допиливать OpenSource, терять месяц жизни впустую, разбираться с модемом, раскрывать секреты OpenWRT«варения для нового устройства и трогать I2C устройства за их регистры.

Статья является логическим продолжением прошлых частей. Поэтому, если вы не хотите терять нить повествования и не видели прошлые — начните сначала с них, а затем можете продолжить: [1], [2], [3]

И ещё один момент. Автор подразумевает что вы знакомы с Uboot и OpenWRT. Хотя бы поверхностно, сделано это намеренно, дабы не раздувать статью по объёму объяснениями что такое uci, ubus, etc. Статья получилась длинной, поэтому наливайте что вам по душе. И приятного прочтения!

Глава 0. Uboot

Загрузчик неотъемлемая часть любого более-менее сложного устройства. Помимо своих прямой обязанности — загрузка система, он ещё и спасает устройство от превращения в «тыкву», которой поможет только программатор.

Выбранный мной SoM HLK-7688, имеет несколько аппаратных ревизий (на момент написания статьи известно о двух, ниже по тексту просто «модуль 1.2» и «модуль 1.3») и судя по всему — они имеют отличия, хотя и прямых подтверждений этому нет.

«Причём тут загрузчик?» — Дело в том, что китайцы поставляют модули 1.3 с форком Uboot от GnuBee. И если собрать его, прошить в модуль 1.2, то мы неожиданно получим ту самую «тыкву», не подающую признаки жизни. Именно по этой причине мне пришлось отказаться от модуля 1.2, который пожертвовал Павел и использовать модуль 1.3 приехавший чуть позже.

С вводными разобрались: модуль 1.3 и Uboot от GnuBee, теперь можно переходить к процессу допила. В теории я мог оставить стоковый китайский загрузчик, но мне не понравилось, что меню загрузки имеет следующий вид:

Скриншот из телеграм чатика посвящённому этим SoMСкриншот из телеграм чатика посвящённому этим SoM

Давайте по порядку, что мне не понравилось:

  1. Неактуальные пункты меню — кто-то ещё пользуется загрузкой через kermit или грузит систему в RAM, а не ROM?

  2. Очень логично что загрузка система идёт не нулевой по списку *сарказм*

  3. А где прошивка через USB? Загрузчик то умеет

  4. Отладочная информация, да полезно, но только разработчикам что её вывод и делали

Глава 1. Uboot и кротовые норы

Однако стоило только мне взяться за причёсывание вышеописанного, как начинал замечать «особенности», если их можно так назвать.

А — Аскетичность А — Аскетичность

Перед вами стоковый menuconfig, в котором можно выбрать SoC, RAM, параметры тактирования, параметры Ethernet порта и… Всё! Ну т.е. серьёзно, больше ничего нельзя выбрать. Ни параметром UART, ни возможности сконфигурировать внешний вид меню. Кто хоть раз собирал нормальный Uboot поймут моё недоумение.

На логичный вопрос «А где-же тогда всё остальное?» — отвечаю, спряталось в rt2880.h

А остальное будьте добры искать сами)А остальное будьте добры искать сами)

Найдя все интересующие определения, параллельно немного разобравшись в коде получилось это:

c06d256fe8dc85cff656d091fb5ac90e.jpg

Ещё в ходе анализа кода, я пробегался глазами по разным репозиториям, в т.ч. и загрузчика Onion Omega2. Понравился местный вариант веб-флешера:

Вот то место, где аскетизм уместен, к тому же тест не разъезжается по всей страницеВот то место, где аскетизм уместен, к тому же тест не разъезжается по всей странице

Вообще, при должном желании и навыках веб разработки можно и своего наверстать, была бы фантазия. Я же ограничился созданием тёмной темы, ибо большинство дебагов ночные, а глаза выжигать — такое себе:/

Также обнаружилось, что омеговский Uboot неожиданно умеет и в прошивку самого себя через веб. Странно, ведь кодовая база одна — вот этот репозиторий Das-U-boot. Открываем httpd.c и находим там, что таки да, возможность имеется, аналогичная имеется и для ART, но у нас его нет. «Но почему же её не используют?» — об этом немного позже.

Я же не задумываясь переношу uboot.html, попутно проверяя что скрипт генерации пожатого веба makefsdatac умеет в uboot.html. Собираю, прошиваю и о чудо!

Вы Uboot’ы прошивайте или просто показывайте? Красивое…Вы Uboot«ы прошивайте или просто показывайте? Красивое…Позволю себе взять скриншот с вики Омеги2, ибо загрузчики практически не отличаютсяПозволю себе взять скриншот с вики Омеги2, ибо загрузчики практически не отличаются

Но только вот если добавить изменений в Uboot, да так чтобы изменился вес бинарника на выходе, то при попытке залить загрузчик, в консоли происходит следующие:

Error: wrong file size, should be 104108 bytes!

Причём работает в обе стороны, т.е. не важно больше или меньше файл. Выход из ситуации сообразился быстро — был увеличен размер дерективы WEBFAILSAFE_UPLOAD_UBOOT_SIZE_IN_BYTES до размера раздела с загрузчиком, а это 128КБ хватит всем. Далее, в конец готового бинаря добиваются FF«ки через hex редактор, дабы размер соответствовал и всё без проблем загружалось.

Казалось бы, теперь можно смело заливать загрузчик. Да не тут-то было! Файл загружается в ОЗУ и при попытке записи в раздел, cp падает в синтаксическую ошибку. Тупик? На помощь снова приходит репозиторий загрузчика Onion Omega2, там находится вариант вызова функции который использует прямую запись через spi-api, вместо вызова консольного cp. Вот с ним проблем не возникает и загрузчик прошивается как нужно.

Кажется именно по этим двум причинам и был вырезан uboot.html из оригинального репозитория. На этом можно было успокоиться, но. я был бы не я, если бы это так оставил и не автоматизировал. Поэтому был быстро сочинён:

resizer.sh

#!/bin/bash

#thx: https://superuser.com/a/689354
newsize=$(grep 'WEBFAILSAFE_UPLOAD_UBOOT_SIZE_IN_BYTES' $PWD/include/configs/rt2880.h | awk '{$1=$2=""; print "("$0")"}' | tr -d ' ')
filesize=$(stat -c "%s" uboot.bin)
padcount=$((newsize - filesize))

echo ""
echo "===============<>=================="
echo "Image file is automatically enlarged to" 
echo "the one specified in WEBFAILSAFE_UPLOAD_UBOOT_SIZE_IN_BYTES"
echo "before the firmware, make sure that everything is correct!!!"
echo ""

dd if=/dev/zero ibs=1 count="$padcount" | tr "\000" "\377" >> 'uboot.bin'

echo ""

Который делает добавляет FFки в конец файла, но в автоматическом режиме, ну и естественно был добавлен вызов скрипта в makefile.

Аналогичным образом был автоматизирован процесс переключения сетевого адаптера DHCP <> Статический IP на основной Windows машине, для этого был создан .bat«ник следующего содержания:

ubootip.bat

@echo off
ECHO 1. Change to static
ECHO 2. Change to dhcp
set choice=
set /p choice= :
if not '%choice%'=='' set choice=%choice:~0,1%
if '%choice%'=='1' goto static
if '%choice%'=='2' goto dhcp

:static
netsh interface ip set address "Ethernet" static 10.5.5.5 255.0.0.0 10.5.5.6 1
goto end

:dhcp
netsh interface ip set address "Ethernet" dhcp
ipconfig /renew "Ethernet"

И для .bat«ника сделан ярлык для меню пуск. Ещё специально для прошивки через веб, обжал короткий 4x пиновый патч-корд, но это уже совсем мелочи. Теперь прошив загрузчика вызывает только удовлетворение.

Ну и как итог имеем следующий вид меню:

Есть конечно что ещё править, но в целом теперь не выглядит как кашаЕсть конечно что ещё править, но в целом теперь не выглядит как каша

Мне повезло, что платы и компоненты приехали к моменту, когда я заканчивал допил китайского Uboot«а напильником, поэтому не нарушая хронологию можно перейти к системе.

Глава 2. OpenWRT

Начну из далека, т.е. как обычно — с железа. Так уж удачно сложилось, что BQ25896 и INA3221 сидящие на I2C, поддерживаются ядром Linux и под них имеются модули ядра. Получается, что и в данном плане мне повезло. Особенно учитывая, что данные микросхемы никто специально по этому критерию не подбирал. 

С поддержкой MT78×8 тоже проблем нет, по крайней мере с первого взгляда, но об этом позже) В свою же очередь, в OpenWRT имеется поддержка выбранного SoM HLK-7688A.

Отлично, значит качем SDK под ramips, пробуем настроить и собрать прошивку — эта мысль, а как позже окажется ошибка, вылилась мне в месяц потерянного впустую времени.

Бесценный архивБесценный архив

«А что не так?» — дело в том, что SDK включает в себя далеко не все модули ядра, а те что есть — заранее собраны.

Ну, а я подумал, что OpenWRT не поддерживает нужные модули ядра для контроллера заряда. Такую логику можно понять, поскольку система предназначена для маршрутизаторов, следовательно зачем там модули ядра для поддержки всего и вся. Не буду рассказывать, как пошёл по ложному пути и пытался портировать модуль ядра, да и ещё как пакет. Просто скажу — не повторяйте моих ошибок и не занимайтесь бесполезным трудом.

Когда рассказал братьям по разуму что портируешь модули ядра для OWRT SDKКогда рассказал братьям по разуму что портируешь модули ядра для OWRT SDK

Правильный путь — это склонировать ветку с интересующей версией OWRT и приступить к добавлению своего девайса. Учтите, что процесс может отличаться в зависимости от архитектуры процессора целевого девайса, поскольку не для всех таргетов имеется .dts конфиги, а какие-то устройства вообще добавляются патчами.

Минимальный суповой набор для добавления своего девайсаМинимальный суповой набор для добавления своего девайса

Перед вами упрощённое древовидное представление каталога target, именно в нём и описывается, как и с чем наш девайс будет добавлен в список доступных. Пройдёмся по каждому файлу сверху вниз, попутно я буду давать комментарии и описывать наиболее интересные секции в файле.

device_name.dts

Описание формата dtsОписание формата dts

Файл .dts или по-русски просто — древо устройства, содержит в себе параметры, которые ядро/система не могут получить простым сканированием подключенных устройств и периферии.

067f4dec794d8e36cbcbe12e694e8b28.png

aliases — здесь передаются названия ноды для глобального определения. Например, тут назначается светодиод для каждой из активностей роутера. В конкретном случае используется один, хотя конечно же можно использовать различные статусные светодиоды, если такие имеются.

bc1e7835680ff02aef41746747b379c7.png

keys, leds — тут всё довольно просто, сначала передаётся название, которое будет отображаться в системе. Затем номер GPIO и состояние логического уровня, которое считается рабочим. В случае с кнопками linux, code задаёт специальное название которое будет обрабатываться эвентом в модуле ядра Hotplug GPIO.

Название linux, code должно быть определено строго то, что описано в структуре файла драйвера, в противном случае прошивка не соберётся!

Для светодиодов trigger-sources и linux, default-trigger задают события-тригеры с помощью которых ядро будет дёргать светодиоды. Лучше использовать для таких статусных светодиодов как USB, поскольку для остальных светодиодов, тригеры задаются в отдельном файле и подразумевают что их возможно переназначить через веб-интерфейс.

4e17095d05a8d1e702db20c23e7cbb44.png

state_default, gpio — определяют состояние пинов, следует переключить если планируется использовать в режиме GPIO. Изображение выше — карта работы пинов у MT7688A и как видно, режимы пинов могут быть разные.

Кстати о них, помните в первой части я писал:

Что касается светодиодов — видимо не зря практически все производители сетевых железок на MTK, используют по одному светодиоду на порт.
Просто оставим пометочку, что лучше использовать по одному светодиоду на порт и не выделываться.

Так вот, посмотрите, что будет если использовать программное управление светодиодами:

На момент записи видео в конфиге светодиоды были перепутаны местами, но сути не меняет – линк горит даже когда его нет :/На момент записи видео в конфиге светодиоды были перепутаны местами, но сути не меняет — линк горит даже когда его нет :/

Всё дело в кривом драйвере свича, фича настолько редко используемая, что данное ненормальное поведение светодиодов не могут пофиксить довольно давно. Вариантов решения два:

  1. Допилить драйвер — в теории при должном желании и что не маловажно, навыках, это реально исправить

  2. Пойти по пути который практикуют ВСЕ производители сетевых железок на MTK — использовать аппаратное индикацию с одним светодиодом на порт. Тут всё просто, со встроенного в SoC свича выведены определённые GPIO, подключаем по светодиоду на порт, правильно конфигурируем и бед не знаем

Я же когда рисовал схему в 2021 и вешал свои 2 светодиода на порт, даже подозревать не мог, что такая проблема возможна, именно так опыт и приходит)

Кстати, часть для BQ25890 отсутствует не просто так, подробнее опишу в конце статьиКстати, часть для BQ25890 отсутствует не просто так, подробнее опишу в конце статьи

C I2C всё ещё проще, хотя по объёму может сначала испугать, в зависимости от использованной железки и модуля ядра для неё — понадобится соответствующим образом заполнить древо.

«Где взять пример?» — нормальные разработчики описывают его где-то рядом со своим модулем ядра. Если же вам не повезло и его нигде нет, но вы точно знайте, что модуль ядра с конкретной железкой где-либо применяется, то тут только гугл поможет спасибо кэп, да.

a27e783cfd75c518c76c49c6d885ff45.png

spi, flash — в данной секции описывается подключенная периферия по spi, зачастую там находится только описание параметров разделов: название, смещение, флаг «только для чтения» в моём случае отличий от оригинального конфига HLK-7688a нет.

mt76×8.mk

Сюда бы по-хорошему добавить все пакеты, что нужны для работы роутера и его периферииСюда бы по-хорошему добавить все пакеты, что нужны для работы роутера и его периферии

Чуть не забыл про него, тут ничего особенного. Обычный make файл, с помощью которого формируется меню и собирается образ для целевого устройства.

Глава 3. Секреты OpenWRT«вариения

0a56b3a59a47bf17e85dc0f15073c38a.jpg

Я не слукавил, когда в шапке статьи написал о раскрытии секретов. Для оставшихся двух файлов действительно не нашлось нормального описания функций и параметров, пришлось действовать по наитию и прибегать к мозговому штурму русскоязычным чатом OWRT разработчиков.

Файлы 01_leds и 02_network лежащие в каталоге board.d, представляют собой обычные bash скрипты выполняющиеся при первом старте роутера сразу после прошивки. Первый описывает поведение светодидов, названия и их тригеры, а второй описывает интерфейсы и их конфигурацию, задаёт их MAC адреса.

Слева 01_leds, справа  02_networkСлева 01_leds, справа 02_network

Как можно заметить, оба скрипта подключают ещё несколько скриптов-библиотек для выполнения функций из них. Один из таких uci-defaults.sh — в нём и описываются функции из вышеописанных файлов, давайте посмотрим на несколько:

Иногда попадаются нетипичные функции, например как функция задающая поведение для светодиодов индикации SATA портовИногда попадаются нетипичные функции, например как функция задающая поведение для светодиодов индикации SATA портов

Кстати, для функции ucidef_set_led_netdev можно в конце передать тригер, будь то линк или приём/передача данных. И если бы не кривая реализация драйвера свича — то это можно было бы вполне использовать.

В веб интерфейса один из таких светодиодов отображался бы вот такВ веб интерфейса один из таких светодиодов отображался бы вот так

Бывают ситуации, когда нужной функции для настройки попросту нет. С такой ситуацией столкнулся @bam80 из телеграм чата OpenWRT RU Dev, когда добавлял поддержку нескольких роутеров от Kroks.

Роутеры со встроенными LTE модемами и для их настройки функция ucidef_set_interface попросту не имела поддержки протоколов qmi и mbim, используемым вышеупомянутыми модемами. Выходов в подобных ситуациях два:

  1. Интегрировать правила uci прямо в скрипт 02_networks. Такой вариант имеет место быть, поскольку среди исходников поддерживаемых роутеров нашлось такое. Видимо это вполне допустимо

  2. Не нарушать устоявшиеся порядки и отправить PR с модификацией скрипта config_generate (о нем немного позже) — именно так @bam80 в итоге и поступил

Ну и чтобы больше не путаться в назначении скриптов, я создал следующую схему:

Замечания, если я где-то ошибся — приветствуютсяЗамечания, если я где-то ошибся — приветствуются

Надеюсь это кому-нибудь будет полезно. В скриптах конечно интересно разбираться, но когда новички это делают раз за разом, то это мне напоминает один мем:

Старая, но до сих пор актуальная картинкаСтарая, но до сих пор актуальная картинка

Безусловно у человека должен быть развит навык самостоятельного поиска информации, я и сам за это топлю. Но в данном случае информацию приходится добывать совсем иным путём, анализировать скрипты, конфиги.

И это проходит каждый начинающий разработчик, при этом «старички» не торопятся делиться информацией и опытом, судя по тому, что по toh (что-то вроде OWRT’шной вики) шаром покати.

Как сказал один очень хороший человек:

Смысл собирать всю жизнь информацию, а потом забирать её в гроб, не поделившись?

Поэтому, если вы не равнодушны к OWRT и хорошо знайте английский — свяжитесь со мной, я поделюсь текстом для перевода и добавим его в toh OWRT.

Глава 4. Сборка прошивки, модем, I2C, регистры и немного веба

Отлично, с добавлением роутера в список девайсов разобрались. Теперь на этом этапе, в качестве проверки, можно собрать прошивку. Не буду выступать в роли прокси для гугла и пропущу описание базовых манипуляций (скачивание исходников, загрузку пакетов и т.д.), а лишь остановлюсь на нескольких важных моментах:

Первый и третий пункт неразрывно связаны. Когда я только начинал (а это была версия LEDE Reboot 17.01.5 для MR3220 v2) мягко говоря, были проблемы. В виртуальной машине прошивка собиралась порядка 4х часов. Приходилось оставлять старенький HP dv6, на ночь включенным и ложиться спать, а потом среди ночи вставать и проверять «А собралось ли?».

Боль и страдания закончились, когда ко мне на помощь пришёл мой лучший друг Арсений, уже знакомый вам по первой части. Он предоставил доступ к своему двухпроцессорному, 32х ядерному монстру на AMD Opteron. На нём чистая сборка занимает максимум 30 мин, а последующие 10 мин от силы. Одно плохо — иногда, благодаря «ТНС Энерго Кубань» у Арсения часто не бывает электричества и билд-машина становится недоступна.

А чтобы ваша билд-машина была всегда доступна в любой день суток и любую погоду, рекомендую арендовать VPS от AdminVPS по выгодной цене в России.

По поводу дискового пространства — нужно порядка 15 гб+ если хотите без проблем собрать несколько версий OWRT. Альтернативный вариантом может послужить сборка через imagebuilder/в контейнере Docker, вроде как в них и собирается быстрее и места меньше занимает. Но признаться честно, я их не пробовал, мне всё классический вариант по душе, если имеется опыт — делитесь в комментариях.

I2C и регистры

А кто это у нас тут?А кто это у нас тут?

Переходим к I2C устройствам. Начну с хорошего, с INA3221 в этом проекте вообще проблем не наблюдается, модуль ядра hwmon просто берёт и работает, а все необходимые показатели просто доступны из псевдофайла.

С BQ25896 в целом тоже всё неплохо, но не в таком виде как хотелось. Если без лишней воды, то у меня так и не удалось подружить модуль ядра Power supply с данным зарядником. Модуль ядра в логах ядра упорно сообщает о том, что ему не хватает IRQ. Хотя я навесом и накидывал нужный провод, прописывал кое-как в .dts пин куда подключил прерывание, всё без толку. Поэтому:

Если вы работали с зарядниками BQ25XXX под Linux просьба написать в коменты/личку, мне будет очень интересно узнать, что я делаю не так.

Как я выходил из ситуации? Сначала пытался допилить модуль ядра, выкинув проверку на IRQ и попутно добавив принудительное включение OTG, но микросхема всё ровно уходила в offline, т.к. внутри модуля что-то ломалось и её опрос завершался. И это даже работало, свои желанные 5V на USB выходе я получил. Однако я посчитал что это неправильно и решил пойти по другому пути.

Работа с BQ25896 подразумевается в нескольких режимах:

4c3c62371f85e87825efb88c714f1080.png

  • C использованием watchdog«а и постоянным сбором его бита. Если хост не уснул/не умер — то постоянно пинает этот самый бит

  • Возможен вариант и без использования watchdog«а если это требуется и допускается устройством хостом

Не трудно догадаться, что я выбрал последний вариант. Так нужно сделать буквально две записи в регистры и всё будет работать себе спокойно.

Тут бы неплохо изменить значение Fast Charge TimerТут бы неплохо изменить значение Fast Charge TimerА тут понизить Minimum System Voltage LimitА тут понизить Minimum System Voltage Limit

Самые глазастые уже заметили, что данные команды лежат в файле rc.local, т.е. выполняются после загрузки системы, однако удобно.

Конечно же хочется, чтобы модуль ядра завёлся, т.к. какой смысл в этой куче регистров, если из них используется всего ничего. Про регистры я ещё вспомню, а у нас на очереди модем и веб, давайте перейдём к ним.

А как же модем?

Многие в комментариях спрашивают про модем, оно и верно, я ведь не упоминал о нём в прошлых статьях — исправляюсь, хоть и позволю себе цитировать свой же комментарий:

Это одна из немногих ошибок, вместо того чтобы взять внутренний M.2 LTE модуль я решил использовать внешний USB модем e3372h-153. Самое интересное что во время создания схемы я прекрасно видел модули на M.2, но почему-то значения им не придал…

О том, как от этого страдает внешний вид устройства и я сам — расскажу в следующей части, а сейчас давайте разберёмся с программной стороной вопроса.

Модемы Huawei умеют работать в двух режимах:

  1. Stick — модем прикидывается самым обычным модемом с несколькими виртуальными COM портами для настроек и соединения в PPP режиме, либо же NDIS, но всё ещё с одним портом для AT команд

  2. Hilink — в этом режиме модем прикидывается полноценным сетевым интерфейсом через протоколы RNDIS/CDC/EEM/NCM и работает как полноценный роутер со стандартными плюшками вроде NAT, DMZ, port forwarding

И по классике я выбираю второй вариант. Хотя почему один я, правильнее сказать, что подавляющее большинство пользователей используют модемы с Hilink прошивками.

Помимо стандартных пакетов для работы с Hilink модемами в прошивку ещё интегрируется замечательный пакет от польского разработчика: luci-app-3ginfo. Он парсит параметры через web api модема и выводит их в виде отдельного раздела:

Также пакет поддерживает и множество других модемов, в общем, рекомендуюТакже пакет поддерживает и множество других модемов, в общем, рекомендую

С ним была только одна проблема — пакет не работает, если интегрировать его в прошивку. Т.е. интерфейс доступен, но при этом данные в нём не отображаются. Сначала я грешил на проблемы с настройками модема, которые я добавляю uci-defaults правилом:

Хотя по сути это очередной bash скрипт с вызовом любых команд, но зачастую обходятся uciХотя по сути это очередной bash скрипт с вызовом любых команд, но зачастую обходятся uci

Однако, как бы я не менял параметры и не задавал их руками через веб, это ничего не давало. Решение оказалось довольно простым:

Про что я собственно и говорил, можно вызывать абсолютно любые командыПро что я собственно и говорил, можно вызывать абсолютно любые команды

Дело было в том, что по какой-то причине postinst часть не выполнялась после установки. Это подтверждалось и тем фактом, что скрипты функционировали если их вызвать принудительно и им передать параметры. Сейчас же makefile заметно похудел и вместо postinst автор использовал uci-defaults правило.

Классно что пакет живёт и исправляетсяКлассно что пакет живёт и исправляется

Уверен, что среди читателей будут агрегаторы, поэтому если у кого-то из вас наблюдались проблемы и вы каким-то чудом не обновились/забили и перестали использовать пакет, то самое время попробовать ещё раз.

Снова регистры?

Устройство автономное и было бы крайне нелогично, не сделать вывод процент заряда где-либо в вебе.

На удивление я снова обошёлся малой кровью и мне не пришлось ничего программировать. Ещё когда ко мне ехали платы, я отыскал готовый пакет luci-mod-battstatus. Однако он хоть и завёлся, но проценты заряда не показывал:

З - захардкоженностьЗ — захардкоженность

Оно и не удивительно, пакет существует только для одного устройства. И естественно он не будет использовать тот же hwmon для чтения показателей батареи.

Чтобы заставить его работать, пришлось прийти к такому же захардкоженному варианту:

21ec40e6504b286b7d11b844e13c198d.png

Текущее состояние батареи вычитывается из соответствующих бит регистра 0B, причём учитывается и состояние соседних битов, поскольку они меняются постоянно.

А процент заряда опрашивается через чтение псевдофайла, который создаёт модуль ядра для INA3221. Затем с помощью костыля на awk и простой формулы, напряжение на шунте пересчитывается в процент заряда.

Ну а так оно выглядит в веб интерфейсеНу, а так оно выглядит в веб интерфейсе

А как выключать?

Наверное, ни для кого не секрет, что современные роутеры не умеют выключаться. Правильнее сказать, что их железо выключаться не умеет, т.к. DC-DC включены постоянно. И как правило обратной связи между SoC и ними нет совсем никакой.

Можно ограничиться кнопкой/переключателем, так я в первой версии схемы и планировал делать, хотя и чуть более умнее чем просто рвать минус или плюс от основного источника питания.

Но я терпеть не могу вкорячивание дубовых кнопок, если схема и софт в состоянии что-то делать сами, потому что это путь слабых.

Вот наглядный пример в лице моего призрака летающего медведя

На стоковом FBG5 нет никакой подсветки, но довольно удачно на переходной плате, китайцами оставлен один двухпиновый XH 2.54. Что делает народ? Клеит ленту внутрь профиля, выводит провода на этот разъём ии…

Дырявит блин корпус и вешает кнопкуДырявит блин корпус и вешает кнопку

При том, что имеется сразу 3 благоприятных фактора:

  1. На платах MKS RobinNano, пять разъёмов под драйвера, четыре из которых заняты, а пятый пустует (в т.ч. и в случае запаянных драйверов).

  2. В Marlin есть управление подсветкой корпуса и соответствующая GCODE команда M355

  3. Существует готовый проект модуля подсветки

Но народ игнорирует эти факторы и выбирает путь в пользу сверления корпуса. Безусловно это их право, пусть хоть RGB ленту повесят, но ситуация в целом как-то удручает.

А всего-то достаточно спаять простенький модуль аля драйвер, на мосфете с оптопарой, сконфигурировать марлин и ВСЁ.

Кстати он до сих пор живёт в таком виде, внутри принтера. Нет ничего более постоянного чем временное…Кстати он до сих пор живёт в таком виде, внутри принтера. Нет ничего более постоянного чем временное…

Даже не обязательно использовать те же детали что и в оригинальном проекте. Я вообще распотрашил первый попавшийся блок питания и взяв мосфет с десятикратным запасом. И как итог имеем вот такую красоту:

Tasker + termux + curl + отправка команды по telnet прямо в принтер, медведь то с WiFi)Tasker + termux + curl + отправка команды по telnet прямо в принтер, медведь то с WiFi)Ну и до кучи допилил плагин MKS Wifi, дабы можно было выключать/включать подсветку прямо из слайсера Cura, если не будет лень – то обязательно сделаю PR)Ну и до кучи допилил плагин MKS Wifi, дабы можно было выключать/включать подсветку прямо из слайсера Cura, если не будет лень — то обязательно сделаю PR)

Именно поэтому выбор пал на контроллер заряда BQ25896, позволю снова сослаться на статью Препарируем дельфина: что внутри у Flipper Zero

На кнопку «назад» повешен не только GPIO процессора, но и один из контактов bq25896, который запускает его из выключенного состояния. Т.е. на фабрике в контроллер заливается прошивка, делаются необходимые тесты, потом контроллер совершает харакири — просит bq25896 выключиться, тот выключается и обрубает контроллеру питание (кроме RTC, про это чуть ниже), и теперь устройство может очень долго лежать в коробочке, не тратя заряд, тот самый shipping mode (когда в начале статьи мы делали Settings-Power-Power OFF-OFF, то это как раз оно).

Отличие лишь в том, что я использовал кнопку RESET и тем самым получилось, не плодить отдельные кнопки/переключатели на каждый чих. А для включения устройства достаточно лишь несколько секунд удерживать эту самую кнопку, всё просто)

Отключение реализовано тем же харакири-методом: Через i2cset делается запись в нужный регистр. Ну и всё это заворачивается в bash скрипт, дабы простой командой можно было отключить роутер.

Poweroff сделан на всякий случай, ибо есть вероятность, что в момент выключения роутер будет манипулировать с флешкой. Если знайте насколько это актуально – пишите в комментарияхPoweroff сделан на всякий случай, ибо есть вероятность, что в момент выключения роутер будет манипулировать с флешкой. Если знайте насколько это актуально — пишите в комментариях

Конечно же это не всё. Лезть в консоль чтобы отключить роутер — это такое себе удовольствие, как бы я консоль не любил. Поэтому для пользовательской кнопки ES0 вместо программного сброса было прописано выключение. А выключение через веб реализовано модулем luci-app-poweroff, там ничего интересного, я лишь заменил команду poweroff на свой shutdown.

Конфетка!Конфетка!

Итоги третьей части

После всех этих манипуляций, устройство становится довольно близко с заводскими аналогами. По юзабельности конечно же, я не пытаюсь прыгнуть выше головы :3

Допиливать OpenSource напильником — довольно увлекательное занятие. Чего только стоит изучение регистров у BQ25896 и привидение в удовлетворительный вид меню Uboot«а. Безусловно, ещё есть к чему стремиться, например перейти на нормальный Uboot с адекватным kconfig. Подробнее о планах я расскажу в следующей, финальной части.

Напоследок поделюсь списком всех изменённых файлов с краткими комментариями, что и для чего, а вы уже сможете прикинуть объём работ, совершённых одним человеком. Увидимся в следующей части!

d2a24590b600902d4302dbfb40f80bf9.png

Балгодарности

© Habrahabr.ru