Манчестерское кодирование
один из способов кодирования двоичным цифровым сигналом исходных двоичных данных / Материал из Википедии — свободной энциклопедии
Уважаемый Wikiwand AI, давайте упростим задачу, просто ответив на эти ключевые вопросы:
Перечислите основные факты и статистические данные о Манчестерское кодирование?
Кратко изложите эту статью для 10-летнего ребёнка
ПОКАЗАТЬ ВСЕ ВОПРОСЫ
Манче́стерское коди́рование [1] , код Манчестер-II [2] , абсолютный биимпульсный код [3] (иногда применяются синонимы: линейное кодирование [3] [4] , физическое кодирование, манипуляция сигнала, модуляция, импульсно-кодовая модуляция [3] ) — один из способов кодирования двоичным цифровым сигналом исходных двоичных данных для передачи по одному двухуровневому каналу связи или записи на носитель информации.
Сигнал, закодированный манчестерским кодом, является самосинхронизирующимся, то есть для передачи данных не требуется дополнительная линия передачи тактовых импульсов за счет того, что за время передачи одного бита данных, независимо от того, 1 это или 0, обеспечивается один переход с одного уровня на другой, что позволяет приемнику синхронизировать свой внутренний тактовый генератор или таймер с тактовым генератором (таймером) передатчика.
Сигнал, закодированный в соответствии с манчестерским кодом, не имеет постоянной составляющей даже в случае передачи длинных последовательностей из нулей и единиц, поэтому передающие сигнал электрические соединения могут быть гальванически развязаны, например, с помощью трансформатора [5] .
Название кодирования происходит из университета Манчестера, где такое кодирование было впервые использовано для хранения данных на магнитном барабане компьютера Манчестерский Марк I.
Oops something went wrong:
Манчестерский код (Manchester)
Манчестерский код относится к самосинхронизирующимся импульсным кодам и имеет два уровня, что обеспечивает хорошую помехозащищенность. Каждый такт (битовый интервал) делится на две части. Информация кодируется перепадами потенциала, происходящими в середине каждого такта.
Единица кодируется перепадом от высокого уровня сигнала к низкому, а ноль — обратным перепадом. В начале такта может происходить служебный перепад сигнала (при передаче несколько единиц или нулей подряд).
Рассмотрим частные случаи кодирования, как в предыдущих случаях.




При манчестерском кодировании обязательное изменение сигнала в середине каждого битового интервала позволяет легко выделить тактовый синхросигнал. Поэтому манчестерский код обладает хорошими самосинхронизирующимися свойствами.
Сигнал не содержит постоянную составляющую, частота основной гармоники сигнала находится в интервале от fо=N/2 Гц до fо=N Гц, изменяясь в зависимости от вида битового потока.
Манчестерское кодирование использовалось в ранних версиях технологии Ethernet со скоростью передачи 10 Мбит/с.
Дифференциальный манчестерский код (Differential Manchester)
Логические значения «0» и «1» передаются соответственно наличием или отсутствием смены уровня сигнала в начале тактового (битового) интервала. В середине битового интервала имеет место обязательная смена значения сигнала.

Дифференциальное манчестерское кодирование
Этот код обладает теми же самыми преимуществами и недостатками, что и манчестерский.
Из всех рассмотренных нами кодов манчестерское кодирование обладает лучшей самосинхронизацией, поскольку перепад сигнала происходит минимум один раз за такт.
Манчестерский код используется в сетях Ethernet со скоростью передачи 10 Мбит/с (10Bаsе-Т). Дифференциальный манчестерский код – в сетях с технологией Token Ring.
В настоящее время разработчики пришли к выводу, что во многих случаях рациональнее применять потенциальное кодирование, ликвидируя его недостатки с помощью, так называемого логического кодирования (см. ниже в этом разделе).
Код с возвратом к нулю rz (Return to Zero)

