Как стать автором
Обновить
0

Как управлять FM-вещанием через iPhone

Время на прочтение16 мин
Количество просмотров11K


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


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


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


Кратко наш путь выглядит так:


  • Уровень 0: git clone fm_transmitter
  • Уровень 1: поиск готовых систем fm-вещания для дальнейшей модификации
  • Уровень 2: железный хакинг

Уровень 0: git clone fm_transmitter


Часто для того, чтобы понять, как нужно делать что-то правильно, нужно просто начать это делать. Мы начали с поиска существующих проектов в GitHub по управлению fm-передачей (google: site:github.com "fm transmitter"). И сразу же вышли на живой проект — https://github.com/markondej/fm_transmitter, позволяющий вещать радио посредством подключенного к GPCLK(General Purpose Clock) пину Raspberry PI провода. Протестировав работоспособность проекта на реальном радио и услышав свою мелодию вместо оригинальной радиостанции, на минуту показалось, что дело сделано, и задачу в Jira вот-вот можно будет закрывать.


Оставалось только придумать интерфейс взаимодействия с RPi через мобильное приложение. Выбрали классический в мире IoT подход: WiFi AP + веб-приложение. Во вселенной Opensource был быстро найден подходящий проект rpi-hostap, позволяющий в пару кликов развернуть WiFi Access Point с нужной конфигурацией на Raspbian и с веб-приложением внутри локальной сети AP (со статическим IP), к которому бы стучалось iOS-приложение, управляющее радио.


+Веб-приложение


Веб-приложение реализовано на базе Python-фреймворка Flask и содержит следующие HTTP-эндпоинты для управления радиовещанием:


  • /setfreq?freq=<частота вещания в Mhz> — установка нужной fm-частоты
  • /start?audio=<название> — запуск вещания выбранного аудио на ранее заданной частоте
  • /stop — остановка вещания
  • /seek?perc=<% проигрывания> — промотка аудио на нужное место
  • /repeat?enable=<bool> — включение/отключение повторения при завершении аудио
  • /sync — получение текущей информации о ходе проигрывания
  • /upload — загрузка нового аудио

Этот интерфейс не предполагалось использовать в многопользовательском режиме, однако для надежности все методы были защищены общим threading.Lock-объектом: одновременно можно было вызывать только какой-то один из методов.


+Мобильное приложение


После появления HTTP-интерфейса уже можно было общаться с RPi множеством различных способов. Нашей конечной целью было управление fm-вещанием через iPhone:


скриншот мобильного приложения
Структура iOS приложения


На этом этапе у нас был полностью готовый прототип fm-трансмиттера с интерфейсом, позволяющим его легко тестировать в разных локациях. До текущего момента все тесты проходили в помещении офиса, что давало дальность вещания до 20 метров. Но после серии уличных тестов выяснилось, что даже 5-метровый радиус получается гарантировать не всегда…


+Удлинение GPIO-провода


Мы стали пытаться увеличить дальность вещания путем удлинения GPIO-провода, отходящего от GPCLK-пина. Увеличение дальности оказалось незначительным.


-Удлинение GPIO-провода+ стереоскопическая антенна


Для еще большего увеличения дальности решили попробовать стереоскопическую антенну. Чтобы её использовать, был необходим переход с GPIO пина на контур антенны. В этот момент мы впервые достали паяльник, но пока не подозревали, что станем с ним неразлучны до конца проекта. Это дало результат как минимум не хуже предыдущего, но теперь стало удобнее эксплуатировать антенну.


+Усилитель для стереоскопической антенны


Было очевидно, что GPCLK-пин Rasberry "не вытянет" нужной мощности вещания без дополнительной помощи. После небольшого ресерча выяснилось, что такая "помощь" существует — SPF5189Z. Это усилитель сигнала, использующий внешнее питание. Добавили этот компонент в разрыв между переходником и антенной:


фото усилителя + антенны
Усилитель SPF5189Z для антенны с питанием от USB и переходником на GPIO


