Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Регистрируясь, я даю согласие на обработку данных и условия почтовых рассылок.
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр Вы владелец небоскреба! Стройте этажи, управляйте магазинами и работниками!

Небоскреб Мечты

Казуальные, Симуляторы, 2D

Играть

Топ прошлой недели

  • cristall75 cristall75 6 постов
  • 1506DyDyKa 1506DyDyKa 2 поста
  • Animalrescueed Animalrescueed 35 постов
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая «Подписаться», я даю согласие на обработку данных и условия почтовых рассылок.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
0 просмотренных постов скрыто
IcyFemida

Нашел в телеге забавного бота, который ставит "диагноз" по профилю Пикабу. Решил проверить админа⁠⁠

1 месяц назад

Вечер, сижу листаю телегу, и тут знакомый кидает ссылку на какого-то бота для Пикабу. Типа вбиваешь ник, а он тебе выдает твой "архетип" на сайте.

Ну, думаю, очередная фигня. Но ради интереса решил попробовать. Сначала себя прогнал:

Выпал "Стойкий Обитатель", ну ладно, хоть не "Воин Свежего" :)

А потом стало интересно, а что он покажет на реально старых и известных профилях? Недолго думая, вбил admin. И вот тут я орнул.

"Верховный Смотритель", ахах. Кажется, бот что-то знает.

Решил поделиться с вами, может, тоже захотите себя или друзей проверить. Штука забавная.

Вот ссылка на самого «Пикабушного Диагноста»:
---> t.me/PikaAnalystBot <---

Показать полностью 2
Своими руками Программирование Telegram Бот IT Гифка Telegram (ссылка) Длиннопост
4
118
monobogdan
monobogdan
TECHNO BROTHER

Продолжение поста «Я купил игровую консоль и написал для неё BIOS»⁠⁠2

1 месяц назад

Меня часто спрашивают, почему я не наносек.

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

Так что фигня это все, мой максимум - второсортные развлекательные статейки, чисто как бульварное чтиво, только про IT. Почти как нейромусор.

Опрос Покупка Гаджеты Нужно ваше мнение Консоли Игры Своими руками Arduino Инженерия Программирование C++ Arm Raspberry Pi Гифка Длиннопост Ответ на пост Текст
35
993
monobogdan
monobogdan
Посты о ремонте и моддинге ретрогаджетов.
TECHNO BROTHER

Я купил игровую консоль и написал для неё BIOS⁠⁠2

1 месяц назад

Осторожно: Статья написана максимально простым языком. Так что если вы гик, но не умеете программировать - вам всё равно будет интересно!

Недавно я наткнулся на DIY-игровую консоль за 1.500 рублей - Waveshare GamePi13. Когда гаджет приехал ко мне, я запустил примеры игр от производителя... и оторопел от 5 FPS в Pong - это ж как плохо нужно код писать!

Не желая мириться с этим, я открыл схему устройства, даташит на RP2040 и принялся писать свой собственный BIOS. Если вам интересно узнать, как работают DIY-консоли «изнутри», можно ли запускать внешние программы на микроконтроллерах из RAM, как реализованы различные подсистемы BIOS, а в конце даже написать «Змейку» - добро пожаловать под кат!

❯ Предисловие

Иногда китайские производители выпускают на рынок дешевые гаджеты с ориентиром исключительно на гиков. Чего-уж говорить, с какой-нибудь R36s чего только не сделали: и кастомные прошивки, и порты игр с ПК, и даже достаточно сложные аппаратные модификации. Однако в тусовке DIY'щиков обычно всё куда хардкорнее...

«Андерграундные» консоли выходят чуть ли не каждый день, но лишь единицы из них становятся хоть сколь либо популярными и попадают на массовый конвейер. От «больших» консолей их отличает простая схемотехника, использование распространенных и дешевых микроконтроллеров общего назначения и полная свобода творчества — что хочешь, то и твори! По характеристикам они чаще всего близки к оригинальному GameBoy или GameBoy Advance, а покупают их инженеры, демосценеры и ретро-энтузиасты, которые не только играют во что-то готовое, но и пишут небольшие игрушки сами!

Самые известные консоли такого формата — это нашумевший Playdate и чуть менее известный Arduboy. Обе консоли сильно ограничены в характеристиках и это подстегивает интерес гиков к постоянной оптимизации кода и попыткам впихнуть «невпихуемое». Выделился даже российский «Микрон», представив свою DIY-консоль «для хардкорных ардуинщиков» — некий MikBoy на базе своего же МИК32 «Амур»!

Я уверен что Микроновцы будут читать эту статью... Если вдруг всё получится и MikBoy пойдёт в серию — то напишите мне пожалуйста сообщение :)

Я уверен что Микроновцы будут читать эту статью... Если вдруг всё получится и MikBoy пойдёт в серию — то напишите мне пожалуйста сообщение :)

Подобным «ардуинщиком» являюсь и я. Ещё со школьных лет меня нереально тянет к микроконтроллерам и Embedded-электронике в целом. О консоли собственной разработки я мечтаю с 14 лет, при этом мне не просто хочется собрать прототип и «забить», но и запустить мелкосерийное ручное производство и продавать устройства подписчикам! К своим 24-годам я сделал два прототипа и развел три платы, но все эти проекты так или иначе откладывались в долгий ящик...

Один из ранних-ранних прототипов, предназначенный для обкатки драйвера дисплея.

Один из ранних-ранних прототипов, предназначенный для обкатки драйвера дисплея.

