Лет десять назад как-то по случаю я купил простенькую погодную станцию Oregon Scientific BAR208HG. Радовала она домочадцев достаточно долго, и продолжает радовать до сих пор. Мне же со временем стало не хватать её функционала и захотелось расширить свои возможности наблюдения за погодой. И тут выяснился один неприятный факт — покупка продвинутой метеостанции от того же Oregon Scientific не давала возможности транслировать показания с её датчиков на старую станцию. Не совпадала версия протокола передачи данных. Примерно в это же время я был вовлечён в такую увлекательную авантюру, как передачу метеоданных на сервис небезызвестного Народного мониторинга. Уже на тот момент сети имелось достаточно много информации о самих погодных станциях и датчиках Oregon, о протоколе передачи данных и методах их расшифровки. Я легко нашёл и несколько готовых программ и библиотек Arduino для приёма и расшифровки сигнала. Вся эта информация показалась мне недостаточно систематизирована, местами неточна, а программы давали удовлетворительный результат только на очень коротких расстояниях. В конечном итоге я пришёл к старой истине: "Хочешь сделать что-то хорошо — сделай сам". Результатом последующих изысканий стало написание вот этой заметки, в которой хотелось бы поделиться полученными знаниями и умениями.  Вся экосистема Oregon Scientific работает по общему принципу — датчики являются передатчиками, вещающими через строго определённые интервалы времени. Для минимизации коллизий при передаче интервалы вещания для всех датчиков различны, например, для моей станции датчики передают показания с интервалом 39, 41 и 43 секунды на 1-ом, 2-ом и 3-ем канале соответственно. Сами метеостанции являются в свою очередь только приёмниками. Таким образом связь является односторонней. Производитель использует несколько версий протокола передачи данных: Все датчики вещают на несущей частоте 433Мгц. Метод модуляции — ООК (On/Off Key), т.е. банальный "вкл/выкл", как в азбуке Морзе. Во всех версиях протокола используется манчестерское кодирование с разной избыточностью и тактовой частотой 2048Гц. На рисунке ниже приведены методы кодирования информации для обоих рассматриваемых протоколов версий 2.1 и 3.0  Нужно отметить, что длины импульсов и пауз не кратны тактовой частоте. Такая несимметричность удобна при использовании OOK приёмника, когда неизвестно, прямой или инверсный у него цифровой выход. Ведь по своей сути манчестерское кодирование и является дифференциальным — не зависящим от начального значения сигнала. При такой несимметричности кода можно правильно выставить синхронизацию ещё в момент приёма первого бита. Производитель пошёл ещё дальше — параметры несимметричности кода различается для разных версий протокола. Вероятно, это сделано для уверенной идентификацией принимающей стороной версии получаемого кода ещё до его расшифровки. В обоих версиях передача данных происходит полубайтами, тетрадами или нибблами. Передача осуществляется младшим битом вперёд.  Пакет данных состоит из ряда полей, начинающихся с преамбулы. Первое отличие протоколов состоит в длине преамбулы. В версии 2.1 она состоит из 4-ёх тетрад Fh, а версии 3.0 — из 6-и таких же тетрад. Для чего нужна преамбула? Для корректного приёма пакета помимо синхронизации приёмника и передатчика, нужно, чтобы автоматическая регулировка усиления (АРУ) приёмника настроилась на уровень сигнала от передатчика. Процесс этот достаточно медленный, и если им пренебречь и лишить пакет преамбулы, то начальные данные будут сильно искажены, и раскодировать их скорее всего не получится.  Следующим идёт поле синхронизации, состоящее из терады Ah. Это указатель на начало информационной части пакета. Технически его можно было бы отнести к преамбуле, но в некоторых программных реализациях наоборот относят его к полю типа датчика. Тип датчика — поле длиной в 4 тетрады. Исходя из этого типа, принимающая сторона должна сделать вывод, известен ли ей этот тип и способна ли она обрабатывать такие пакеты. Ведь тип датчика определяет многое: Значение поля "Канал" задаётся переключателем под крышкой батарейного отсека датчика. Значение же поля "Идентификатор" меняется каждый раз после сброса или смены батареек. Идентификатор позволяет работать нескольким датчикам и метеостанциям, каждому со своим, даже если все они находятся в непосредственной близости друг к другу. Предполагается, что перевод погодной станции в режим поиска датчика и одновременный сброс датчика с большой долей вероятности приведёт к тому, что первым придёт сигнал именно от только что сброшенного датчика. Приёмник запоминает его идентификатор, и до следующего вызова процедуры поиска будет игнорировать все аналогичные датчики, работающие на этом же канале, но с иными идентификаторами. Важно отметить, что значение идентификатора выбирается только из определённого множества, а не может быть случайным.  Поле "Батарея" размером в одну тетраду содержит несколько информационных битов: Размер и наполнение поля "Данные" определяется типом датчика. Я собрал в сети информацию о данных и методах её расшифровки для наиболее распространённых типов:  Поле "Контрольная сумма" — первая ступень проверки целостности полученных данных. Рассчитывается она, как однобайтовая сумма всех тетрад начиная с поля типа датчика и заканчивая данными. Например, для пакета 5D5314D01510950AC13B529 Контрольная сумма будет равна: 5h + Dh + 5h + 3h + 1h + 4h + Dh + 0h + 1h + 5h + 1h + 0h + 9h + 5h + 0h + Ah + Ch + 1h + 3h = 5Bh Разработчики программ при написании процедур декодирования данных часто ограничиваются проверкой только этого поля, что нередко приводит к ошибкам при раскодировании. Очевидно, что комплементарное искажение одного и того же бита двух разных тетрад в пакете может остаться незамеченным при таком методе проверки. Поле CRC8 — вторая ступень проверки целостности данных. В обеих версиях протокола используется алгоритм CRC8-CCITT с порождающим полиномом 07h. Поскольку в пакете принят обратный порядок передачи битов от младшего к старшему, то и расчёт ведётся в таком же порядке для полей начиная от "типа" и заканчивая "данными". Различие в расчёте между версиями 2.1 и 3.0 заключается в том, что в версии 2.1 из расчёта исключено поле "ID" и стартовая сумма не всегда равна нулю а определяется типом датчика. Например, для пакета датчика THN132N (версия 2.1) EC401B183520D33F расчёт производится с начальным значением D6h для последовательности CRC8-CCITT( D6h < E < C < 4 < 0 < 1 < 8 < 3 < 5 < 2 < 0 ) = F3h Для пакета же датчика PCR800 (версия 3.0), имеющего вид 29140EC00000279410142E рассчёт производится с нулевым начальным значением для последовательности CRC8-CCITT( 00h < 2 < 9 < 1 < 4 < 0 < E < C < 0 < 0 < 0 < 0 < 0 < 2 < 7 < 9 < 4 < 1 < 0) = E2h В сводной таблице приведены основные параметры наиболее распространённых датчиков.
 Хотелось бы немного рассказать о своём опыте реализации декодировщика протокола. Опробованные мной декодировщики для платформы Arduino ориентированы на работу с устойчивым, неискажённым сигналом и обеспечивают уверенный приём только на очень малых расстояниях между датчиком и приёмником. С увеличением этого расстояния микроконтроллер с внешним приёмником теряет связь намного быстрее, чем "родная" погодная станция. Подключение осциллографа к выходу приёмника даёт ответ на вопрос, почему это происходит. На осциллограммах показан сигнал от THGN132N на выходе приёмника при различном удалении датчика.   Видно, что с увеличением расстояния, когда уровень принимаемого сигнала падает, на него начинают накладываться шумы, приводящие к дроблению и сужению импульсов, появлению иных помех на цифровом выходе приёмника. Вероятно разработчики из Oregon знакомы с этой проблемой и научились её решать, а вот для Arduino я такого решения не нашёл. Посчитав наиболее правильным при обработке такого сигнала вычисление огибающей с попыткой последующего восстановления неверных блоков кода, я написал свою библиотеку, где постарался учесть всю исследованную проблематику. Надо заметить, что в моей реализации такого метода обработки кода требуется значительный объём ОЗУ. Кроме того, программа чувствительна к отклонению тактовой частоты передатчика, что случается, как оказалось, не так уж редко в силу низкого качества используемых в датчиках компонентов, в том числе и кварцевых резонаторов.