Снова разогрели паяльник для пайки переходника питания усилителя через USB с того же Powerbank, с которого питался RPi, после чего разместили все в картонной коробке для удобства эксплуатации. На этот раз дальность вещания была увеличена с нестабильных 10 метров до стабильных 15 метров на улице, чего едва хватало.


Finale: -fm_transmitter


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


Уровень 1: поиск готовых систем fm-вещания для дальнейшей модификации


"Уровень 0" привнес интерфейс управления, независимый от железа, поэтому мы могли смело отказаться от использования проекта fm_transmitter и поискать другой способ организации fm-вещания.


У нас не было желания строить собственный велосипед из fm-вещателя и усилителя, поэтому мы решили отыскать готовую систему и немного её "подпилить" под себя. Интернет-разведка привела нас к китайской компании CZERF, занимающейся беспроводными технологиями. В ассортименте продуктов, выпускаемой данной компанией, было обнаружено интересное устройство — fm-трансмиттер на 7 ватт с кнопочным управлением (2 кнопки на выставление частоты ▲/▼ и кнопка питания) и audio-jack'ом — CZERF-7C (официальный сайт кидается 500 ошибкой). Такая мощность позволила бы в десятки раз увеличить дальность в условиях улицы. Задача сводилась к связыванию проприетарного прибора малоизвестной китайской компании с RPi.


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


фото платы с красным выделением контроллера и радиомодуля
Внутренности прибора (1 — радиомодуль, 2 — микроконтроллер)


+RPi Relay Board


Под рукой уже был разогретый Raspberry PI с "Уровня 0", поэтому мы пришли к идее имитации нажатий на кнопки устройства с помощью GPIO-реле. Это реле предоставляло очень удобный интерфейс управления — достаточно насадить реле на GPIO-шину RPi, после чего посылать сигнал на один из пинов GPIO Raspberry, как нужное реле замыкает цепь подобно оригинальной кнопке:


RPi.GPIO.output(RELAY_PIN, RPi.GPIO.HIGH)
time.sleep(0.03) # минимальное удерживания кнопки, которое воспринимает контроллер
RPi.GPIO.output(RELAY_PIN, RPi.GPIO.LOW)
time.sleep(0.03)

Потребовалась серьезная переработка веб-приложения (без изменения HTTP-интерфейса): теперь при вызове /setfreq(установка частоты) нужно было запускать фоновую задачу по "нащелкиванию" нужной частоты, а при вызове /start(запуск проигрывания) — дожидаться выставления частоты и запускать фоновое аудио, которое бы по audio-jack уходило бы с RPi в радиомодуль (до этого аудио-сэмплы читались из файла без непосредственного проигрывания на RPi).
За дальность вещания пришлось расплатиться скоростью выставления частоты — за одну имитацию нажатия на управляющие кнопки происходило изменение частоты на 0.1Mhz. Если, например, нужно с частоты 90Mhz переключиться на 105Mhz, потребовалось бы ждать (105-90)*10*(0.03*2)=9 секунд. Вдобавок к этому появилось щелканье реле на протяжении всего времени переключения частоты и необходимость запоминания частоты программно, так как из кода не было никакой связи с реальной("железной") частотой на устройстве.


Но тем не менее самой большой проблемой оказалось другое — наводки. 7-ваттная антенна fm-вещателя оказывала на реле крайне негативное воздействие: в какие-то редкие моменты могли происходить случайные переключения частоты вверх или вниз из-за наводок. С учетом отсутствия обратной связи с реальной частотой на устройстве, код мог "думать", что нужная частота "нащелкана", когда на самом деле нет.


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


фото реле на rpi
Управление прибором с RPi Relay Board


-RPi Relay Board + Оптроны


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


Мы отыскали несколько элементов, функции которых аналогичны реле:



Твердотельное реле с интерфейсом, подобным RPi Relay Board, найти не получилось. Стало понятно, что так или иначе придется мастерить собственную схему управления, поэтому оптрон оказался самым подходящим решением: "тихий", компактный, дешевый и легкодоступный. Принцип его работы крайне прост: при подаче тока на светодиод открывается выходной транзистор и замыкает ножки 4 и 3 для протекания тока в цепи.