И вот, 25 сентября мне стукнуло 24 годика. Уже взрослый мальчик получил в качестве подарка донат от постоянного читателя и пошёл изучать маркетплейсы в поисках интересного железа. По ключевым словам «tft lcd diy» был найден «ESP32 Bitcoin Miner V2» (выгодный девкит с 2.8" и ESP32-S2), девкит ESP32 с 4.3" дисплеем и емкостным тачскрином, а также некий Waveshare GamePi13, о котором мы сегодня с вами и поговорим!

Отдельное спасибо хотелось бы сказать тем самым подписчикам. Без вашей поддержки этой статьи бы не было!

Waveshare — знаменитый в кругах энтузиастов SBC производитель. В основном компания занимается дисплеями, модулями расширения и одноплатными компьютерами.

Waveshare — знаменитый в кругах энтузиастов SBC производитель. В основном компания занимается дисплеями, модулями расширения и одноплатными компьютерами.

В тот же день я заказал устройство, и уже через 3 недели трепетного ожидания, GamePi13 оказался у меня на столе. На первый взгляд консоль показалась очень маленькой: её 1.3" дисплей был даже меньше, чем у Nokia 6230i, а кнопки оказались расположены непривычно близко друг к другу. Ко всему прочему, у консоли не было предусмотрено вообще никакого корпуса: ни «болванки» от производителя, ни STL-файлов для печати. Что-ж, это только придаёт брутальности нашему устройству!

Оба устройства помещаются в одну ладошку... А ведь когда-то 6230i казался реально большим!

Оба устройства помещаются в одну ладошку... А ведь когда-то 6230i казался реально большим!

Как вы уже могли заметить, консоль состоит из двух независимых модулей: платы разработки Waveshare RP2040-PiZero и «бутербродного» геймпада с дисплеем, который подключается к гребёнке основной платы. В этом и кроется главный секрет устройства: геймпад изначально рассчитан именно для «одноплатников» Raspberry Pi, но поскольку Waveshare также выпускает плату RP2040 с Pi-совместимой гребёнкой, они решили заодно адаптировать его и для PiZero.

❯ Что внутри?

Хоть PiZero и похожа на референсную плату в лице Raspberry Pi Pico, у неё есть несколько серьёзных отличий:

  • Во первых, на плате установлена SPI-флэшка объёмом аж в 16МБ. Это максимальный объём, который поддерживает XIP-контроллер в RP2040. В RPi Pico же используется флэш-память объёмом всего в 2МБ.

  • Далее внимание привлекает использование менее эффективного ULDO RT9193 вместо полноценного DC-DC преобразователя в оригинальном Pico. Сам микроконтроллер сможет работать при разрядке аккумулятора ниже 3.6В, а вот периферия — под вопросом. Иными словами, мы не сможем использовать «все соки» из аккумулятора и нам придётся реализовывать отсечку по напряжению.

  • На плате распаяна микросхема-чарджер литий-ионных аккумуляторов ETA6096 с током зарядки аж в 1А. Если захотите использовать аккумулятор меньшей емкости — стоит подобрать резистор ISET большего номинала, иначе есть риск перегрева.

  • Из разъёмов распаян HDMI (да, я тоже в шоке), слот для MicroSD (под него отдали весь SPI0) и два Type-C: один для аппаратного USB-контроллера в RP2040, второй для USB через PIO. В общем, пытались угодить всем.

Плата с геймпадом не менее интересная. С фронтальной стороны у нас расположилось 10 кнопок и 1.3" IPS-дисплей с разрешением 240x240, использующий контроллер ST7789. Вообще, для такой диагонали разрешение дисплея крайне избыточно: оно не только съедает драгоценные килобайты оперативной памяти для фреймбуфера, но и значительно грузит DMA-контроллер и всю шину SPI. Я бы на месте инженеров установил бы сюда «золотой стандарт» — недорогой 1.8" 128x160. Все кнопки подключены к отдельным пинам без сдвигового регистра и занимают значительную часть доступных GPIO.

Я бы сделал лучше!

Я бы сделал лучше!

С обратной стороны расположился небольшой динамик, усилитель, построенный на базе NS8002, 3.5мм джек для подключения наушников, а также токоограничивающий резистор подсветки и обвязка для дисплея. Подсветка подключена напрямую к VSYS и рассчитана на питание от 3.3В, так что никакой регулировки яркости и продвинутых режимов сна!

Производитель платы — компания SpotPear.

Производитель платы — компания SpotPear.

Ну что-ж, собираем наш бутерброд обратно, подключаем Type-C и смотрим на одну из представленных демо-игр — Тетрис!

Нет, это не пережатая гифка, игра действительно идёт буквально в 1 FPS и с мерцанием — и это на микроконтроллере с ядром Cortex-M0+ на частоте аж в 150МГц! Я напомню, что N-Gage с процессором TI OMAP на более старом ядре ARM926EJ-S с частотой 104МГц умудрялся тянуть первый Tomb Raider с полностью программным рендерингом в 25 FPS!!!

Далее я решил открыть официальный вики Waveshare и изучить информацию о консоли, где нашел несколько примеров игр для неё, одной из которых был Pong. Какое же было моё разочарование, когда я узнал, что обе игры написаны полностью на Python: игровая логика, маршалинг данных, работа с «железом» — всё это было на интерпретируемом языке и более того, написано плохо и крайне неэффективно!

class hardware():
def init():
spi0=SPI(1,baudrate=900000000, phase=0, polarity=0,
sck=Pin(game_kit.lcd_sck, Pin.OUT),
mosi=Pin(game_kit.lcd_sda, Pin.OUT))
display = st7789.ST7789(spi0, 240, 240,
reset=Pin(game_kit.lcd_rst, Pin.OUT),
dc=Pin(game_kit.lcd_dc, Pin.OUT),cs=Pin(game_kit.lcd_cs, Pin.OUT),
xstart=0, ystart=0, rotation=0)
# 初始界面,提示游戏开始
display.fill(st7789.BLACK)
display.text(font2, "Pong!", 90, 90)
display.text(font2, "Let's go!", 60, 140)
time.sleep(1)

hardware.display = display


class pong():
def __init__(self):
# bgm
self.bgm = p_music(p_music.song2, tempo=1, duty=500, pins=[
Pin(game_kit.buzzer, Pin.OUT)])
# 控制音乐暂停和播放的键start
self.key_start = button(game_kit.key_start, self.key_start_callback)

# led
self.led = Pin(game_kit.led_sta, Pin.OUT)

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

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

def blit_buffer(self, buffer, x, y, width, height):
"""
Copy buffer to display at the given location.

Args:
buffer (bytes): Data to copy to display
x (int): Top left corner x coordinate
Y (int): Top left corner y coordinate
width (int): Width
height (int): Height
"""
self.set_window(x, y, x + width - 1, y + height - 1)
self.write(None, buffer)

Звуковая подсистема, состоящая из одноканальной тональной пищалки на аппаратном ШИМ-контроллере, тоже была со своими «приколами». Например «тишина» — это 0, то есть магнит всегда прижат к нижней части, хотя должно быть PWM_MAX / 2.

Под впечатлением от такого кода, я решил попробовать написать SDK для этой консоли сам. Однако моё видение идеальной DIY-консоли сильно отличалось от того-же Arduboy или Playdate!

❯ Архитектура

При проработке архитектуры будущего «BIOS», я сразу же поставил для себя несколько чётких задач:

  • Во первых, BIOS должен быть достаточно абстрактным для того, чтобы скрывать от игры детали реализации конкретного «железа». Иными словами, игра оперирует не DMA-контроллерами, FPU-сопроцессором и SPI, а набором простых и понятных подсистем: графика, ввод, звук, хранилище. Кроме того, это позволяет легко портировать игры для такого BIOS'а на другие платформы: можно без проблем реализовать симулятор (не эмулятор!) консоли на ПК или портировать её на ESP32 с минимальными изменениями.

  • Во вторых, мы ставим производительность в основной приоритет при разработке устройства. В конце-концов это же позорище, что простейшая игра тормозит и мерцает на мощном микроконтроллере, но при этом тетрисы с трёхмерной графикой вполне шустро работали на телефонах Sony Ericsson 2005 года. Именно поэтому для написания игр используются не скриптовые языки по типу Lua или JS, а самый обычный «C с классами».

  • В третьих, сам BIOS должен быть легко портируем между разными платами (у SpotPear есть вторая похожая плата — уже с 1.5" и стиком) и даже аппаратными платформами. Этот проект может стать основной прошивкой для консоли уже моей разработки и иметь вот такую «кроссплатформу» было бы отнюдь не лишним!

Руководствуясь критериями выше, я решил писать BIOS на C++ (на деле C с классами) с активным использованием интерфейсов и VMT. Это позволяет не только удобно структурировать модули и повышает читаемость кода игры, но и избавляет от необходимости вручную составлять таблицу системных вызовов к API. Тем не менее, в таком подходе есть один серьёзный нюанс: когда у подсистем появляются новые методы или добавляются перегрузки к прошлым, их необходимо по порядку добавлять в конец интерфейса, иначе VMT ломается.

vtable for CTest:
.word 0
.word typeinfo for CTest
.word CTest::Test()
.word CTest::Abc()
vtable for ITest:
.word 0
.word typeinfo for ITest
.word __cxa_pure_virtual
.word __cxa_pure_virtual

В своё время Microsoft решила эту проблему в COM с помощью QueryInterface и миллиона вариаций этих самых интерфейсов: IDirectSound8, IDirectDraw7 и т.д, но мы можем не изобретать велосипед, а просто предоставлять «старым» играм такие же «старые» версии VMT.

Основным объектом в BIOS'е является CSystem, который содержит в себе ссылки на другие подсистемы консоли, а также на информацию о текущей аппаратной платформе:

/// @brief Primary system service, supplied to both games and system modules.
class ISystem
{
public:
virtual CSystemInfo* GetSystemInfo() = 0;

virtual void* Alloc(uint32_t size) = 0;
virtual void Free(void* ptr) = 0;

virtual IGraphicsService* GetGraphicsService() = 0;
virtual IInputService* GetInputService() = 0;
virtual IDebugService* GetDebugService() = 0;
};

Несмотря на кажущуюся «динамическую» натуру системы, никаких IID я переизобретать не стал. BIOS должен реализовывать ровно тот минимальный функционал системы, который нужен. Экземпляр CSystem создаётся так называемым «портом» на конкретную плату, который должен заполнить структуру с указателями на реализации подсистем — прямо как machine-файлы в Linux! И RAII не нарушили, и полный контроль без костылей сохранили — ляпота!

void InitializePlatform()
{
CommManager = new CCommunicationManager();
CDebugService* dbgSvc = new CDebugService();

/* Print some userful debug information */
CJEDECFlashID* flashId = FlashManager.GetFlashID();

dbgSvc->Print("Initializing platform");
dbgSvc->Print("Flash memory manufacturer: 0x%x, capacity: %dKb", flashId->Manufacturer, flashId->Capacity / 1024);
dbgSvc->Print("CID: %d", FlashManager.GetCID());
dbgSvc->Print("First available: %d", FlashManager.GetFirstUserSector());

/* Service initialization */
InputService = new CInputService(dbgSvc);
GraphicsService = new CGraphicsService(dbgSvc);

/* Platform description info */
PlatformInfo.DebugService = dbgSvc;
PlatformInfo.GraphicsService = GraphicsService;
PlatformInfo.InputService = InputService;

System = new CSystem(&PlatformInfo);
}

int main() {
InitializePlatform();

while (true) {
/* Tick all platform-depend services here */
CommManager->Tick();
PowerStateManager.Tick();
InputService->Tick();

System->Tick();
}
}

В целом, базовая архитектура примитивная и понятная. Перейдем же к деталям реализации конкретных модулей.

❯ Графика

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

struct CFrameBufferInfo
{
uint16_t Width;
uint16_t Height;
CColor* Pointer;
uint32_t Size;
};

class IDrawingSurface : public ISystemService
{
public:
virtual void Clear(CColor color) = 0;
virtual void DrawBitmap(CBitmap* bitmap, int x, int y) = 0;
virtual void DrawBitmapEx(CBitmap* bitmap, int x, int y, CSpriteInfo* spriteInfo) = 0;
virtual void DrawRect(CColor color, int x, int y, int width, int height) = 0;
virtual void FillRect(CColor color, int x, int y, int width, int height) = 0;
virtual void DrawLine(CColor color, int x1, int y1, int x2, int y2) = 0;
virtual void DrawString(CColor color, int x, int y, CAnsiChar* str) = 0;
};

class IGraphicsService : public ISystemService
{
public:
virtual void SetPowerState(bool isPowerEnabled) = 0;
virtual void SetBacklightState(bool isBacklightEnabled) = 0;
/* Maybe some controller-related functions in future? Like BIAS and HW rotation? */

virtual CFrameBufferInfo* GetFrameBufferInfo() = 0;
virtual IDrawingSurface* GetDrawingSurface() = 0;
virtual void Flush() = 0;
};

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

/* Perform hardware reset */
gpio_put(PIN_LCD_RST, 0);
sleep_ms(DISPLAY_INIT_SLEEP_TIME);
gpio_put(PIN_LCD_RST, 1);
sleep_ms(DISPLAY_INIT_SLEEP_TIME); /* Wait for display controller to complete initialization */

Reset(); /* Perform software reset to maintain default register state */
SendCommand(cmdSLPOUT, 0, 0); /* Disable sleep mode */
SendCommand(cmdCOLMOD, 0x05); /* Set color format and decoding*/
SendCommand(cmdINVON, 0, 0); /* Disable inversion */
SendCommand(cmdNORON, 0, 0); /* Enable normal mode */
SendCommand(cmdMADCTL, cmdMADCTL_RGB); /* Set pixel size */

uint8_t windowSize[] = { 0 >> 8, 0, DISPLAY_WIDTH >> 8, DISPLAY_WIDTH }; /* Set display window (note this is not safe for displays with sides not equal in size) */
SendCommand(cmdCASET, windowSize, 4);
SendCommand(cmdRASET, windowSize, 4);

SetPowerState(true); /* Enable display */

Вероятно читатель может спросить: «зачем выделять целых 115КБ под фреймбуфер, если можно использовать команды CASET/RASET и рисовать отдельные спрайты прямо в память дисплея?». Дело в том, что в таком случае скорость отрисовки будет падать обратно пропорционально размеру и числу рисуемых изображений. Если мы попытаемся нарисовать параллакс-фон, состоящий из трёх картинок с размерами 240x240, то нашим узким местом станет не только цена обращения к XIP-кэшу, но и производительность SPI-контроллера (который напрямую тактируется от системного PLL) и мы получим те самые 1-2 FPS. Кроме того мы потеряем возможность использования DMA и нам придётся ждать каждой транзакции на экран: это проблема многих «самодельных» консолей, которую, впрочем, можно решить обратившись к опыту предков — а именно PPU.

В своём проекте я решил активно задействовать DMA-контроллер для отправки фреймбуфера на дисплей. Концепция простая: мы указываем ему переслать фреймбуфер, начинаем подготавливать следующий кадр и если транзакция ещё не завершена - то дожидаемся её окончания, дабы картинка оставалась целостной. Однако если обновление логики следующего кадра завершается быстрее, чем DMA-контроллер успевает отправить сканлайны - мы можем получить эффект тиринга.

/* Setup DMA for SPI */
dmaChannel = dma_claim_unused_channel(true);

dmaConfig = dma_channel_get_default_config(dmaChannel);
channel_config_set_transfer_data_size(&dmaConfig, DMA_SIZE_8);
channel_config_set_dreq(&dmaConfig, spi_get_dreq(spi1, true));
channel_config_set_read_increment(&dmaConfig, true);
channel_config_set_write_increment(&dmaConfig, false);

...

if(!dma_channel_is_busy(dmaChannel))
{
uint8_t cmdByte = cmdRAMWR;
gpio_put(PIN_LCD_CS, 0);
gpio_put(PIN_LCD_DC, 0);
spi_write_blocking(spi1, &cmdByte, 1);

gpio_put(PIN_LCD_DC, 1);
dma_channel_configure(dmaChannel, &dmaConfig, &spi_get_hw(spi1)->dr, frameBufferInfo.Pointer, frameBufferInfo.Size, true);
}

Далее переходим к фактической отрисовке изображений. На данный момент поддерживается только один формат пикселей — RGB565, поскольку нет особого смысла использовать 8-битную палитру для изображений 32x32 (но есть смысл использовать 4х-битную, как на NES). Процесс рисования называется блиттингом и поскольку реализация полноценного альфа-блендинга слишком дорогая для реалтайм графики на микроконтроллерах, для описания прозрачности используется техника колоркеев.

Взято с <a href="https://pikabu.ru/story/ya_kupil_igrovuyu_konsol_i_napisal_dlya_neyo_bios_13327291?u=https%3A%2F%2Fru.pinterest.com%2Fpin%2F663506957573347585%2F&t=pinterest&h=b409d0ad71297189d8f711597c010a1f143b8fba" title="https://ru.pinterest.com/pin/663506957573347585/" target="_blank" rel="nofollow noopener">pinterest</a>

Взято с pinterest

ColorKey — это как ChromaKey, но для описания прозрачного цвета используется только базовый цвет, а не цвет + порог допустимых цветов. Помните как в играх 90-х были картинки с розовым фоном цвета Magenta? Вот это оно самое :)

for(int i = 0; i < min(y + bitmap->Height, frameBufferInfo->Height) - y; i++)
{
CColor* bitmapScanline = &bitmap->Pointer[i * bitmap->Width];
CColor* scanline = &frameBufferInfo->Pointer[(y + i) * frameBufferInfo->Width + x];

for(int j = 0; j < min(x + bitmap->Width, frameBufferInfo->Width) - x; j++)
{
uint16_t sample = *bitmapScanline;

if(sample != bitmap->ColorKey)
*scanline = sample;

scanline++;
bitmapScanline++;
}
}

Рисование текста реализовано знакомым для Embedded-инженеров способом: шрифты описываются в формате 8x8, где 8 битов каждого байта обозначают наличие или отсутствие пикселя в текущей позиции. Такие шрифты не только занимают очень мало места, но их также очень легко и быстро рисовать, а также масштабировать под различные разрешения экранов. На данный момент я задумываюсь — стоит ли добавлять в консоль поддержку полноценного UTF-16, если учесть что основной таргет на русскоязычную аудиторию, где и CP866 хватает с головой?

Какой же дисплей чёткий...

Какой же дисплей чёткий...

❯ Ввод

Далее мы плавно переходим к реализации драйвера ввода. Как я уже говорил выше, все кнопки подключены к своим отдельным GPIO без использования сдвигового регистра или I/O Expander'а, что с одной стороны и хорошо (некоторые китайские производители реализовывают консоли с кнопками, основанными на матричном (!!!) принципе), а с другой — отъедает большинство GPIO у RP2040. Свободными пинами мы могли бы выполнять множество полезной работы: получать уровень заряда аккумулятора у Fuel Gauge, управлять уровнем подсветки с помощью ШИМ-контроллера и ключа, или, в конце-концов, сделать порт для подключения периферии... но нет так нет.

Сам по себе драйвер ввода до жути примитивный: он позволяет получить состояние отдельных кнопок, осей (как Input.GetAxis в Unity) и проверить, нажата ли хоть какая-то кнопка:

class IInputService : public ISystemService
{
public:
virtual EKeyState GetKeyState(EKeyCode keyCode) = 0;
virtual int GetAxis(EInputAxis axis) = 0;
virtual bool IsAnyKeyPressed() = 0;
};

Для удобства и портабельности BIOS'а между платами, кнопки геймпада маппятся к соответствующим GPIO в отдельной таблице трансляции, которая также содержит состояния этих самых кнопок:

// Should be layouted in order of EKeyCode enum
CButtonState ButtonMapping[] = {
{
PIN_KEY_LEFT
},
{
PIN_KEY_RIGHT
},
{
PIN_KEY_UP
},
{
PIN_KEY_DOWN
},
{
PIN_KEY_A
},
{
PIN_KEY_B
},
{
PIN_KEY_X
},
{
PIN_KEY_Y
},
{
PIN_KEY_LEFT_TRIGGER
},
{
PIN_KEY_RIGHT_TRIGGER
}
};

Дело в том, что в нашем проекте недостаточно иметь лишь одно булево: нажата-ли кнопка или нет, для компенсации дребезга кнопок у нас также реализуется задержка перед следующей проверкой и дополнительное состояние для удобства реализации меню — «только что отпущена».

void CInputService::Tick()
{
timeStamp = get_absolute_time();

for(int i = 0; i < ButtonMappingCount; i++)
{
CButtonState* buttonState = &ButtonMapping[i];
bool gpioState = !gpio_get(buttonState->GPIO); // Buttons are pull-up to high when not pressed

// Check if there was elapsed enough time
if(timeStamp > buttonState->LastStateChange)
{
if(buttonState->State == EKeyState::ksReleased)
buttonState->State = EKeyState::ksIdle;

if(buttonState->State == EKeyState::ksIdle && gpioState)
buttonState->State = EKeyState::ksPressed;

if(buttonState->State == EKeyState::ksPressed && !gpioState)
buttonState->State = EKeyState::ksReleased;

buttonState->LastStateChange = timeStamp + KEY_DEBOUNCE_THRESHOLD;
}
}
}

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

EKeyState CInputService::GetKeyState(EKeyCode keyCode)
{
uint32_t code = (uint32_t)keyCode;

if(keyCode >= ButtonMappingCount)
return EKeyState::ksIdle; /* Maybe we should throw an exception? */

return ButtonMapping[code].State;
}

int CInputService::GetAxis(EInputAxis axis)
{
EKeyCode a = EKeyCode::keyLeft;
EKeyCode b = EKeyCode::keyRight;

if(axis == EInputAxis::inputAxisVertical)
{
a = EKeyCode::keyUp;
b = EKeyCode::keyDown;
}

return GetKeyState(a) == EKeyState::ksPressed ? -1 : (GetKeyState(b) == EKeyState::ksPressed ? 1 : 0);
}

А вот и результат:

❯ Запуск программ

Вот мы и подошли к, возможно, самой интересной подсистеме в нашем BIOS'е. Думаю многие читатели так или иначе интересовались тем, как же компилятор и линкер превращают исходный код и объектный файлы в пригодные для выполнения программы и библиотеки. Вопрос запуска нативных программ на микроконтроллерах интересовал и меня — я даже написал целых три статьи об этом: в первой мы поговорили о ESP32 и Xtensa, а во второй реализовали BinLoader путём реверс-инжиниринга и хакинга кнопочного телефона, а в третьей сделали полу-универсальный ElfLoader для нескольких моделей телефонов на разных платформах.

Но начнём мы с простого. Каждая программа делится на три основных секции:

  • .text — содержит в себе машинный код функций и так называемые Literal pools. Может быть как в ROM, так и в RAM. На системах, где есть возможность выполнять код и в ROM, и в RAM, есть отдельная секция - .iram.

  • .data — содержит инициализированные переменные, которые обычно попадают в оперативную память. Для статических констант есть отдельная секция, называемая .rodata.

  • .bss — содержит в себе не-инициализированные переменные, обычно это нули. В исполняемый файл секция .bss напрямую не записывается, остаётся лишь информация о том, каков её размер, а саму секцию затем выделит динамический линкер.

Куда попадут части программы определяет специальная утилита — линкер, которая на основе специального скрипта «раскладывает» данные по нужным секциям. Благодаря этому скрипту, мы можем, например, перенести часть функций в оперативную память для более быстрого исполнения или добавить в начало программы заголовок с описанием приложения.

В моём случае, я решил загружать игры в SRAM и дабы не реализовывать нормальный динамический линкер и релокации, решил выделить под игру фиксированный кусочек оперативной памяти объёмом в 128КБ. Для этого я отредактировал скрипт линкера Pico C SDK так, чтобы сразу после вектора прерываний шла наша программа:

. = ALIGN(4);

.ram_vector_table (NOLOAD): {
*(.ram_vector_table)
} > RAM

iram_program_reserve_size = 128K;

.iram_program (NOLOAD) : {
. = ALIGN(4);
PROVIDE(iram_program_origin = .);
. += iram_program_reserve_size;
} > RAM

.uninitialized_data (NOLOAD): {
. = ALIGN(4);
*(.uninitialized_data*)
} > RAM

Для компиляции программы также используется кастомный скрипт для линкера и особый Makefile, где после сборки программы мы копируем все её секции в выходной файл в «сыром» виде. Поскольку программа собирается под выполнение из конкретного адреса — пока речь идёт о переносимости только между одной аппаратной платформой. На RP2040, RP2350 и возможно STM32 такое «прокатит», но вот на других ARM-процессорах — большой вопрос!

OUTPUT_FORMAT("elf32-littlearm")


SECTIONS
{
. = 0x200000c0;

.program_info : {
*(.program_info*)
}

.text : {
*(.vtable*)
*(.text*)
*(.rodata*)
*(.data*)
*(.bss*)
}

/DISCARD/ : {
*(.ARM.*)
*(.comment*)

}
}

Каждое приложение, как и базовая система, предполагает использование ООП и поэтому представляет из себя реализацию класса IApplication. Для этого нам нужна некоторая runtime-поддержка: аллокатор, функция для создания экземпляра приложения, а также указатель на ISystem. Именно поэтому каждая программа должна экспортировать специальный заголовок, где содержится указатель на функцию-инициализатор:

#define PROGRAM_HEADER 0x1337
#define PROGRAM_INFO(name, clazz) int test; CAllocator* __Allocator; IApplication* __createInstance(CAllocator* allocator, ISystem* systemPtr) { __Allocator = allocator; return new clazz(systemPtr); } \
CProgramInfo __program_info __attribute__ ((section(".program_info"))) = { PROGRAM_HEADER, BIOS_VERSION, name, &__createInstance };

struct CProgramInfo
{
uint32_t Header;
uint32_t BIOSVersion;
CAnsiChar Name[32];

CreateApplicationInstanceFunction CreateApplicationInstance;
};

...

PROGRAM_INFO("Blink", CBlinkApplication)

Таким образом, для выполнения нашей программы и вызова её обработчиков событий нам достаточно лишь загрузить файл по адресу 0x200000c0 и создать экземпляр IApplication. Всё очень просто и понятно!

CAllocator allocator;
allocator.Alloc = malloc;
allocator.Free = free;

IApplication* app = ((CProgramInfo*)ptr)->CreateApplicationInstance(&allocator, System);

Но "моргалка" ведь слишком просто, согласитесь? Поэтому мы с вами напишем ремейк классической игры Змейка, которая работает в настоящие 60 FPS!

❯ Заключение

Вот таким нехитрым образом я понемногу реализовываю свою мечту детства: «андерграунд" консоль собственной разработки. Конечно здесь ещё много чего нужно доделывать перед тем, как начинать разводить свою плату, но начало ведь положено! В контексте GamePi13, я считаю что моя реализация SDK для консоли всё таки немного лучше, чем то, что предлагает производитель «из коробки».

Я понимаю что мой не совсем трушный эмбеддерский подход может вызвать разные ощущения у читателей: так что приглашаю всех заинтересованных в комментарии, обсудим с вами «сломанный Branch-prediction из-за виртуалов», «UB из-за того, что порядок указателей на реализации в VMT может отличаться» и «какого фига игры у тебя оказались в SRAM, а высокопроизводительный код на Flash, если у XIP кэш всего в 16КБ!».

А если вам интересна тематика ремонта, моддинга и программирования для гаджетов прошлых лет — подписывайтесь на мой Telegram-канал «Клуб фанатов балдежа», куда я выкладываю бэкстейджи статей, ссылки на новые статьи и видео, а также иногда выкладываю полезные посты и щитпостю. А ролики (не всегда дублирующие статьи) можно найти на моём YouTube канале.

Если вам понравилась статья...

И у вас появилось желание что-то мне задонатить (например прикольный гаджет) - пишите мне в телегу или в комментариях :) Без вашей помощи статьи бы не выходили! А ещё у меня есть Boosty.

