Ru-Devices Communication Network Protocol

From endrobene wiki :: ITE
Jump to: navigation, search

Contents

Параметры UART

Физический интерфейс: только линии RXD+TXD. Режим передачи: асинхронный

Baud rate = 57600 (Без удвоения скорости в микроконтроллерах AVR)
Data bits = 8
Parity = none
Stop bits = 1
Handshaking = none

Структурная схема сетевой связи с устройствами

Пакет данных

Данные передаются от компьютера к устройству и обратно цельными пакетами. Оборванные пакеты системой передачи данных игнорируются. Если пакет был оборван с особой виртуозностью - может наступить длительный цикл ожидания и повисание сетевой передачи. Следующие версии будут бороться с этим при помощи таймера.

Структура пакета данных

Пакет данных состоит из двух блоков:

Заголовок пакета сетевого протокола связи с устройствами. The header of the Devices Communication Network Protocol (UART)

Заголовок пакета данных

Заголовок пакета данных на языке C описывается в таком виде:

// header follows any response or request (see code section)
typedef struct tagNET_PACKETHEADER
{
	UCHAR signature1; // байт №1 подписи заголовка
	UCHAR signature2; // байт №2 подписи заголовка
	UCHAR length;     // длинна данных в байтах, которые следуют за заголовком
	UCHAR cmd;        // код команды
} NET_PACKETHEADER;

Подпись (SIGNATURE)

Начало каждого заголовка пакета данных содержит два байта подписи. Они определены как:

const UCHAR NET_SIGNATURE1 = 0xFF;
const UCHAR NET_SIGNATURE2 = 0xFE;

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

Длинна дополнительных данных (LENGTH)

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

Таким образом команда может предусматривать одно количество дополнительных байт данных, а отправлено может быть другое. Если отправлено меньше байт, чем предусмотрено командой - такая команда с заголовком записывается как ошибочная, и вся команда с принятыми дополнительными данными игнорируется (на неё также не производится ответ-подтверждение). Если отправлено больше данных, чем предусмотрено форматом команды, лишние принимаемые байты должны быть просто проигнорированы.

Команды (CMD)

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

Правило именования команд: команды в названии которых отсутствует префикс SET используются только для чтения состояния устройства и не изменяют внутренней конфигурации устройства.

Код команды который обычно указывается - это код запроса (REQ или REQUEST). Запрос - команда от компьютера (клиент) к микроконтроллеру устройства (серверу). Когда микроконтроллер формирует пакет ответа, он должен установить старший бит данных кода команды в единицу, или попросту выполнить логическую операцию OR с константой NET_ANS_COMMAND_MASK:

// this is a request code, MCU answers by setting highest bit to the answer's cmd
const UCHAR NET_ANS_COMMAND_MASK = 0b10000000; // 0x80

Таким образом, если, например, код входной команды был равен 0x03 (0b00000011 в двоичной), то код ответа будет равен 0b10000011 в двоичной системе счисления (или 0x83 в шестнадцатеричной).

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

Дополнительные данные (Extra)

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

Неспецифичные для устройства команды

Неспецифичные команды являются общеподдерживаемыми для всех устройств ITE на линии связи UART (Com-порт компьютера и UART приемопередатчик контроллера устройства).

Эхо (ECHO)

Команда Эхо полезна для того, чтобы определить, есть ли на линии устройство. Поскольку в бортовом компьютере установлено восемь или более COM-портов, то на каждом из них может быть одно отдельное устройство. Для того, чтобы не привязывать каждый номер COM-порта к своему устройству следует использовать алгоритм инициализации, который предусматривает последовательный опрос портов с определением присутствия устройства на линии, типа, имени и возможностей устройства.

Если устройство присутствует на линии, то оно должно ответить на команду Эхо. Принятый компьютером через COM-порт пакет с ответом означает, что на линии есть устройство, с которым можно продолжать работу.

Код команды Эхо, а также размер дополнительных данных на языке C описывается в таком виде:

const UCHAR NET_CMD_REQ_ECHO = 0x01; // код команды Эхо
 
// Размеры дополнительных данных для запроса и ответа на команду Эхо
const UCHAR NET_CMD_SIZE_REQ_ECHO = 0; // размер входящих к контроллеру дополнительных данных для пакета Эхо
const UCHAR NET_CMD_SIZE_ANS_ECHO = 0; // размер отправляемых контроллером дополнительных данных для пакета Эхо

Запрос класса устройства (DEVICECLASS)

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

Код команды Запрос класса устройства равен:

const UCHAR NET_CMD_REQ_DEVICECLASS = 0x02; // код команды-запроса класса устройтсва

Класс устройтсва - это однобайтное число, которое равно одному из следующих:

// === ITE HARDWARE MODULE DEVICE CLASS ===
const UCHAR DEVICE_CLASS_CDC = 1;          // Контроллер направления камеры
const UCHAR DEVICE_CLASS_PMC_MOTION = 2;   // Контроллер управления движением - маршевый
const UCHAR DEVICE_CLASS_PMC_ROTATION = 3; // Контроллер управления движением - поворот колес 
const UCHAR DEVICE_CLASS_PPC = 4;          // Первичный распеределитель питания
const UCHAR DEVICE_CLASS_NAVI = 5;         // Модуль навигации

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

// дополнительных данных запроса у DEVICECLASS нет.
 
// дополнительные данные ответа DEVICECLASS
typedef struct tagNET_PACKET_ANS_DEVICECLASS
{
	UCHAR device_class;
} NET_PACKET_ANS_DEVICECLASS;
 