Набросали макет платы с 2 кнопками (кнопки частоты) на базе оптронов для замены реле:


схема монтажа
Схема управления v0


И достаточно быстро спаяли нулевую версию схемы на проводах:


фото монтажа на проводах
Схема управления v0: реализация


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


+Плата v1 + Экранированный провод + 3d-каркас


Наводки были последней крупной проблемой. На этом этапе не было никаких сомнений, что провода есть основной субъект наводок. Поэтому все силы были брошены на разработку полноценной платы управления, которая схематично была практически аналогична "схеме на проводах". В схему платы лишь было добавлено управление кнопкой питания fm-трансмиттера (тоже через оптрон), чтобы можно было управлять fm-вещанием с помощью веб-приложения на RPi (эндпоинт /start).


Схема первой версии платы получилась такая:


схема первой версии платы
Схема управления v1


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


фото собранной первой версии
Плата управления v1


Эта плата по нашим ожиданиям должна была устранить влияние помех. Для еще большей защиты от помех мы соорудили экранированный провод от этой платы до управляющих пинов RPi на основе кабеля типа CCC-4G.


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


фото двухэтажной платы в корпусе устройства
"Второй этаж" для перехвата управления с первого


А для удобства эксплуатации этой системы управления радиовещанием мы решили спроектировать и распечатать корпус на 3d-принтере. Он получился у нас двухкомпонентный:


  • Внешняя оболочка + крышка с отверстием для антенны
  • Внутренний скелет для плотного размещения элементов системы в оболочке

3d-каркас


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


фото итоговой коробки с вытянутой антенной
Мобильный fm-вещатель в собранном виде


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


+Оптрон управления вещанием — Плата v1 + Плата v2


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


Провели командный брейншторм, общий посыл которого был таков: "нужно найти способ устранения наводок, не требующий еще большего углубления в радиотехнику". Идеальным вариантом было бы обойтись уже полученными в ходе проделанной работы знаниями. И такой способ нашелся. Мы вспомнили, что к микроконтроллеру, связывающему кнопки и дисплей с радиомодулем, ведут целых 10 ножек, в то время, как мы знали назначение только 5 из них (3 кнопки, земля и питание) Управлять любой другой из них через оптрон — уже знакомый нам способ. Одна из ножек наверняка должна отвечать за питание самого радиомодуля, ответственного за вещание. Достали мультиметр и быстро вычислили эту ножку. Оказалось, можно, не отключая питание всего устройства, включать/выключать только вещание, когда это нужно. А значит у нас появилась возможность выставлять частоту до активного вещания, что позволит избавиться от остаточных наводок "непереключения". После пары экспериментов выяснилось, что память(текущая fm-частота) находится в микроконтроллере, а не в радиомодуле, поэтому, отключая питание радиомодуля, мы можем спокойно "нащелкать" нужную частоту на контроллере, после чего уже итоговая частота будет отправлена в радиомодуль.


Мы модифицировали первую версию платы, впаяв недостающий оптрон прямо на пластину платы, чтобы быстро провести тесты и оценить влияние наводок:


фото платы v1 с висящим оптроном
Плата управления v1.5


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


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


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


схема платы_v2
Схема управления v2


И заказали ее у производителя:


фото платы в корпусе и конденсаторами на кнопках
Плата управления v2 + фильтрующие конденсаторы на всех кнопках


Finale: -кнопочное управление


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


Мы обратили внимание, что наводки влияют только на те элементы, на пути которых встречаются кнопки. Так, на включение/выключение вещания, которым управлял только наш оптрон, наводки не влияли.


В итоге было решено окончательно погрязнуть в азах радиоэлектроники, чтобы стабилизировать работу устройства, отказаться от "нащелкивания" частоты и окунуться в мир hardware-reversing'а.


Уровень 2: Железный хакинг


Самая надежная деталь — та, которой нет.