Что думаете о таком формате статей?
Всего голосов:
Если бы я собрался с духом и произвел 20-50 штучек консолей-самоделок с полностью готовым SDK, примерами и туториалами, купили бы себе такую
Всего голосов:
Что думаете о таком проекте?
Всего голосов:

Подготовлено при поддержке @Timeweb.Cloud

Показать полностью 18 3
[моё] Опрос Покупка Гаджеты Нужно ваше мнение Консоли Игры Своими руками Arduino Инженерия Программирование C++ Arm Raspberry Pi Гифка Длиннопост
75
67
IcyFemida

Мне стало одиноко работать за компом, и я "поселил" на рабочий стол пиксельного кота. Делюсь с вами⁠⁠

1 месяц назад

Привет, Пикабу!

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

Я всегда с теплотой вспоминал старые "Тамагочи" и подумал: а почему бы не сделать что-то подобное, но для рабочего стола?

Так родился The Desktop Cat — мой небольшой, но сделанный с душой проект. Это маленький пиксельный котик, который живет прямо на вашем экране, поверх всех окон, и требует немного вашей заботы.

Что он умеет:

  • Жить своей жизнью: Котик просто сидит, спит, иногда просит кушать. Его можно взять мышкой и перетащить в любое место на экране.

  • Требует заботы: У него есть показатели голода и счастья. Не забывайте его кормить, иначе он загрустит!

  • Кастомизация: Вы можете дать ему уникальное имя и настроить цвет виджета со статистикой, чтобы он подходил под ваши обои.

  • Всегда с вами: Он работает поверх всех окон, будь то игра, браузер или код.


