Комментарии

к официальному описанию протокола LinkBell

Протокол LinkBell предназначен для применения в устройствах, содержащих микроконтроллеры, и поэтому не должен требовать для работы значительных ресурсов, особенно памяти. С другой стороны, он должен выполнять задачу, возлагаемую на протокол - "прозрачно" передать информацию от отправителя к получателю по имеющимся линиям связи. Нередко линии связи накладывают ограничение на сигнал: например, независимость постоянной составляющей сигнала от передаваемой информации, или узкий частотный диапазон. Когда такие требования есть, может применяться, например, кодирование типа "Манчестер-2". Сигнал, формируемый с применением протокола LinkBell, этим требованиям удовлетворяет. Разумеется, ничего не даётся бесплатно, и расплачиваться приходится в два раза более низкой пропускной способностью канала при заданной скорости передачи битов. Впрочем, это же характерно и для "Манчестера-2". Для приёма и передачи информации можно применять UART - приёмопередатчик последовательных данных, имеющийся в большинстве микроконтроллеров, а также COM-порт компьютера. Это упрощает реализацию протокола в устройствах.

Коды CRC для блоков по 16 байтов определяются по методу и с применением образующего полинома, взятых из описания протокола Modbus RTU. Порядок битов в байтах кода CRC соответствует порядку битов в остальных байтах. Код CRC так же, как адреса устройств, передаётся начиная со старшего байта. Это вызвано желанием упростить отладку программного обеспечения пользователем, ведь такой порядок привычнее для восприятия. Процедура подсчёта CRC может быть выполнена, например, так (пример функции на языке Си):

#define CRC_POLYNOME 0xA001 //corresponds to X^16+X^15+X^2+X^0

unsigned int common_flags;

unsigned int CalcCrc(unsigned int crc, unsigned char data)

{

unsigned int result;

char i;

result=crc^(unsigned int)data;

for(i=0;i<8;i++)

{

if(result%2) common_flags|=(1<<CRC_AUX_FLAG);

else common_flags&=~(1<<CRC_AUX_FLAG);

result=result>>1;

if(common_flags&(1<<CRC_AUX_FLAG))

result=result^CRC_POLYNOME;

}

return result;

}

Здесь common_flags - глобальная переменная, один бит которой (CRC_AUX_FLAG) выделен для потребности функции CalcCrc. Перед расчётом CRC для принятого или передаваемого блока байтов следует инициализировать переменную crc значением, равным FFFFh для проводных сетей или (FFFFh-SYSNO) для радиосетей. SYSNO - идентификатор сети, его значение у сетей, в которых возможно попадание сигнала из одной в другую, должно различаться. Тогда данные из "чужой" сети не будут обработаны, так как подсчитанный код CRC не совпадёт с переданным. После инициализирования переменной crc следует вызвать функцию CalcCrc столько раз, сколько байтов защищается кодом CRC.

Контрольный пример. Расчёт CRC16 для двух байтов 02h и 07h, если SYSNO=0, должен дать значение crc=1241h, расчёт CRC16 для байтов 02h, 07h, 41h и 12h должен дать значение crc=0000h.

Кодирование информации сетевого уровня на канальном призвано, во-первых, обеспечить свойства сигнала, подобные кодировке "Манчестер-2" (описанные выше), во-вторых, получить значения байтов для маркеров начала и конца кадра и преамбулы, отличающиеся от любых значений байтов внутри кадра. Кодирование нибблов в байты выполняется так, что из двух идущих подряд битов второй является инверсией первого:

Разряд ниббла

Разряды байта

N0

B1 = N0, B0 = /N0

N1

B3 = N1, B2 = /N1

N2

B5 = N2, B4 = /N2

N3

B7 = N3, B6 = /N3

Здесь "/" означает инверсию значения бита.

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

Передача преамбулы преследует две цели. Во-первых, нельзя передавать информацию сразу же после включения передатчика, ведь и он, и иногда какие-то устройства в приёмнике должны выйти на установившийся режим, а на это требуется определённое время, до десятков и даже сотен миллисекунд. Во-вторых, в некоторых каналах имеется или возможен шум, который UART контроллера может воспринимать как биты сигнала, в том числе старт- и стоп-биты. После подачи в канал осмысленной информации UART может не найти старт-бит. Поэтому в начале передачи следует подать такую последовательность единиц и нулей, чтобы UART смог найти в ней правильное положение старт- и стоп-битов, то есть синхронизироваться. Принятая последовательность байтов преамбулы (B2h и 4Dh) обладает свойством самосинхронизации на периоде в 4 повтора этих кодов, то есть после передачи B2h 4Dh B2h 4Dh B2h 4Dh B2h 4Dh UART готов к приёму байтов.

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

Пример сборки пакета

Исходные данные: пусть в сети с идентификатором 10 (000Ah) от устройства с идентификатором 1000 (03E8h) требуется передать устройству с идентификатором 100 (0064h) число типа unsigned long, равное 3735928559, или DEADBEEFh :-) (tnx to Oleksandr Redchuk). Ретрансляция не требуется.

Прикладной уровень: число записывается 4 байтами: EFh BEh ADh DEh.

Сетевой уровень: добавляется заголовок длиной 6 байтов. Получается:

06h 00h 00h 64h 03h E8h EFh BEh ADh DEh

Канальный уровень: для указанной последовательности значение кода CRC16, инициализированного значением FFFFh - 000Ah = FFF5h, равно E25Dh.

Таким образом, информация перед преобразованием нибблов принимает вид:

E2h 5Dh 06h 00h 00h 64h 03h E8h EFh BEh ADh DEh

Далее происходит преобразование каждого ниббла по таблице, после чего получается:

A9h 59h 66h A6h 55h 69h 55h 55h 55h 55h 69h 65h 55h 5Ah A9h 95h A9h AAh 9Ah A9h 99h A6h A6h A9h

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

B2h 4Dh B2h 4Dh B2h 4Dh B2h 4Dh 2Bh A9h 59h 66h A6h 55h 69h 55h 55h 55h 55h 69h 65h 55h 5Ah A9h 95h A9h AAh 9Ah A9h 99h A6h A6h A9h 4Bh

(с) Michael G. Belousoff