Набив шишек на предыдущих этапах, захотелось разобраться, как же работает наше устройство на более низком уровне. Интерфейс кнопок оказался слишком проблемным, а чутье подсказывало, что кнопки — это лишь интерфейс пользователя для некоторого низкоуровневого интерфейса. Оставалось лишь найти этот низкоуровневый интерфейс.


+Осциллограф


Так как устройство CZERF-7C является проприетарным (мануала по внутренней работе платы найти нигде не удалось), пришлось выковыривать информацию о его работе самостоятельно.


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


фото ножек


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


Сразу же натыкаемся на уже известную нам проблему наводок — но теперь на осциллогаф. Пришлось приобрести экранирующую медную сетку и замотать в неё антенну fm-трансмиттера в ходе исследования сигнала осциллографом.


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


скриншоты pin2 pin3
Анализ пинов 2 и 3


скриншоты pin4 pin3
Анализ пинов 3 и 4


Захваченные сигналы возникают синхронно по времени, что очень похоже на некий протокол. Хоть устройство CZERF-7C и является проприетарным, отдельные его части открыты. Так, микроконтроллер, который управлял радиомодулем этого устройства, оказался программируемым STC11F02E с публичным datasheet, на основе которого получилось установить протокол — SPI. Это и есть искомый низкоуровневый интерфейс.


+SPI


Кратко SPI работает так:


  • Есть 3 линии данных — CS, MOSI и CLK.
    CLK MOSI
  • MOSI (master out slave in) — линия передачи данных от управляющего устройства к контролируемому (в нашем случае — от контроллера в радиомодуль)
  • CLK (clock) — линия передачи синхроимпульсов, которые говорят приемнику SPI, в какой момент делать считывание данных на линии MOSI. Данные могут считывается по переднему или заднему фронту импульса (а иногда и по обоим фронтам одновременно).
  • CS (chip select) — на этой линии выставляется низкий или высокий уровень, который говорит приемнику SPI(в нашем случае это радиомодуль), что пока выставлен уровень, будет происходить передача данных на линии MOSI и передача синхроимпульсов на линии CLK. Обычно разрешающим сигналом для CS является низкий уровень, а здесь используется высокий уровень. Дальше будет понятно, почему разработчики этого устройства так сделали.
  • Есть 4 режима работы, определяющих фронт считывания данных с CLK

В этом устройстве считывание происходит по переднему фронту (Mode 0). В посылке можно увидеть, что данные меняются по заднему фронту, значит задний фронт не используется для считывания данных — по протоколу данные не могут меняться при считывающем фронте. Лучше всего это видно на этом захвате сигнала:


захваченный фронт
Анализ режима работы SPI


Зеленый сигнал(внизу) — это MOSI, желтый(вверху) — CLK. Исходя из этого, можно установить назначение оставшихся 3 из 4 ножек: ножка 2 — это CS, 3 — CLK, 4 — MOSI.


+Декодирование "трафика"


Перехватим несколько посылок с разными заведомо известными частотами:


  • 102.6Mhz
  • 102.4Mhz
  • 92.9Mhz

Всего в посылке передается 16 бит. Можно заметить, что у этих сообщений не меняется хвостовая чаcть — последние 5 бит = 10010


Скорее всего это команда, которая устанавливает частоту, а данные передаются в первых 11 битах. Рассмотрим первые 11 бит двух соседних частот: 102.4Mhz и 102.6Mhz.


  • 102.4 Мгц
  • 102.6 Мгц

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


  • 102.4: 10000000000
  • 102.6: 10000000010

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


  • 102.4: 1024
  • 102.6: 1026

Для контроля, убеждаемся, что 92.9 — это 929: reverse(110000101110) = 011101000011 = 929.


Мы собрали достаточно информации для того, чтобы попробовать самостоятельно выставить нужную частоту новым методом. Осталось лишь "откусить" ножки CS, CLK, MOSI от головного микроконтроллера, забрав управление себе, и отладить отправку собственной посылки.


+Arduino. Взлом частоты.