Проект полностью бесплатный и с открытым исходным кодом, написан на Unity. Я сам его сейчас использую, и работать стало как-то веселее :)

Зачем я это пишу?
Очень хочется поделиться этим маленьким позитивным проектом с вами. Буду невероятно рад, если он кому-то поднимет настроение. И, конечно, я активно его развиваю, так что любой фидбэк или идеи (может, добавить собачку?) — бесценны!

  • Следить за проектом в Telegram: https://t.me/desktopcat

  • Скачать готового котика (для Windows): https://github.com/Lixher/Desktop-Cat/releases

  • Для любопытных разработчиков (и для звезд ⭐): https://github.com/Lixher/Desktop-Cat

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

Показать полностью 2
Своими руками Кот Unity Программирование Полезное Длиннопост Милота Гифка Telegram (ссылка)
24
11
IcyFemida
Серия Diagrammer

Меня достал PowerPoint, и я написал Telegram-бота, который рисует схемы за меня. Делюсь с вами⁠⁠

1 месяц назад

Пример

UPD: Ребята, спасибо за активность! Ссылки на бота и GitHub для удобства оставил в закрепленном комментарии и в самом конце поста.

Привет, Пикабу!

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

Каждый раз это превращалось в ритуал: найди Visio, открой PowerPoint, разберись в онлайн-редакторе... В итоге тратишь полчаса на то, чтобы нарисовать три квадратика и две стрелочки.