Бит «1» — импульс одной полярности в первой половине битового интервала, во второй половине битового интервала сигнал имеет нулевой потенциал.
Бит «0» – импульс другой полярности в первой половине битового интервала, во второй половине битового интервала сигнал имеет нулевой потенциал. Код имеет хорошие синхронизирующие свойства.

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

Потенциальный код 2b1q
Это потенциальный код с четырьмя уровнями сигнала для кодирования данных. Название отражает суть кодирования – каждые два бита (2В) передаются за один такт сигналом определенного уровня (1Q). Линейный сигнал имеет четыре состояния. Другими словами, скорость передачи информации N при этом методе кодирования в два раза больше скорости модуляции В.

Сигнал в коде 2B1Q
На рисунке изображен сигнал, соответствующий последовательности бит: 01 01 10 00. Основная частота сигнала в коде 2B1Q не превышает значения fо=N/4 Гц.
Однако для реализации этого метода кодирования мощность передатчика должна быть выше, чтобы четыре значения потенциала четко различались приемником на фоне помех.
Код MLT3 (Multi Level Transmission — 3).
Используются три уровня передачи: «-1», «0», «+1».
Единице соответствует обязательный переход с одного уровня сигнала на другой на границе тактового интервала.
Нулю соответствует отсутствие изменения уровня линейного сигнала.
При передаче последовательности единиц период изменения уровня сигнала включает четыре бита. В этом случае fо=N/4 Гц. Это максимальная основная частота сигнала в коде MLT-3. В случае чередующейся последовательности нулей и единиц основная гармоника сигнала находится на частоте fо=N/8 Гц, что в два раза меньше чем у кода NRZI.