Легче всего отладка будет протекать на максимально простом устройстве (RPi плохо подходит для этих целей). Подключаем Arduino к плате CZERF-7C:


фото Arduino с проводами


И пишем небольшой скетч, позволяющий отправить с Arduino посылку в режиме SPI:


#include <SPI.h>

void setup (void)
  {
    // инициализация SPI контроллера на arduino
    SPI.begin();
    // выставление частоты работы CLK, здесь ставится максимальный делитель частоты 128.
    // частота работы Arduino 16000000Гц. Значит частота синхроимпульсов будет 16000000/128 = 125000 Гц
    SPI.setClockDivider(SPI_CLOCK_DIV128);
    // установка режима работы SPI (mode 0)
    SPI.setDataMode(SPI_MODE0);
  }

void loop (void)
  {
      // выставляем высокий уровень на CS, ножка 10
      // инициализируем окно передачи сообщения по SPI
      digitalWrite(SS, HIGH);

      // 16-битная посылка
      const unsigned int freq = 0b0000000000110010;  // 102.4 Mhz

      // передаем посылку (https://www.arduino.cc/en/Reference/SPITransfer)
      SPI.transfer16(freq);

      // выставляем низкий уровень на CS, ножка 10
      // закрываем окно передачи данных по SPI
      digitalWrite(SS, LOW);

      // повторяем через 20 секунд
      delay (20000);
  }

Код до безобразия прост, но здесь стоит подробнее остановиться на режимах работы SPI. Для SPI есть 4 режима работы. Они отличаются фронтом считывания (передний или задний, на картинке ниже они показаны стрелками) и начиная с какого уровня стартует сигнал CLK (высокий или низкий)



Ранее мы выяснили, что CZERF-7C работает в режиме Mode 0(CPOL = 0, CPHA = 0), поэтому в настройках SPI: SPI.setDataMode(SPI_MODE0)


Запустив скетч на Arduino, каждые 20 секунд начала устанавливаться частота 102.4Mhz. Можно поменять константу freq, и частота после перезагрузки скетча будет меняться на неё.


-Arduino + Rpi


Отладив механизм отправки на Arduino, можно возвращаться к Rpi, на котором крутится веб-приложение по управлению радио. В случае с Arduino нам не требовалась гальваническая развязка в виде оптронов, так как мы сумели запитать Arduino от того же пина, от которого питается микроконтроллер CZERF-7C. Но в случае с RPi без развязки не обойтись, поэтому схема немного усложнилась:



Схема управления v2.5


Мы собрали эту схему "на коленке" и набросали небольшой прототип для отправки посылки с Raspberry PI, аналогичный Arduino-скетчу выше:


import spidev
import time

spi = spidev.SpiDev()
# device = CS
spi.open(bus=0, device=0)
spi.max_speed_hz = 2000 # минимальная частота, которую выдает RPi на SPI
spi.mode = 2 # причина смены режима описана ниже
While True:
    spi.xfer2([~0x00, ~0x32]) # отправка частоты 1024
    time.sleep(20)
spi.close()

Для организации работы через оптроны нужно поменять режим работы SPI на Mode 2(CPOL = 1, CPHA = 0). Это связно с тем, что сигнал на оптронах инвертируется. По этой же причине мы по линии MOSI отправляем инвертированные значения [~0x00, ~0x32] = 11111111 11001101 вместо 00000000 00110010


Подсоединяем RPi к плате трансмиттера, запускаем и… ничего не работает. Снова беремся за осциллограф смотреть, какой сигнал у нас формируется после оптронов. Чтобы посмотреть сигнал, нужно снова оборачивать в экран антенну… И в этом случаем все начинает работать. Значит наводки от антенны искажают нашу SPI-посылку. Придется воспользоваться старым приемом выключения вещания для выставления частоты. Алгоритм получается следующий:


  1. Выключить питание радиомодуля (вещание пропадает)
  2. Включить питание радиомодуля (вещание не появляется до отправки команды)
  3. Выставить частоту (вещание появляется, т.к отправляем команду в радиомодуль)