В какой-то момент я психанул и подумал: «Какого черта я не могу делать это там, где и так сижу целыми днями — в телеге?»

Так и родился Diagrammer Bot — мой небольшой проект, который я пилил по вечерам. Изначально делал чисто для себя, но, кажется, получилось что-то, чем не стыдно поделиться с людьми.

Что эта штука умеет (постарался сделать максимально просто и мощно):

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

2. Полный цикл работы: создал, соединил, ошибся, исправил.
Можно не только добавлять блоки, но и удалять их, редактировать текст, убирать неправильные стрелки. Всё через удобные кнопки.

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

4. Темы и экспорт.
Есть светлая и темная темы, которые переключаются на лету. А когда схема готова — одной кнопкой скачивается PNG-файл в высоком разрешении для презентаций или чего угодно.

Для тех, кому интересно, как это работает:
Под капотом крутится Python, асинхронщина на python-telegram-bot, а за отрисовку отвечает старый добрый Graphviz. Самой большой болью было научить его правильно находить картинки на диске и не создавать пустые файлы, когда в схеме нет стрелок. Но вроде победил :)

Весь код открыт и лежит на GitHub, так что если вы тоже кодер — милости прошу.


Зачем я это все пишу?

Во-первых, буду дико рад, если бот кому-то из вас пригодится и сэкономит время. Он полностью бесплатный.
Во-вторых, очень хочется услышать ваше мнение. Может, есть идеи, какую фичу добавить следующей? Или что-то работает криво? Любой фидбэк будет бесценен.

  • Ссылка на самого бота (просто нажми Start): https://t.me/diagrammer_robot

  • Для любопытных — ссылка на GitHub (буду рад звездочке ⭐): https://github.com/Lixher/diagrammer-bot