const UCHAR NET_CMD_SIZE_REQ_DEVICECLASS = 0; // размер дополнительных данных запроса
const UCHAR NET_CMD_SIZE_ANS_DEVICECLASS = sizeof(NET_PACKET_ANS_DEVICECLASS);

Запрос имени устройства (DEVICENAME)

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

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

Код команды Запрос имени устройства и формат его дополнительных данных описываются так:

const UCHAR NET_CMD_REQ_DEVICENAME = 0x03; // код команды запроса имени устройства
 
// формат дополнительных данных ответа для команды DEVICENAME
typedef struct tagNET_PACKET_ANS_DEVICENAME
{
	UCHAR devicename[20]; // строка должна быть ноль-завершенной
} NET_PACKET_ANS_DEVICENAME;
 
// размер дополнительных данных запроса
const UCHAR NET_CMD_SIZE_REQ_DEVICENAME = 0;
 
// размер дополнительных данных ответа
const UCHAR NET_CMD_SIZE_ANS_DEVICENAME = sizeof(NET_PACKET_ANS_DEVICENAME);

Пример ответа для контроллера камеры:

const UCHAR NET_DEVICE_NAME[] = "CDC ver. 5.0"; // коротко, лаконично и ничего не понятно - выдержан фирменный стиль
const UCHAR NET_DEVICE_NAME[] = "C'); DROP TABLE ITE"; // деструктивный подход к решению проблем

Как указывалось выше, длинна дополнительных данных ответа не зависит от фактической длинны нуль-терминированной C-строки имени устройства.

Запрос возможностей устройства (DEVICECAPS)

Установка конфигурации устройства (SETCONFIG)

(вспомогательная команда)

Установка времени (SETTIME)

(вспомогательная команда)

Установка таймера (SETTIMER)

(вспомогательная команда)

Пуск таймера (STARTTIMER)

(вспомогательная команда)

Останов таймера (STOPTIMER)

(вспомогательная команда)

Получение значения таймера (GETTIMER)

(вспомогательная команда)

Запуск бутлоадера (UPDFIRM)

Переводит модуль в режим обновления прошивки.

Код команды, а также размер дополнительных данных на языке C описывается в таком виде:

#define NET_CMD_UPDFIRM 0x09 //***
 
// Размеры дополнительных данных для запроса обновления прошивки
#define NET_CMD_SIZE_UPDFIRM 4
 
// Последовательность для предотвращения случайного запуска бутлоадера - и есть дополнительные данные:
#define NET_CMD_ESCAPESEQ_UPDFIRM 0x12345678

*** код можно и поменять

Процедура обновления прошивки модуля

Шаг первый

Для начала необходимо вызвать сам бутлоадер отправкой следующей последовательности:

Signature Length Cmd Payload
0xFF 0xFE 0x04 0x09 0x12 0x34 0x56 0x78

Ответ контроллера при успешном запуске бутлоадера:

Signature Length Cmd
0xFF 0xFE 0x00 0x89
Шаг второй

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

Signature Length Cmd Page Address Data Control sum
0xFF 0xFE LL 0x09 A0 A1 D0 D1 ... D(n-1) Dn CC

где:

- A0A1 - адрес начала (или любой точки страницы - в принципе, не важно), в которую осуществляется запись;
- LL = 2 + length(Data) + 1 - обычная длина пакета - 2 байта адреса, кол-во байт данных, 1 байт контр. суммы;
- CC = A0 + A1 + D0 + D1 + ... + D(n-1) + Dn - формула вычисления контрольной суммы;


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

Signature Length Cmd Payload
0xFF 0xFE 0x01 0xFF Cs

где:

Cs - контрольная сумма, подсчитанная контроллером модуля;


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

Пример: Atmega168 (размер страницы 64 слова). После выполнения следующей команды

Signature Length Cmd Page Address Data Control sum
0xFF 0xFE 0x08 0x09 0x30 0x00 0xAA 0xBB 0xCC 0xDD 0xEE 0x2C

Фрагмент памяти имеет вид:

...........................................
:102F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81
:102F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71
:102F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61
:102F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51
:102F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41
:102FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31
:102FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21
:102FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11
:102FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01
:102FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1
:102FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1
:10300000AABBCCDDEE0000000000000000000000C4
:1030100000000000000000000000000000000000B0
:1030200000000000000000000000000000000000A0
:103030000000000000000000000000000000000090
:103040000000000000000000000000000000000080
:103050000000000000000000000000000000000070
:103060000000000000000000000000000000000060
:1030700000031B031B0125001A00000000FFFF01D5
:10308000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50
:10309000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40
:1030A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30
:1030B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20
:1030C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10
:1030D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:1030E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
:1030F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:10310000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF
:10311000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF
...........................................

Бросается в глаза всякий мусор, который записался начиная с адреса 0x3070.

Ответ контроллера об успешной записи страницы:

Signature Length Cmd
0xFF 0xFE 0x00 0x89

Во время записи страницы горит индикаторный светодиод на модуле.

Далее можно повторять шаг 2-й до тех пор, пока все данные не будут записаны.

Шаг третий

После выполнения записи новой прошивки командой

Signature Length Cmd
0xFF 0xFE 0x00 0x09

осуществляется выход из режима бутлоадера и автоматическая перезагрузка модуля.

Специфичные для устройства команды

В зависимости от типа устройства (класса устройства), оно может поддерживать несколько специфичных для него команд. Коды команд, а также формат дополнительных данных и формат ответа следует искать в документации к прошивке этих устройств. Тем не менее, известно, что все специфичные для устройства команды имеют код больший или равный константе NET_CMD_REQ_DEVICE_SPECIFIC:

// this is the minimum device-specific request code
const UCHAR NET_CMD_REQ_DEVICE_SPECIFIC = 0x20;
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox