Протокол обмена WAKE16
Протокол WAKE16 является логическим уровнем интерфейса управления оборудованием с помощью асинхронного последовательного канала.
Физический уровень интерфейса протоколом не определяется. В качестве него может использоваться, например, RS-232 или RS-485.
Протокол позволяет производить обмен пакетами данных длиной до 216 байт с адресуемыми устройствами, которых может быть до 215 – 1.
Последовательный канал должен быть сконфигурирован следующим образом:
- Число байт в посылке – 8
- Количество стоп-бит – 1
- Бит чётности – нет
- Скорость обмена – 1200 ÷ 921600 бит/сек
- использование линий управления модемом – произвольное.
Основой протокола WAKE16 является протокол SLIP (UNIXTM Serial Link Interface Protocol).
Передача данных осуществляется в двоичном виде, то есть используются все возможные значения байта (0x00...0xFF).
Для передачи служебной информации зарезервированы два кода: FEND = 0xC0 (Frame End) и FESC = 0xDB (Frame Escape).
Управляющий код FEND служит для обозначения начала посылки, а код FESC служит для передачи ESC-последовательностей.
Если в потоке данных встречаются байты, значения которых совпадают с управляющими кодами, производится подмена этих байт ESC-последовательностями.
Этот механизм называют байт-стаффингом. Код FEND заменяется последовательностью <FESC>, <TFEND>, а код FESC – последовательностью <FESC>,
<TFESC>, где TFEND = 0xDC (Transposed FEND), TFESC = 0xDD (Transposed FESC).
Коды TFEND и TFESC являются управляющими только в ESC-последовательностях, поэтому при передаче данных они в подмене не нуждаются.
Структура пакета
Пакет всегда начинается управляющим кодом FEND (0xC0). Затем следует необязательный байт адреса, после которого идет байт команды.
За ним следует байт количества данных и собственно байты данных. Завершает пакет байт контрольной суммы CRC16:
FEND |
ADDR |
CMD |
N |
Data1 |
... |
DataN |
CRC16 |
FEND: управляющий код FEND (0xC0) является признаком начала пакета. Благодаря стаффингу, этот код больше нигде в потоке данных не встречается,
что позволяет в любой ситуации однозначно определять начало пакета.
ADDR: 16-битное слово адреса используется для адресации отдельных устройств. На практике распространена ситуация, когда управление осуществляется
только одним устройством. В таком случае слово адреса не требуется, и его можно не передавать. Вместо него сразу за кодом FEND передается байт команды CMD.
Для того чтобы можно было однозначно установить, к адресу или команде относится второй байт пакета, введены некоторые ограничения.
Для адресации используется 15 бит, а старший бит, передаваемый вместе с адресом, должен всегда быть установлен в единицу:
|
D15 |
... |
D1 |
D0 |
ADDR= |
1 |
... |
A1 |
A0 |
Иногда возникает необходимость передать какую-то команду или данные сразу всем устройствам. Для этого предусмотрен коллективный вызов, который
осуществляется путем передачи нулевого адреса (учитывая единичный старший бит, в этом случае передаваемый адрес равен 0x8000).
Нужно отметить, что передача в пакете нулевого адреса полностью аналогична передаче пакета без адреса.
Поэтому при реализации протокола можно автоматически исключать нулевой адрес из пакета.
Учитывая разрядность адреса и один зарезервированный адрес для коллективного вызова, максимальное количество адресуемых устройств составляет 215 – 1.
Если возникает необходимость передать значение адреса, содержащие значения 0x40 или 0x5B (передаваемый байт в этом случае будет равен 0xC0 или 0xDB),
то производится байт-стаффинг. Поэтому следует учитывать, что устройства с такими адресами требуют большей длины пакета.
Это может быть заметно в тех случаях, когда используются короткие пакеты. В таких случаях следует избегать назначения устройствам названных адресов.
CMD: байт команды всегда должен иметь нулевой старший бит:
|
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
CMD= |
0 |
C6 |
C5 |
C4 |
C3 |
C2 |
C1 |
C0 |
Таким образом, код команды занимает 7 бит, что позволяет передавать до 128 различных ко-манд. Коды команд выбираются произвольно в зависимости от
нужд приложения. Рекомендуется использовать несколько стандартных кодов команд:
Код |
Описание команды |
0x01 |
Передача управления основной программе центрального контроллера |
0x02 |
Передача управления загрузчику центрального контроллера |
0x03 |
Чтение блока FLASH-памяти центрального контроллера |
0x04 |
Запись блока FLASH-памяти центрального контроллера |
0x08 |
Сброс устройства |
0x71 |
Запрос информации об устройстве |
0x7A |
Изменение адреса устройства |
Команды обычно имеют несколько параметров, которые передаются далее в виде пакета данных.
Поскольку код команды всегда имеет нулевой старший бит, этот код никогда не совпадает с управляющими кодами.
Поэтому при передаче команды байт-стаффинг никогда не производится.
N: имеет значение, равное числу передаваемых байт данных. Под величину N отводится два байта:
|
D15 |
... |
D1 |
D0 |
N= |
0 |
... |
N1 |
N0 |
Таким образом, один пакет может содержать до 216 байт данных. Значение N не учитывает служебные байты пакета FEND, ADDR, CMD, N и CRC16.
В результате байт-стаффинга фактическая длина пакета может возрасти. Значение N не учитывает этот факт и отражает количество полезных байт данных
(то есть значение N всегда таково, как будто байт-стаффинг не осуществляется).
Если передаваемая команда не имеет параметров, то передается N = 0x0000 и байты данных опускаются.
Если возникает необходимость передать значение N, равное 0xC0 или 0xDB, то производится байт-стаффинг.
Однако при таких больших значениях N длина пакета столь велика, что его удлинение ещё на один байт практически незаметно.
Data1...DataN: байты данных, количество которых определяется значением N. При N = 0 байты данных отсутствуют.
Байты данных могут иметь любое значение, кроме FEND (0xC0) и FESC (0xDB). Если возникает необходимость передать одно из этих значений, то производится байт-стаффинг.
СRC: 16-битное слово контрольной суммы CRC16. Контрольная сумма рассчи-тывается перед операцией байт-стаффинга для всего пакета, начиная с байтов адреса
(или байта команды, если адреса нет) и заканчивая последним байтом данных. При вычислениях используется значение адреса вместе со старшим битом.
Для расчёта контрольной суммы используется полином CRC16 = X16 + X12 + X5 + 1 ([1] 0001 0000 0010 0001 = 0x1021). Значение CRC16 перед
вычислением инициализируется числом 0xFFFF. Если CRC16 содержит значения байтов 0xC0 и 0xDB, то они заменяются ESC-последовательностями.
Функция для вычисления CRC16 показана ниже (используется "зеркальный" полином 1000 0100 0000 1000 [1] = 0x8408):
void UpdateCRC16 (char b)
{
char i;
CRC16 ^= b;
for (i = 8; i > 0; i--)
if (CRC16 & 1)
CRC16 = (CRC16 >> 1) ^ 0x8408;
else
CRC16 >>= 1;
}
Эту функцию следует вызвать для каждого байта, в результате чего переменная CRC16 будет содержать вычисленное значение контрольной суммы.