Спасибо, что дочитали! Не топите :)

Показать полностью 2
Программист Своими руками Программирование Telegram Бот Полезное Python Гифка Telegram (ссылка) Длиннопост
24
78
Webnout
Arduino & Pi

Ответ на пост «Часы из часов на дисплее из дисплеев»⁠⁠1

2 месяца назад

Доброго времени суток Вам, уважаемые Пикабушники.

Почти три года назад Алекс Гайвер разработал безумно интересный и, на мой взгляд, самый недооцененный фанатами проект - "Часы из часов на дисплее из дисплеев!". Но, проект так и остался демонстрацией возможностей дисплея.

Со своими сыновьями собрали его, подшаманили скетч и часы получились (все исходники предоставлю в конце поста). Плюс, Часы научились показывать температуру на улице, температуру/влажность/давление в доме. Делюсь, вдруг кто-то захочет повторить это сам или со своими детьми. На момент сборки моим мальчишкам было 11 лет и они, вполне нормально управляются с паяльником, поэтому думаю, что с возраста 10+ детям будет интересно, тем более, что процесс сборки/пайки очень интересен, да и результат впечатлит. Также, думаю, что проект может быть интересен какому-нибудь школьному кружку Самоделкиных, если такие ещё остались в школах, т.к. часы собираются модульно и коллективное творчество тут вполне уместно. У меня остался комплект плат (9 шт. и одна прозапас), поэтому с радостью подарю их какому-нибудь школьному кружку - пишите.

