Порт zwift-jersey на tiny85

В процессе поисков связанных с Zwift проектов наткнулся на https://github.com/pete911/zwift-jersey – автоматизацию ввода промо-кодов в Zwift’e на базе Arduino. Открыл для себя тогда, что у Arduino бывают разные контроллеры для связи с USB и “не все Arduino одинаково полезны” – точнее, не все могут выступать в роли USB HID-устройств без дополнительных манипуляций. На тот момент купил пару Arduino Leonardo, прошил в одну из них скетч по ссылке, повводил коды во всех аккаунтах и на том успокоился.

Лежащая без дела Leonardo (не самая дешевая плата) мозолила глаза возле велостанка, а с учетом того, что в последнее время стал активнее разбираться с работой простых микроконтроллеров (tiny13, tiny85), решил попробовать реализовать тот же проект на плате подешевле.

Tiny85 были куплены задолго до того “про запас”, часть из них была в исполнении с разведенным на плате USB-разъемом. На ней и ставил эксперименты.

У tiny85 512 байт памяти и 8 КБ флеша, из которых примерно 1.5 КБ занято под загрузчик, который и позволяет шить контроллер через USB-порт без каких-либо дополнительных устройств. В отличие от Leonardo, тут нет отдельного чипа, который выступал бы в качестве USB HID, поэтому для работы в проекте используется V-USB. Для работы в качестве клавиатуры используется готовая библиотека DigisparkKeyboard, взять которую можно по этой ссылке (digistump-avr/libraries/DigisparkKeyboard разместить в ~/Arduino/libraries/DigisparkKeyboard).

Первая проба самая очевидная: берем оригинальный скетч, подключаем библиотеку, заменяем “Keyboard.print” на “DigiKeyboard.print”, пробуем. Облом: “Global variables use 935 bytes (182%) of dynamic memory, leaving -423 bytes for local variables. Maximum is 512 bytes.”. Оперативки контроллеру не хватает под хранение массива такого размера. Если сделать список вполовину меньше – все начинало работать. Флеша в оригинальном варианте занималось 5250 байт.

Дальше пошли эксперименты. Если массив не влазит в память – можно избавиться от массива. Вручную разворачиваем цикл, печатая по блоку для каждой записи в списке. 563 байта (109%) – уже лучше. Вспоминаем, что строковые константы дефолтно копируются в оперативную память. Обрамляем все строки в списке в F(). Теперь всего 95 байт! Собственно, на этом можно было бы и закончить, но так как на самом деле путь был более долгим и накопилось немного статистики по разным вариантам кода, то запишу и ее:

  • Для начала сократил “обвязку” вокруг ввода кода – печатал “p” напрямую перед кодом, использовал DigiKeyboard.println. Добавил мигание светодиодом на каждый введенный код. В принципе работало, но Zwift любит тормозить в произвольных местах, так что иногда случалось “залипание” клавиш и не все коды срабатывали.
  • Оформил функцию, которой передавалась строка с кодом для Zwift’а. Внутри функции – все необходимые паузы. 105 RAM / 5806 flash.
  • В библиотеке рекомендовали использовать DigiKeyboard.delay для пауз. Однако замена его на обычный delay() позволяет экономить 70 байт флеша.
  • Если в оригинальную функцию мигания светодиодом не передавать одну из переменных – адрес светодиода – а просто прописать LED_BUILTIN (у нас ведь нет других светодиодов), это экономит 30 байт флеша.
  • Если убрать в функции печати кода все паузы, мигание светодиода, а “р” печатать непосредственно в коде, то экономится только 100 байт флеша. Зато если убрать функцию вообще и просто plaintext’ом накопировать блоки в основную часть кода (пока без пауз) – выходит уже 4442 байта (в этом моменте еще использовал отдельную функцию для мигания светодиодом в процессе работы и библиотечный delay). Использование оригинальной функции мигания и обычного delay дало 4230 байта.
  • Задержка перед миганием в оригинальной функции занимает дополнительные 16 байт флеша.
  • Итоговый plaintext-вариант со всеми корректными задержками – 95 RAM / 5552 flash. И если не мигать светодиодом в процессе ввода кодов – 5250 flash.

Код:

tiny85_zwift_lowmem_ultimate.ino

 

Одна мысль про “Порт zwift-jersey на tiny85”

Добавить комментарий