Сигнал в коде MLT-3
Логическое кодирование
Логическое кодирование выполняется передатчиком до физического кодирования, рассмотренного выше, средствами канального или физического уровня. На этапе логического кодирования борются с недостатками методов физического цифрового кодирования — отсутствие синхронизации, наличие постоянной составляющей. Таким образом, сначала с помощью средств логического кодирования формируются исправленные битовые последовательности, которые потом с помощью простых методов физического кодирования передаются по линиям связи.
Логическое кодирование подразумевает замену бит исходной информационной последовательности новой последовательностью бит, несущей ту же информацию, но обладающей, кроме этого, дополнительными свойствами, например возможностью для приемной стороны обнаруживать ошибки в принятых данных или надежно поддерживать синхронизацию с поступающим сигналом.
Различают два метода логического кодирования:
— кодирование избыточным кодом;
— скремблирование.
Избыточные коды (табличные коды) основаны на разбиении исходной последовательности бит на группы и последующей замене каждой исходной группы кодовым словом в соответствии с таблицей. Кодовое слово всегда содержит большее количество бит, чем исходная группа.
Логический код 4В/5В заменяет исходные группы длиной в 4 бита кодовыми словами длиной в 5 бит. В результате общее количество возможных битовых комбинаций для них (2 5 =32) больше, чем для исходных групп (2 4 =16). Поэтому в кодовую таблицу можно включить 16 таких комбинаций, которые не содержат более двух нулей подряд, и использовать их для передачи данных. Код гарантирует, что при любом сочетании кодовых слов на линии не могут встретиться более трех нулей подряд.
Остальные комбинации кода используются для передачи служебных сигналов (синхронизация передачи, начало блока данных, конец блока данных, управление передачей на канальном уровне). Неиспользуемые кодовые слова могут быть задействованы приемником для обнаружения ошибок в потоке данных. Цена за полученные достоинства при таком способе кодирования данных — снижение скорости передачи полезной информации на 25%.
Линейный код
Исходная группа
Логическое кодирование 4В/5В используется в сетях Ethernet со скоростью передачи 100МБит/с:
- в сочетании с кодом NRZI (спецификация 100Base FX, среда передачи — оптоволокно);
- в сочетании с кодом MLT-3 (спецификация 100Base TX, среда передачи UTP Cat 5e).
Имеются также коды и с тремя состояниями сигнала, например, в коде 8В/6Т для кодирования 8 бит исходной информации используются кодовые слова троичного кода из 6 элементов. Каждый элемент может принимать одно из трех значений (+1, 0, -1). Избыточность кода 8В/6Т выше, чем кода 4В/5В, так как на 2 8 =256 исходных символов приходится 36=729 результирующих кодовых слов. Этот метод кодирования используется в спецификации 100Base T4 – при организации 100Мбит/с Ethernet по кабелю UTP Cat3 (устаревшая спецификация). Здесь для передачи битового потока одновременно используются 3 витые пары. Скорость передачи информации по каждой паре составляет N=100 Мбит/с / 3 = 33,3 Мбит/с, скорость модуляции линейного сигнала равна 25 М Бод (8:6=1,33; 33,3:1,33=25), что позволяет использовать неэкранированную витую пару UTP Cat3. В коде8B/10В каждые 8 бит исходной последовательности заменяются десятью битами кодового слова. При этом на 256 исходных комбинаций приходится 1024 результирующих комбинаций. При замене в соответствии с кодовой таблицей соблюдаются следующие правила:
- ни одна результирующая комбинация (кодовое слово) не должна иметь более 4-х одинаковых бит подряд;
- ни одна результирующая комбинация не должна содержать более 6 нулей или 6 единиц;
Код 8B/10В(+NRZI) используется в стандарте Gigabit Ethernet 1000Base-Х (когда в качестве среды передачи данных используется оптоволокно). Осуществляют логическое кодирование сетевые адаптеры. Поскольку, использование таблицы перекодировки является очень простой операцией, метод логического кодирования избыточными кодами не усложняет функциональные требования к этому оборудованию. Для обеспечения заданной пропускной способностиNБит/с передатчик, использующий избыточный код, должен работать с повышенной тактовой частотой. Так, для передачи сигнала в коде 4В/5В со скоростью передачи информации N=100 Мбит/с, передатчик должен работать с тактовой частотой 125 МГц (то естьB=125МБод). При этом спектр линейного сигнала расширяется. Тем не менее, спектр сигнала избыточного потенциального кода оказывается уже спектра сигнала в манчестерскомкоде, что оправдывает дополнительный этап логического кодирования, а также работу приемника и передатчика на повышенной тактовой частоте. Скремблирование представляет собой такое «перемешивание» исходной битовой последовательности, при котором вероятность появления единиц и нулей на входе модуля физического кодирования становится близкой 0,5. Устройства (или программные модули), выполняющие такую операцию, называются скремблерами (scramble — свалка, беспорядочная сборка). Схема включения скремблера в канал связи
Скремблер в передатчике выполняет преобразование структуры исходного цифрового потока. Дескремблер в приемнике восстанавливает исходную последовательность бит. Практически единственной операцией, используемой в скремблерах и дескремблерах, является XOR — «побитное исключающее ИЛИ» (сложение по модулю 2). Основная часть скремблера и дескремблера – это генератор псевдослучайной последовательности (ПСП) в виде К-разрядного регистра сдвига с обратными связями. Различают 2 основных типа пар скремблеров – дескремблеров:
- самосинхронизирующиеся;
- с начальной установкой (аддитивные).
Самосинхронизирующиеся схемы управляются скремблированной последовательностью. Эти схемы имеют недостаток – размножение ошибок. Влияние ошибочного символа проявляется столько раз, сколько обратных связей имеется в схеме.
Вариант реализации скремблирования в самосинхронизирующейся схеме. Пусть, например, скремблер реализует соотношение Вi=Ai+Bi-5+Bi-7. Здесь Bi – двоичная цифра результирующего кода, полученная на i-м такте работы скремблера; Ai – двоичная цифра исходного кода, поступающая в передатчике на вход скремблера на i-м такте; Bi-5 и Bi-7 – двоичные цифры результирующего кода, полученные на предыдущих тактах работы скремблера, соответственно на «i-5» и «i-7» тактах. Дескремблер в приемнике восстанавливает исходную последовательность, используя соотношение Ci=Bi+Bi-5+Bi-7=(Ai+Bi-5+Bi-7 )+Bi-5+Bi-7=Ai В аддитивных схемах скремблированная последовательность не поступает на вход регистров сдвига, размножение ошибок отсутствует, но требуется синхронизация работы пары скремблер-дескремблер. 
Манчестерский код
Ни в одной из версий Е^егпе! не применяется прямое двоичное кодирование бита 0 напряжением О В и бита 1 — напряжением 5В, так как такой способ приводит к неоднозначности. Если одна станция посылает битовую строку 00010000, то другая может интерпретировать ее как 10000000 или 01000000, так как они не смогут отличить отсутствие сигнала (0 В) от бита 0 (0 В).
Можно, конечно, кодировать единицу положительным напряжением +1 В, а ноль — отрицательным напряжением -1 В. Но при этом все равно возникает проблема, связанная с синхронизацией передатчика и приемника. Разные частоты работы их системных часов могу привести к рассинхронизации и неверной интерпретации данных. В результате приемник может потерять границу битового интервала. Особенно велика вероятность этого в случае длинной последовательности нулей или единиц.
Таким образом, принимающей машине нужен способ однозначного определения начала, конца и середины каждого бита без помощи внешнего таймера. Это реализуется с помощью двух методов: манчестерского кодирования и разностного манчестерского кодирования.
В манчестерском коде каждый временной интервал передачи одного бита делится на два равных периода. Бит со значением 1 кодируется высоким уровнем напряжения в первой половине интервала и низким — во второй половине, а нулевой бит кодируется обратной последовательностью — сначала низкое напряжение, затем высокое. Такая схема гарантирует смену напряжения в середине периода битов, что позволяет приемнику синхронизироваться с передатчиком. Недостатком манчестерского кодирования является то, что оно требует двойной пропускной способности линии по отношению к прямому двоичному кодированию, так как импульсы имеют половинную ширину. Например, для того чтобы отправлять данные со скоростью 10 Мбит/с, необходимо изменять сигнал 20 миллионов раз в секунду. Манчестерское кодирование показано на рис. 4.15, б.
Разностное манчестерское кодирование, показанное на рис. 4.15, в, является вариантом основного манчестерского кодирования. В нем бит 0 кодируется изменением состояния в начале интервала, а бит 1 — сохранением предыдущего Уровня. В обоих случаях в середине интервала обязательно присутствует переход. Разностная схема требует более сложного оборудования, зато обладает хорошей защищенностью от шума. Во всех сетях ЕЛегпе! используется манчестерское кодирование благодаря его простоте. Высокий сигнал кодируется напряжением в +0,85 В, а низкий сигнал 0,85 В, в результате чего постоянная
составляющая напряжения равна 0 В. Разностное манчестерское кодирование в ЕЛегпе! не используется, но используется в других ЛВС (например, стандарт 802.5, маркерное кольцо).
Манчестерский код для чайников
Манчестерский Код — это самосинхронизирующийся двоичный код без постоянной составляющей, в котором значение каждого передаваемого бита определяется направлением смены логического уровня в середине обусловленного заранее временного интервала. Поскольку логических уровней у самой маленькой единицы информации (бит) на данный момент известно всего два (1 и 0), вариантов тут немного: либо смена 1 => 0 либо 0 => 1. Согласно общепринятым стандартам для Манчестерского кода переход от нуля к единице считается 1, а если наоборот, то 0. На самом деле последнее утверждение — это просто формальность — вопрос в том, с какой стороны посмотреть 😉 Главное, чтобы и приёмник и передатчик смотрели на жизнь одинаково.