Часы получают время и погоду из интернета, поэтому должны быть подключены к сети Wi-Fi.

Результат (часы, которые у вас получатся):

Вживую выглядят намного интереснее, чем на фото.

Вживую выглядят намного интереснее, чем на фото.

Видео работы часов.

Перейти к видео

В скетче символы "С" у температуры уже заменил на U (улица) и D (дом), но всё никак не перезалью в часы... (((

Ну и немного фото/видео сборки:

1/2

Нанесли паяльную пасту. Припаивал только крайние ножки микросхем, с остальными справлялись сыновья.

1/6

Собираем всё в кучу.

Первые тесты:

Перейти к видео

Исходники можно скачать ЗДЕСЬ. Там всё понятно и с комменатриями.

//

Что и у кого заказывал:

1) Печатные платы. Заказывал ЗДЕСЬ. Вы пишите продавцу. Отправляете ему архив SMD.zip из папки PCB, он считает и говорит, сколько это будет стоить. Для сборки проекта нужно 9 плат, но лучше заказать одну прозапас, мало ли что...

2) Дисплеи заказывал ЗДЕСЬ. Всего нужно 36 дисплеев.

3) NodeMCU (1 шт.) - заказывал ЗДЕСЬ.

А вот дальше товары, которые покупал - уже недоступны, поэтому просто ищу на али, но можете поискать и сами.

4) Конденсаторы 50 В, 10мкФ (нужно 18 шт.), но они продаются по 50, благо стоят недорого - ССЫЛКА

5) Драйвер max7219 (нужно 18 шт.) - ССЫЛКА

6) Резистор 10 кОм (нужно 18 шт.) - ССЫЛКА

7) Датчик температуры/влажности/давления BME 280 (1 шт.) - ССЫЛКА

8) Блок питания можно не покупать, а запитать часы от нормального зарядника для телефона (5 вольт и 3 ампера хватит с запасом).

В принципе всё. Всем добра!

Показать полностью 9 2
[моё] Alexgyver Своими руками Самоделки Программирование YouTube Arduino Электроника Техника Видео Короткие видео Ответ на пост Длиннопост
4
pavelfokin
pavelfokin
ИТ-проекты пикабушников

Меня бесят голосовые, и я за выходные навайбкодил своего первого телеграм-бота, который их расшифровывает⁠⁠

2 месяца назад

Привет! Хочу поделиться как я сделал своего первого телеграм-бота, бота для транкрибации голосвых. Сначала, конечно, я посмотрел какие похожие боты есть, но те, которые нашёл, мне не понравились, неудобно или медленно. И я решил что жизненно необходимо запилить своего.

👀 Какие телеграм-боты транскрибации смотрел

Когдя я искал существующие боты для рашифровки голосовых, то посмотрел несколько.

Telegram Premium. Не бот, но есть транскрибация голосовых, возвращает полотно текста. Если это “Привет, как дела?”, то ок. Но если голосовое минуты на 2–3, то читать сложно.

Буквица. Тоже стена текста.

Briefly. Если текст длинный, то сразу даёт саммари, а транскрипция трудно читаема (сохраняет повторы, мусорные слова).

Silero STT. Сплошной текст вперемешку с таймкодами. Неудобно читать.

Whisper Summary AI. Присылает несколько сообщений сразу: ссылки на гугл-док, сплошной текст, разделение на спикеров и таймкоды. Круто, конечно, но опять не то, что надо.

Voicee_AI_Bot. Для голосового на 20 секунд присылает ссылки на PDF, DOCX, TXT, отдельное сообщение с предложением создать интерактивную версию, отдельное сообщение с вариантами обработки. Транскрипция без абзацев. Спасибо большое!

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

С чего начать? Конечно же c ИИ.

🤖 ИИ, ИИ, ИИ…

Первое, что сделал, конечно, посоветовался с электронным помощником:


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

И вот такой итоговый план:

  • Регистрируешь бота через @botfather.

  • Выбираешь Whisper API как основной движок.

  • Пишешь логику на Python + Aiogram.

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

  • Размещаешь на шустром VPS в Европе.

Ок, звучит просто.

Потом ещё несколько итераций я общался про UX и взаимодействие с пользователем. Старался утрясти своё видение, что значит идеально и что я хочу получить от бота.

То есть, как я себе представляю идеальный процесс. Отправляю голосовое, и максимально быстро вижу результат. Без всяких, “это может занять несколько минут…”, “вы 15-й в очереди…”, или просто молчание, когда непонятно, что происходит. Результат — это отформатированный текст, который сохраняет стиль говорящего и который удобно читать. Ну и в целом хочется, чтобы взаимодействие с ботом было ненапряжным.

Из чатов с чатом я выделил три фокуса:

  • UX. Минимальный, понятный, ненавязчивый.

  • Скорость это важно. Стремится к минимальному TTFB, ну или давать пользователю знать, что происходит, и не пропадать из чата.

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

Удобно. Быстро. Безопасно.

💅 UX важнее фич

С UX всё понятно, чем меньше кликов, экранов и непонятных шагов, тем лучше. Скинул голосовое — получил текст.