Теперь частота выставляется только в половине случаев… Здесь-то стало понятно, почему разработчики CZERF-7C выбрали нетипичную полярность CS.


-Паразитное питание



При выключении радиомодуля, он начинал подпитываться от ножек CS, CLK, MOSI через встроенные защитные диоды. По этой причине разработчики fm-трансмиттера, все линии SPI вне посылки сообщений притягивают к низкому уровню (pull-down). У контроллера SPI в RPi линия MOSI после отправки сообщения выставлялся в низкий уровень, а так как сигнал на оптронах инвертируется — на линии MOSI радиомодуля оказывался высокий уровень, который "паразитно" подпитывал радиомодуль и не давал ему полноценно выключаться. Когда же подавалось полноценное питание на радиомодуль, он начинал сразу вещать на частоте, которую ему установили до этого и тем самым опять создавать наводки на линии SPI от RPi.


-Аппаратный SPI + Собственная реализация SPI


Казалось бы, нужно просто выставлять MOSI в высокий уровень после каждой отправки сообщения, но это оказалось не так-то просто. Настройки SPI в RPi не позволяли этого сделать, вдобавок если линию MOSI инициализировать как обычный GPIO пин, то переставал работать аппаратный SPI до перезагрузки RPi. Самым простым и быстрым решением было самим реализовать программный SPI через прямое выставление уровней на ножках GPIO. К этому времени мы уже были экспертами по протоколу SPI:


def _clock(self):
    RPi.GPIO.output(CLK, RPi.GPIO.HIGH)
    time.sleep(0.001)
    RPi.GPIO.output(CLK, RPi.GPIO.LOW)
    time.sleep(0.001)

def _send(self, bits):
    RPi.GPIO.output(CS, RPi.GPIO.LOW)
    time.sleep(0.001)
    for bit in bits:
        RPi.GPIO.output(MOSI, RPi.GPIO.HIGH if bit else RPi.GPIO.LOW)
        self._clock() # 500Hz
    GPIO.output(CS, RPi.GPIO.HIGH)

Все заработало как надо, и мы были готовы делать третью версию платы управления.


-Микроконтроллер + Плата v3


Проблемы нестабильной работой прибора в результате наводок были полностью ликвидированы. Мы знали 90% всех функций микроконтроллера, управляющего радиомодулем, а поэтому были уверены, что его можно полностью заменить своей платой с собственным софтом. Оставалось только выяснить назначение последней ножки(№1) микроконтроллера и дело в шляпе.


Функций у CZERF-7C было не так-то много, поэтому можно было применить "брутфорс", вычислив функцию последней ножки методом перебора. У этого прибора был режим настройки, в который можно было попасть, зажав кнопку power при подключении питания. В этом режиме помимо выставления границ частоты можно было задавать силу вещания: 1/7 ватт. Оказалось, что на этой ножке была логическая единица при выборе силы в 1 ватт и логический ноль при выборе 7 ватт. Можно было бы просто откусить эту ножку, и дело с концом, но мы решили добавить еще пару оптронов в финальную версию платы: для включения low(1ватт) и high(7ватт) режимов на всякий случай — места у нас теперь в корпусе прибора было предостаточно.


С учетом полноты информации, проектируем новую версию платы:



Схема управления v3


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


Плата_v3
Финальная плата управления вместо оригинального контроллера, кнопок и дисплея


Finale


Hardware-reversing быстро принес свои плоды: мы сумели избавиться от всех проблем, которые привнесли предыдущие уровни. Оборачиваясь назад, сложно поверить, на что мы рассчитывали в начале, а сейчас — сложно представить развитие этой истории каким-либо иным образом.


Этот по-настоящему "венчурный" для нас проект показал, что в любой новой сфере можно разобраться за адекватное время при наличии интереса у команды, толерантности к ошибкам и открытости новым идеям.

Теги:
Хабы:
+7
Комментарии19

Публикации

Информация

Сайт
postuf.com
Дата регистрации
Дата основания
Численность
31–50 человек
Местоположение
О.А.Э.

Истории