Введите число и нажмите «Encode Manchester!«:
Теперь давайте внимательно посмотрим на картинку и попробуем проанализировать и перечислить основные преимущества и недостатки преобразования данных в Манчестерский Код:
- Pазмер данных увеличивается вдвое — это негативно сказывается на скорости передачи
- Kоличество логических нулей всегда равно количеству логических единиц, соответственно у такого сигнала не будет постоянной составляющей — это крайне важно для электрических цепей и радиоволн
- Комбинация логических уровней 11 однозначно говорит о последнем принятом 0, а комбинация 00, соответственно, говорит о 1. Таким образом после одной из них приёмник синхронизируется
- Не может идти последовательно более двух одинаковых логических уровней, т.е. комбинация типа 111 или 000 невозможна
- В начале данных и в конце не может быть двух одинаковых логических уровней — только 10 или 01
Сначала пишем тест
О пользе тестов можно почитать тут. В контексте решения текущей задачи будет использоваться техника Mock-объектов, поэтому для тестирования используется связка gtest (Google Test) + gmock (Google Mocking Framework). Всё это добро поставляются в исходниках, поэтому единственное требование к системе — совместимый C / C++ компилятор, например gcc g++ для Linux или Visual Studio C++ для Windows. Так выглядит простое консольное приложение, которое будет собираться вместе с тестами и запускать их:
#include "gtest/gtest.h" int main(int argc, char* argv[]) testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); >
Теперь сами тесты. Более простой задачей является преобразование данных в Манчестерский Код (encode), поэтому с неё, пожалуй, и начнём:
#include #include extern "C" #include "../../../../manchester/src/tx/Man_Encode.c" > class IManEncode public: virtual void Man_Encode_One() = 0; virtual void Man_Encode_Zero() = 0; >; /* Mock implementation */ ACTION_P2(Act_Inc_1, T, V) ON_CALL(*T, Man_Encode_One()) .WillByDefault(Act_Inc_1(T, testing::ByRef(++V))); > ACTION_P2(Act_Inc_0, T, V) ON_CALL(*T, Man_Encode_Zero()) .WillByDefault(Act_Inc_0(T, testing::ByRef(++V))); > class ManEncodeMock : public IManEncode public: MOCK_METHOD0(Man_Encode_One,void()); MOCK_METHOD0(Man_Encode_Zero,void()); ManEncodeMock() _total_1 = _total_0 = 0; ON_CALL(*this, Man_Encode_One()) .WillByDefault(Act_Inc_1(this, testing::ByRef(_total_1))); ON_CALL(*this, Man_Encode_Zero()) .WillByDefault(Act_Inc_0(this, testing::ByRef(_total_0))); > void Expect_Total_1_And_0_Eq(int total) EXPECT_EQ(_total_1, total); EXPECT_EQ(_total_0, total); > private: int _total_1, _total_0; >; /* Fixture class for each test */ class ManEncodeTest_F : public testing::Test public: static ManEncodeMock* getMock() return _ManEncodePtr; > protected: virtual void SetUp() _ManEncodePtr = &_ManEncode; > private: ManEncodeMock _ManEncode; static ManEncodeMock* _ManEncodePtr; >; ManEncodeMock* ManEncodeTest_F::_ManEncodePtr; /* Man_Encode externs (events) */ void On_Man_Encode_One() ManEncodeTest_F::getMock()->Man_Encode_One(); > void On_Man_Encode_Zero() ManEncodeTest_F::getMock()->Man_Encode_Zero(); > /* 0 => 1010101010101010(manchester) */ TEST_F(ManEncodeTest_F, Send_0) testing::InSequence s; for (int i = 0; i 8; i++) EXPECT_CALL(*getMock(), Man_Encode_One()); // MSB EXPECT_CALL(*getMock(), Man_Encode_Zero()); > Man_Encode(0); getMock()->Expect_Total_1_And_0_Eq(8); > /* 255(dec) => 11111111(bin) => 0101010101010101(manchester) */ TEST_F(ManEncodeTest_F, Send_255) testing::InSequence s; for (int i = 0; i 8; i++) EXPECT_CALL(*getMock(), Man_Encode_Zero()); // MSB EXPECT_CALL(*getMock(), Man_Encode_One()); > Man_Encode(255); getMock()->Expect_Total_1_And_0_Eq(8); > /* 170(dec) => 10101010(bin) => 0110011001100110(manchester) */ TEST_F(ManEncodeTest_F, Send_170) testing::InSequence s; EXPECT_CALL(*getMock(), Man_Encode_Zero()); // MSB for (int i = 0; i 3; i++) EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); > EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_Zero()); Man_Encode(170); getMock()->Expect_Total_1_And_0_Eq(8); > /* 85(dec) => 01010101(bin) => 1001100110011001(manchester) */ TEST_F(ManEncodeTest_F, Send_85) testing::InSequence s; EXPECT_CALL(*getMock(), Man_Encode_One()); // MSB for (int i = 0; i 3; i++) EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); > EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_One()); Man_Encode(85); getMock()->Expect_Total_1_And_0_Eq(8); > /* 84(dec) => 01010100(bin) => 1001100110011010(manchester) */ TEST_F(ManEncodeTest_F, Send_84) testing::InSequence s; EXPECT_CALL(*getMock(), Man_Encode_One()); // MSB for (int i = 0; i 3; i++) EXPECT_CALL(*getMock(), Man_Encode_Zero()).Times(2); EXPECT_CALL(*getMock(), Man_Encode_One()).Times(2); > EXPECT_CALL(*getMock(), Man_Encode_Zero()); EXPECT_CALL(*getMock(), Man_Encode_One()); EXPECT_CALL(*getMock(), Man_Encode_Zero()); Man_Encode(84); getMock()->Expect_Total_1_And_0_Eq(8); >
Все тесты помещены в макрос TEST_F() . В начале теста с помощью EXPECT_CALL() необходимо установить ожидаемое поведение. В процессе преобразования 0 => 1010101010101010 и при условии, что старший бит идёт первым (MSB), ожидается последовательный вызов методов On_Man_Encode_One() и On_Man_Encode_Zero() и так восемь раз. После того, как ожидаемое поведение описано, необходимо вызвать проверяемый метод Man_Encode() . Если реальное поведение отличается от ожидаемого, в процессе выполнения тестов будет сообщено об ошибке. В конце каждого теста также выполняется проверка условия, что количество нулей равно количеству единиц.
Преобразовать данные в Манчестерский Код очень легко:
#include "Man_Encode.h" /******************************************************************** * Function Name: Man_Encode * * Return Value: no * * Parameters: character to transmit * * Description: Convert char to Manchester Code (2 chars) * * MSB is first to convert * ********************************************************************/ void Man_Encode(register char character) register unsigned char bitcount = 8; while (bitcount--) if (character & 0x80) On_Man_Encode_Zero(); On_Man_Encode_One(); > else On_Man_Encode_One(); On_Man_Encode_Zero(); > character 1; > >
Реализация обратной задачи — декодирования данных из Манчестерского Кода в оригинальный несколько сложнее. Перед началом передачи данных необходимо синхронизироваться с приёмником сиигнала. В реализации тестов нас особо не интересует как именно приёмник синхронизируется и в какой последовательности будут вызваны(если вообще будут) On_Man_Decode_Add_1() и On_Man_Decode_Add_0() — для этой цели обозначим предварительные ожидания как testing::AtMost(1) . После синхронизации процесс декодирования можно точно спрогнозировать и описать соответствующие ожидания с помощью EXPECT_CALL() . Также как и в предыдущем случае в конце каждого теста проверяется отсутствие постоянной составляющей (количество нулей и единиц должно совпадать).
#include #include extern "C" #include "../../../../manchester/src/rx/Man_Decode.c" > class IManDecode public: virtual void Man_Dec_Add_1() = 0; virtual void Man_Dec_Add_0() = 0; >; /* Mock implementation */ class ManDecodeMock : public IManDecode public: MOCK_METHOD0(Man_Dec_Add_1,void()); MOCK_METHOD0(Man_Dec_Add_0,void()); >; /* Fixture class for each test */ class ManDecodeTest_F : public testing::Test public: static ManDecodeMock* getMock() return _ManDecodePtr; > protected: virtual void SetUp() _total_1 = _total_0 = 0; _ManDecodePtr = &_ManDecode; > void Expect_Total_1_And_0_Eq(int total) EXPECT_EQ(_total_1, total); EXPECT_EQ(_total_0, total); > void Perform_Stable_Zero(unsigned char periods) _total_0 += periods; Man_Decode_Stable_Zero(periods); > void Perform_Stable_One(unsigned char periods) _total_1 += periods; Man_Decode_Stable_One(periods); > private: ManDecodeMock _ManDecode; static ManDecodeMock* _ManDecodePtr; int _total_1, _total_0; >; ManDecodeMock* ManDecodeTest_F::_ManDecodePtr; /* Man_Decode externs (events) */ void On_Man_Decode_Add_1() ManDecodeTest_F::getMock()->Man_Dec_Add_1(); > void On_Man_Decode_Add_0() ManDecodeTest_F::getMock()->Man_Dec_Add_0(); > /* Helpers for TEST_F */ #define EXPECT_MAN_SYNCH(x,y) \ EXPECT_CALL(*getMock(), Man_Dec_Add_##x()) \ .Times(testing::AtMost(1)); /* Clay? */ \ EXPECT_CALL(*getMock(), Man_Dec_Add_##y()) \ .Times(testing::AtMost(1)); /* Clay? */ \ EXPECT_CALL(*getMock(), Man_Dec_Add_##x()); /* Sync */ \ EXPECT_CALL(*getMock(), Man_Dec_Add_##y()) /* Sync */ \ #define PERFORM_MAN_SYNCH(x,y) \ Perform_Stable_##x(1); /* Clay balance (1 - 1 = 0) */ \ Perform_Stable_##y(2); /* Sync balance (2 - 2 = 0) */ \ Perform_Stable_##x(2); /* Sync */ \ Perform_Stable_##y(1) /* Clay */ \ /* 1010101010101010(manchester) => 0 */ TEST_F(ManDecodeTest_F, Decode_0) testing::InSequence s; EXPECT_MAN_SYNCH(1,0); EXPECT_CALL(*getMock(), Man_Dec_Add_0()).Times(8); PERFORM_MAN_SYNCH(One, Zero); for (int i = 0; i 8; i++) Perform_Stable_One(1); Perform_Stable_Zero(1); > Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 0101010101010101(manchester) => 11111111(bin) => 255(dec) */ TEST_F(ManDecodeTest_F, Decode_255) testing::InSequence s; EXPECT_MAN_SYNCH(0,1); EXPECT_CALL(*getMock(), Man_Dec_Add_1()).Times(8); PERFORM_MAN_SYNCH(Zero, One); for (int i = 0; i 8; i++) Perform_Stable_Zero(1); Perform_Stable_One(1); > Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 0110011001100110(manchester) => 10101010(bin) => 170(dec) */ TEST_F(ManDecodeTest_F, Decode_170) testing::InSequence s; EXPECT_MAN_SYNCH(0,1); for (int i = 0; i 4; i++) EXPECT_CALL(*getMock(), Man_Dec_Add_1()); EXPECT_CALL(*getMock(), Man_Dec_Add_0()); > PERFORM_MAN_SYNCH(Zero, One); Perform_Stable_Zero(1); for (int i = 0; i 3; i++) Perform_Stable_One(2); Perform_Stable_Zero(2); > Perform_Stable_One(2); Perform_Stable_Zero(1); Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 1001100110011001(manchester) => 01010101(bin) => 85(dec) */ TEST_F(ManDecodeTest_F, Decode_85) testing::InSequence s; EXPECT_MAN_SYNCH(1,0); for (int i = 0; i 4; i++) EXPECT_CALL(*getMock(), Man_Dec_Add_0()); EXPECT_CALL(*getMock(), Man_Dec_Add_1()); > PERFORM_MAN_SYNCH(One, Zero); Perform_Stable_One(1); for (int i = 0; i 3; i++) Perform_Stable_Zero(2); Perform_Stable_One(2); > Perform_Stable_Zero(2); Perform_Stable_One(1); Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) > /* 1001100110011010(manchester) => 84(dec) => 01010100(bin) */ TEST_F(ManDecodeTest_F, Decode_84) testing::InSequence s; EXPECT_MAN_SYNCH(1,0); for (int i = 0; i 3; i++) EXPECT_CALL(*getMock(), Man_Dec_Add_0()); EXPECT_CALL(*getMock(), Man_Dec_Add_1()); > EXPECT_CALL(*getMock(), Man_Dec_Add_0()).Times(2); PERFORM_MAN_SYNCH(One, Zero); Perform_Stable_One(1); for (int i = 0; i 3; i++) Perform_Stable_Zero(2); Perform_Stable_One(2); > Perform_Stable_Zero(1); Perform_Stable_One(1); Perform_Stable_Zero(1); Expect_Total_1_And_0_Eq(11); // Sync(3) + Byte(8) >
Предположительная реализация процесса декодирования Манчестерского кода:
#include "Man_Decode.h" static bool ds_LB; /******************************************************************** * Function Name: Man_Decode_Stable_Zero * * Return Value: no * * Parameters: Stable digital input periods. Ideal 1 or 2 * * Description: Convert signal from Manchester Code. * * Fire according On_Man_Decode_Add_1() * * callback event. * ********************************************************************/ void Man_Decode_Stable_Zero(register unsigned char periods) if ( periods ) if ( !--periods ) if ( ds_LB ) On_Man_Decode_Add_1(); ds_LB = 1; > > else if ( !--periods ) On_Man_Decode_Add_1(); ds_LB = 1; > > > /******************************************************************** * Function Name: Man_Decode_Stable_One * * Return Value: no * * Parameters: Stable digital input periods. Ideal 1 or 2 * * Description: Convert signal from Manchester Code. * * Fire according On_Man_Decode_Add_0() * * callback event. * ********************************************************************/ void Man_Decode_Stable_One(register unsigned char periods) if ( periods ) if ( !--periods ) if ( !ds_LB ) On_Man_Decode_Add_0(); ds_LB = 0; > > else if ( !--periods ) On_Man_Decode_Add_0(); ds_LB = 0; > > >
Сборка и запуск тестов
Если Вы работаете в связке Windows + Visual Studio, необходимо выполнить следующее:
@set GTEST_HOME=gtest-1.6.0 @set GMOCK_HOME=gmock-1.6.0 cl /EHsc /I%GTEST_HOME% /I%GTEST_HOME%/include -I%GMOCK_HOME% ^ -I%GMOCK_HOME%/include main.cpp src/manchester/Man_Encode.cpp ^ src/manchester/Man_Decode.cpp %GTEST_HOME%/src/gtest-all.cc ^ %GMOCK_HOME%/src/gmock-all.cc main.exe

При использовании Linux + gcc g++:
GTEST_HOME=gtest-1.6.0 GMOCK_HOME=gmock-1.6.0 g++ -g -I$GTEST_HOME -I$GTEST_HOME/include -I$GMOCK_HOME \ -I$GMOCK_HOME/include -pthread main.cpp src/manchester/Man_Encode.cpp \ src/manchester/Man_Decode.cpp $GTEST_HOME/src/gtest-all.cc \ $GMOCK_HOME/src/gmock-all.cc ./a.out

Тестов много не бывает. Например, было бы неплохо добавить проверку для последовательности из двух байт и более, или проверку условия отсутствия невозможных для Манчестерского Кода комбинаций — например 111 или 000. Чем больше терпения и выдержки на этом этапе разработки — тем крепче будет сон после её сдачи в эксплуатацию.
Практика
Тесты это хорошо, но пока что всё это больше похоже на теорию — а теория без практики, как известно, скучна. Поэтому, если Вы дочитали до этого момента, милости прошу посетить следующий пост, в котором в качестве приёмника и передатчика используются два микроконтроллера, а сам процесс эмулируется в виртуальной среде, которая умеет моделировать поведение электрических цепей.
Исходники к текущему посту на GitHub.