UX должен быть невидимым. Лучший интерфейс это его отсутствие

Хорошо сказано.

Скорость ответа воспринимается как качество. Бот должен экономить время. Есть скорость техническая, а есть скорость восприятия действия человеком. Слишком упарываться в техническую оптимизации не хотелось, всё-таки это только первая итерация. Поэтому два UX-момента:

  1. Присылать реакцию бота и обновления статуса как можно быстрее. Но со статусами мельтешить тоже не стоит, раз в 2 секунды достаточно.

  2. Стримить ответ от LLM и редактировать сообщение в телеграм. Тут главное соблюдать лимиты Telegram API.

Кроме того, UX бота выражается и в его характере.

🧐 Характер бота

Хотя функций у бота минимум, всё равно есть взаимодействие: приветственное сообщение, сообщение об ошибке и т.д. И хочется, чтобы бот был в общении приятным «человеком» и чтобы стиль ответов оставался одинаковым.

Поэтому важно продумать его характер (tone of voice).

С помощью ИИ я сгенерировал такой промт, который использовал для генерации сообщений от бота:

Твоя личность — это личность компетентного, эффективного и немного ироничного личного помощника. Придерживайся следующих принципов:

1. Компетентность превыше всего: Будь точным, ясным и уверенным. Говори по делу.

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

3. Ты — союзник пользователя: Ты на его стороне в борьбе с потерей времени. Всегда подчеркивай его выгоду.

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

5. Говори от первого лица: Всегда используй "я" ("я заметил", "я сделал", "я предлагаю").

# ЧЕГО СЛЕДУЕТ ИЗБЕГАТЬ

- НЕ извиняйся и не заискивай. Не используй фразы вроде "к сожалению", "простите".

- НЕ будь фамильярным. Никакого сленга.

- НЕ будь негативным. Вместо проблемы всегда предлагай решение.

Теперь про технику.

🛠 Техстек

Хоть ИИ и бро, но техстек я чутка поменял.

Вместо aiоgram выбрал python-telegram-bot, потому что больше звёзд на гитхабе и звучит солидно.

Вместо VPS в Европе, деплой в Railway в европейский регион. Минимально движений с инфраструктурой.

Для базы решил использовать Turso. Никогда не пробовал, интересно, как оно. Всё-таки у меня MVP из палок и глины.

OpenAI как провайдер моделей: для spech-to-text использую whisper-1, для обработки транскрипций gpt-4o-mini.

Можно начинать кодить. Погнали!

☕ Вайбкодинг

Запустил Сursor и создал простую структуру проекта, чтобы ИИ было проще не терять контекст:

/bot

__init.py__

bot.py

config.py

db.py

llm.py

models.py

stt.py

stream.py

usage.py

users.py

main.py

README.txt

requirements.txt

Дальше, самая лёгкая часть. Пишу в чат, что мне надо, пью чай, пока иишка трудится. Иногда перезапускаю Сursor потому, что агент начинает бредить.

Использовал в основном gemini-2.5-pro.

Алгоритм простой:

[ Голосовое ]

│

▼

[ Скачиваю в память ]

│

▼

[ Whisper-1 → транскрибация ]

│

▼

[ GPT-4o-mini → форматирование/саммари ]

│

▼

[ Готовый текст пользователю ]

│

▼

[ PROFIT 🚀 ]

С ORM не стал заморачиваться, просто запросы в базу, данные мапятся в dataclass-ы.

Тестов не вайбкодил.

🔒 Конфиденциальность

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

По кнопке можно удалить все тексты, которые бот сохранял для работы.

🙏 Итог. Нужен твой фидбек

Получилось ли сделать идеальный бот для одной функции? Не знаю. Сделать, сделал, а пользователей потестить нет.

Бот @VoxitoBot. Говорить - проще. Читать - легче.

Если попробуетe и дадите фидбек, буду очень благодарен. 🙌

Интересно и общее ощущение от UX, и может что упадёт, и что будет если больше одного пользователя будет одновременно.

Пишите ваше мнение в комментариях!

Да, и для MVP ограничение на длину голосового — 5 минут.

P.S. Эту статью я изначально опубликовал на VC.ru вот ссылка.

Показать полностью 2
[моё] Python Своими руками Программирование Telegram Голосовые сообщения Длиннопост
10
5
AndreyU24

Удаленное управление ESP32 и другими IoT-устройствами⁠⁠

2 месяца назад

Всем привет!

Хочу показать небольшой проект, над которым сейчас работаю — MicroComm.

«Это сервис для тех, кто создаёт IoT-устройства, — он будет полезен как профессиональным разработчикам, так и DIY-любителям».

IoT — это сокращение от Internet of Things, что в переводе с английского означает «Интернет вещей».

Примеры применения IoT:

- Умный дом (умные лампочки, термостаты, камеры наблюдения).

- Промышленный IoT (IIoT) — мониторинг оборудования, предиктивное обслуживание.

- Сельское хозяйство — датчики влажности почвы, автоматический полив.

- Медицина — носимые устройства для отслеживания состояния здоровья.

- Транспорт — системы умного транспорта, GPS-трекеры, подключённые автомобили.

С помощью MicroComm можно легко организовать связь со своим устройством через интернет:

  • отправлять команды на устройство удалённо,

  • получать ответы с результатами выполнения,

  • видеть полную историю: что отправляли, когда, какой был ответ и были ли ошибки.

Кроме того, устройство может присылать собственные логи — а в будущем вы сможете работать с ними через API (например, для аналитики или отладки).

Всё это работает «из коробки»: не нужно страивать серверы, писать бэкенд или разбираться со сложными протоколами. Просто создаете устройство на сайте, выбираете подходящий клиент и управляете своим устройством через веб или API.

В основном работаю с Python, поэтому написал клиент для ESP32 на MicroPython.

Кто знаком с MicroPython, можете попробовать: https://microcomm.ru/pages/clients/micropython/
Есть еще набросок клиента на Python: https://microcomm.ru/pages/clients/python/

Для Arduino клиента пока нет, в будущем появится (хотя, с него и надо было начинать)

На видео я через веб-интерфейс вызываю команду (RAND_COLOR) ESP меняет цвет светодиода и возвращает результат выполнения.

Перейти к видео

Спасибо, что прочитали этот пост до конца!

Буду рад любым комментариям — советам, вопросам, предложениям.

Показать полностью 1
[моё] IT Программирование Python Программист Linux Arduino Своими руками Видео Короткие видео
1
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии