Psion Link Protocol


Это первая часть перевода описания протокола обмена ПДА Psion. Документ достаточно объемный, поэтому прошу меня не пинать ногами если процесс будет идти несколько медленно.

Psion Link Protocol

Версия 1.04, от 02 июня 2000
by Alexander Thoukydides (alex@thouky.co.uk)
Copyright (C) Alexander Thoukydides.
Перевод Андрей А. Породько Copyright (C).

Вы можете свободно копировать, передавать и/или модифицировать данный документ на условиях лицензии GNU (GNU Free Documentation License), версии 1.1 или другой, более поздней, опубликованной Free Software Foundation; без частей помеченных как "Неизменная", без титульных листов. Копия лицензии "GNU Free Documentation License".

Введение

Операционные системы SIBO и EPOC (ОС для ПДА Psion и родственных ему, EPOC относится к Psion Series 5 и выше, SIBO для предыдущих версий, прим. пер.) используют свой собственный протокол для обмена по последователным линиям. Данный протокол называется Psion Link Protocol (PLP), и позволяет осуществлять удаленный доступ к файловой системе данных ОС и решения вопросов синхронизации. Данный документ представляет собой попытку предоставить достаточную информацию для создания клиентских приложений использующих связь устройствами на базе SIBO или EPOC через протокол PLP.

Свежую версию оригинального можно найти на http://www.thouky.co.uk/software/psifs/plp.html.

История

ВерсияДатаАвторОписание
1.042 июня 2000 г.Alexander ThoukydidesДокумент опубликован на условиях лицензии GNU версии 1.1 для документации.
1.0321 апреля 2000 г.Alexander ThoukydidesИправлен HTML код. Обновлена адреса email. Добавлена ссылка на последнюю версию.
1.0223 анваря 2000 г.Alexander ThoukydidesДобавлено детальное описание функций NCP_SET_TIME и NCP_GET_MACHINE_INFO.
1.0122 декабря 1999 г.Alexander ThoukydidesДобавлено описание для большинства команд сервера RFSV.
1.0009 декабря 1999 г.Alexander ThoukydidesПредварительная версия.Отсутствует описание RFSV-сервера.

Отказ от гарантий

Данный документ приводится "как есть"; без каких бы то либо гарантий. (Далее следуют обычные в таком случае изъявления на этот счет, я их опускаю, так как это касается юридической стороны, а мне бы не хотелось ее исказить. прим. пер.) Все торговые марки признаются за их владельцами.

Благодарности.

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

Уровни

Протокол PLP состоит из набора уровней которые некоторым образом соотносятся с моделью OSI :

Уровень OSIНазвание в ОС EPOCОписание
7Прикладнойнеприменимо
6ПредставительныйLINK, RPCS, RFSV и т.д.Множество сервером, каждый из которых предоставляет свой уровень сервиса
5СеансовыйNCPМультиплексор для организации множественных каналов клиент-сервер с communications channels включая кправление потоком (flow control)
4Транспортныйнеприменимо
3Сетевойнеприменимо
2КанальныйLinkСинхронизация, обнаружение и коррекция ошибок
1ФизическийRS-232

Соглашения

Если не указано обратное, действуют следующие соглашения:

Физический уровень

На самом нижнем уровне PLP использует стандартный протокол RS-232. В зависимости от конкретного устройства, использующего EPOC, может понадобится специальный кабель.

Линии DTR и RTS переводятся в 1 если соединения PLP установлено и сбрасываются в случае рассоединения. Таким образом, достаточно контролировать сигнал DTR для определения активности устройства с EPOC.

Любая скорость передачи поддерживаемая устройствами может быть использована. Формат данных 8,1,N (8-бит данных, 1 стоп-бит, без четности).

Канальный уровень

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

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

Формат кадра (пакета)

Все данные передаются кадрами (пакетами) следующего формат:

Размер (байт)1111n112
ПолеSYNDLESTXContSeqDataDLEETXCRC

Поля Cont и Seq объединены в один байт, где Cont -- это старший полубайт, а Seq младший. Если величина поля Seq больше 7, то выставляется наиболее значащий в поле Seq и в кадр добавляется дополнительный байт (только вариант EPOC):

Размер (байт)11111n112
ПолеSYNDLESTXCont(Seq & 7) | 8Seq >> 3DataDLEETXCRC

Длина поля Data field (n) может варьироваться в пределах от 0 до 300 байт. Сеансовый (NCP) обязан разбивать более длинные данные (и собирать их) на части умещающиеся в данные пределы. 16-ти битная циклическая контрольная сумма (CRC) передается в порядке, обратном принятому для других данных -- более значащий байт идет первым.

Специальные символы

В протоколе используются следующие специальные символы:

НазваниеЗначениеОписание
STX0x02Начало пакета
ETX0x03Конец пакета
EOT0x04Символ-затычка для ETX (A stuffed ETX character)
DLE0x10Разделитель полей в пакете
SYN0x16Байт синхронизации начала пакета

При предотвращения неправильного распознавания управляющих символов внудтри пакета, используется система подстановок. Для этого любые символы DLE которые могут встретится в полях Cont/Seq и Data при передаче заменяются двойным символом DLE (DLE DLE), соответственно на приемной стороне такие пары должны бать ообратно преобразованы в одиночные символы данных. Вариает протокола для EPOC также заменяет байты ETX последовательностью DLE EOT.

Циклическая контрольная сумма

Для получения CRC используется стандартный полином x16 + x12 + x5 + 1. Сумма вычисляется для полей Cont/Seq и Data до описанных выше подстановок. Следующий пример C-кода выполняет расчет CRC:
static const int table[] =
{
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

new_crc = (old_crc << 8) ^ table[((old_crc >> 8) ^ value) & 0xff];
где value -- это байт, который нужно добавить к текущей сумме (old_crc) для получения новой суммы CRC (new_crc). Значение CRC должно быть инициализировано 0 до обработки любых данных. Возможно необходимо воспользоваться беззнаковыми величинами для предотвращения системных проблем с 16-ти битными целыми.

Таймеры

Используются два события по таймеру для определения таймаутов:

СобытиеВеличина
ПерепосылкаЗависит от скорости обмена
НеактивностьЗависит от конкретного приложения

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

КомпонентаОписание
Фактор скорости обменаДля определения времени, необходимого для передачи битов пакета при заданной скорости, подходящий таймаут можно вычислить как (13200/скорость в bps) секунд.
Время на обработкуДополнительное время, необходимое для обработки и посылки подтверждения. Как правило, для большинства применений достаточно использовать постоянную задержку в 0.2 секунды.
Фактор возвратаДополнительное время, зависящее от количества уже сделанных перепосылок. В простых приложениях может быть опущен.

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

Таймер Неактивности может быть подогнан под конкретное приложение. Если не используется проверка на простой соединения, то он может быть полностью запрещен. В других случаях рекомендуется таймаут в 60 секунд.

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

Элементы протокола данных (Protocol Data Units, PDU)

Всего возможно четыре основных типа пакетов или элементов данных протокола (Protocol Data Unit ,PDU):

НомерПоследовательность
(номер пакета)
НаименованиеОписание
0Номер пакета последнего правильно принятого пакета (Data_Pdu)Ack_PduИспользуется для завершения процедуры подтверждения в процеесе установления, и для подтверждения приема пактов данных (Data_Pdu frames).
10Disc_PduИспользуется для завершения соединения.
 1Disc_Req_PduПервое рассоединение в подтверждение разрыва связи. В настоящей реализации не используется.
20Req_PduИспользуется на шаге установления соединения как запрос на подключение.
 1...3 (use 1)Req_Req_PduПервый запрос в процессе установки соединения. Только для варианта протокола EPOC.
 4...6 (use 4)Req_Con_PduОтвет за запрос соединения. Только для варианта протокола EPOC.
3Next sequence numberData_PduПакет данных.

Только пакеты типа Data_Pdu и Req_Con_Pdu содержат поле "Данные" (Data field).

Пакеты Data_Pdu и Ack_Pdu содержат "последовательный номер пакета" (sequence number, далее просто "номер пакета"). Номер пакета используется для идентификации пакетов при отправке подтверждения приема. Каждое устройство поддерживает свою последовательность номеров пакетов, который (номер) увеличивается при отправке очередного пакета Data_Pdu, номер вычисляется по модулю 8 для варианта протокола SIBO или по модулю 2048 для варианта EPOC. Подробности можно найти в следующих разделах описания.

Порядок соединения

Порядок соденияния для SIBO и EPOC незначительно отличаются. Оригинальная реализация варианта протокола SIBO имеет ошибку связанную с эхом модема (modem echo problem), в этом случае уровень data link может установить связь сам с собой если на последовательном порту имеется заглушка; проблема решена в реализации варианта протокола EPOC.

Поддерживаются режимы соединения точка-точка и клиент-сервер. Точка-точка представляет собой симметричный вариант последовательности соединения клиент-сервер, при котором оба устройства отрабатывают все типы пакетов (PDUs).

Вариант SIBO

Соединение клиент-сервер инициируется клиентом:

От клиентаОт сервераОписание
Req_Pdu Запрос соединения клиентом
 Req_PduЗапрос соединения подтвержден
Ack_Pdu Соединение установлено

Соединение точка-точка очень похоже:

От устройства 1От устройства 2Description
Req_PduReq_PduОба устройства запрашивают соединение
Ack_PduAck_PduОба устройства подтверждают соединение

В обоих случаях "номер пакета" (sequence numbers) должны быть сброшены в 0, и пакет типа Ack_Pdu посылается с полем Seq, установленным в 0. Однако, если принятый пакет Ack_Pdu содержит не ноль, в поле Seq "номер пакета" (sequence number) должен быть проинициализирован указанным числом.

Вариант EPOC

Соединение клиент-сервер инициируется клиентом:

От клиентаОт сервераОписание
Req_Req_Pdu Запрос соединения клиентом
 Req_Con_PduЗапрос соединения подтвержден сервером
Ack_Pdu Соединения установлено

Соедиение точка-точка происходит сходным образом:

От устройства 1От устройства 2Описание
Req_Req_PduReq_Req_PduОба устройства запрашивают соединение
Req_Con_PduReq_Con_PduОба устройства подтверждают запрос на соединение
Ack_PduAck_PduОба устройства принимают соединение

Поле Data field пакета Req_Con_Pdu содержит четырех-байтовое "магическое" число (4 byte magic number). Это псевдо-случайное число генерируется независимо каждым устройством. Если "магические" числа совпадают, значит, соединение точка-точка отвергается, так как это указывает, что устройство пытается соединится само с собой. Для уменьшения риска получения двух одинаковых псево-случайных чисел обоими устройствами, полезным будет включить дополнительно в это число какой-нибудь уникальный элемент, например значение времени.

В обоих случаях номер пакета должен быть сброшен в ноль, и пакет Ack_Pdu должен быть послан с полем Seq равным 0. Тем не менее, если полученный пакет Ack_Pdu содержит не нулевое поле Seq, номер пакета должен быть проинициализирован полученным числом.

Если пакет Ack_Pdu не был получен в течение таймаута перепосылки (re-transmission timeout), пакет Req_Req_Pdu может быть повторно послан еще 4 раза, прежде чем следует прервать попытки соединения.

Универсальная процедура соединения

При недольших дополнительных расходах возможно реализовать оба варианта протокола в пределах одного конечного автомата (within a single state machine). Максимальное значение для номеров пакетов, в этом случае, выбирается после определения типа.

Пакет Req_Req_Pdu всегда может быть использован для инициирования соединения; устройство поддерживающее вариант протокола EPOC просто ответит пакетом Req_Con_Pdu, а устройства, поддерживающие вариант SIBO, будут интерпретировать его как Req_Pdu и ответят пактом Ack_Pdu. Следовательно, вариант протокола может быть определен по пакету Req_Con_Pdu, полученному до пакета Ack_Pdu.

Соответственно, если другое устройство инициировало соединение, то вариант протокола может быть выбран в зависимости от того, какой пакет был принят: Req_Pdu или Req_Req_Pdu.

Последовательность передачи данных

Уровень передачи данных использует только одно окно (is single windowed), т.е. только одно подтверждение приема может быть обработано за один раз. Это гарантирует, что необходим только один буфер на прием, и один на передачу. Однако, из-за асинхронной природы обмена данными, передача пакета и получение подтверждения на него в каждом направлении могут быть разнесены во времени.

Последовательность обмена данными одинакова для обоих (SIBO и EPOC) вариантов протокола. Оба устройства могут инициировать передачу данных, при этом посылая подтверждение на ранее полученные данные.

От устройства 1От устройства 2Описание
Data_Pdu Посылка данных
 Ack_PduПодтверждение приема

Здесь существует только одно различие между вариантами SIBO и EPOC, как было описано ранее: диапазон используемых номеров пакетов (sequence numbers). Это число по модулю 8 (от 0 до 7, прим. пер.) для варианта SIBO. И по модулю 2048 (от 0 до 2047, прим. пер.) для варианта EPOC. Номер пакета увеличивается на 1 до посылки пакета с данными (Data_Pdu).

Подтверждение Ack_Pdu должно посылаться всегда в ответ на полученный пакет Data_Pdu, даже если номер пакета (sequence number ) не совпал с ожидаемым. Однако, поле Seq в пакете Ack_Pdu должно быть равно номеру последнего правильно принятого пакета, и совсем не обязательно является подтверждением на полученный Data_Pdu (However, the Seq field of the Ack_Pdu should be set to the value from the last valid Data_Pdu received, not necessarily that of the Data_Pdu being responded to).

Если подтверждение Ack_Pdu не было получено в течении таймаута перепосылки (re-transmission timeout), или если подтверждение содержит неверный номер пакета (отличающийся от посланного с данными), пакет данных может быть повторно послан еще до 8 раз, прежде чем соединение будет разорвано. Номер павета при перепосылке меняться не должен.

Последовательность рассоединения

В протоколе PLP не предусматривается никаких подтверждений при рассоединение, поэтому существует риск, что одно устройство отсоединится без уведомления другого. Предполагалось, что варианте EPOC исправить это положение, однако не видно, чтобы это было сделано.

Рассоединение также может произойти, если последовательный кабель был физически отключен от устройства, как было описано ранеее, для этого надо следить за линией DSR. Дополнительно, если по истечение таймаута неактивности (inactivity timeout) не было принято ни одного пакета, это может служить сигналом к рассоединению.

Рассоединение в варианте SIBO

Любое из двух устройств может инициировать рассоединение

От устройства 1От устройства 2Описание
Disc_Pdu Инициализация рассоединения

Отметим, что здесь нет подтверждения рассоединения, тем не менее оно считается успешным.

Рассоединение в варианте EPOC

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

От устройства 1От устройства 2Описание
Disc_Req_Pdu Инициализация рассоединения
 Disc_PduРассоединение подтверждено

Даже если реализована поддержка этой усовершенствованной процедуры рассоединения, оригинальная процедура рассоединения (вариант SIBO) также должна поддерживаться. В частности, если пакет Disc_Pdu не получен в течение таймаута перепосылки (re-transmission timeout) нужно послать пакет Disc_Pdu и считать рассоединение состоявшимся.

Конечный автомат

Этат раздел описывает пример конечного автомата, который реализует оба варианта протокола уровня передачи данных (data link layer). В автомате делается попытка установить соединение точка-точка, но и соединение клиент-сервер также поддерживаются.

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

Состояния

Используются пять состояний (здесь и далее термины "событие" и "состояние" используются как синонимы, прим. пер.):

СостояниеОписание
Idle_StateРассоединен
Idle_Req_Stateпослан Req_Req_Pdu, ждем подтверждения соединения Req_Con_Pdu
Idle_Ack_Stateпослан Req_Con_Pdu, ждем отзыва Ack_Pdu
Data_StateСостояние приема/передачи данных. Не требуется вспециальных указаний на это состояние
Data_Ack_Stateпослан пакет данных Data_Pdu, ждем подстверждения приема

События

Следующие события обрабатываются конечным автоматом:

СобытиеИсточник (информации о событии - прим. пер.)Описание
Ack_RxПолученный пакетполучен Ack_Pdu (подтверждение приема)
Disc_Rx получен Disc_Pdu или Disc_Req_Pdu (рассоединение)
Req_Rx получен Req_Pdu (запрос соединения)
Req_Req_Rx получен Req_Req_Pdu (ответ за запрос соединения)
Req_Con_Rx получен Req_Con_Pdu (подтверждение соединения)
Data_Rx получен пакет данных Data_Pdu
ConnectПрограмма-клиентЗапрос соединения
Disconnect Запрос рассоединения
Write Передача данных
TimeoutТаймерИстекло время ожидания подстверждения приема (таймаут перепосылки, re-transmission timer) или истекло время неактивности (inactivity timer)

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

Кроме того, процедура рассоединения описана только п оварианту SIBO, соответственно пакеты Disc_Pdu и Disc_Req_Pdu интерпретируются одинаково.

Переменные

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

ПеременнаяОписаниеЗначение по умолчанию
EnabledСоединение установлено?FALSE
VariantТип протокола: SIBO или EPOCSIBO
RetriesКоличество перепосылок0
Seq_TxНомер последнего отправленного пакета (sequence number) для переданных пактов данных0
Seq_RxНомер последнего принятого пакета данных0
Magic"Магическое" число для данного устройстваПсевдослучайная величина

Таблицы переходов (state tables)

Описанные ниже таблицы детально описывают действия, выполняемые для каждого события, отдельная таблица для каждого состояния.

Функция Inc(x) возвращает следующее за x число по заранее определенному модулю.

Функция Reset() сбрасывает все переменные, за исключением переменной Enabled, в значения по умолчанию, а также получает новое псевдо-случайное число для Magic и запускает таймер перепосылки (re-transmission timer).

Idle_State

СобытиеУсловиеДействиеСледующее состояние
Ack_RxВсегдаНет действияIdle_State
Disc_RxВсегдаНет действияIdle_State
Req_RxEnabledВариант SIBO - послать Req_Con с числом Magic в качестве данных. Запустить таймер перепосылки.
Retries = 4
Idle_Ack_State
иначенет действияIdle_State
Req_Req_RxEnabledВариаен EPOC - послать Req_Con с числом Magic в качестве данных. Запустить таймер перепосылки.
Retries = 4
Idle_Ack_State
иначенет действияIdle_State
Req_Con_RxВсегданет действияIdle_State
Data_RxВсегданет действияIdle_State
ConnectВсегдаEnabled = TRUEIdle_State
DisconnectВсегдаEnabled = FALSEIdle_State
WriteВсегдаОшибка - нет соединенияIdle_State
TimeoutEnabledSend Req_Req_PduStart re-transmission timerIdle_Req_State
иначенет действияIdle_State

Idle_Req_State

СобытиеУсловиеДействиеСледующее состояние
Ack_RxEnabledSeq_Tx = sequence numberSeq_Rx = 0
запустить таймер неактивности (inactivity timer)
Соединение установлено
Data_State
иначенет действияIdle_Req_State
Disc_RxВсегдаReset()Idle_State
Req_RxEnabledВариант SIBO:
SeqTx = 0
Seq_Rx = 0
Послать Ack_Pdu с Seq_Rx
Запустить таймер неактивности
Соединение установлено
Data_State
иначенет действияIdle_Req_State
Req_Req_RxEnabledВариант EPOC:
Послать Req_Con с числом Magic в качестве данных
Запустить таймер перепосылки
Retries = 4
Idle_Ack_State
иначенет действияIdle_Req_State
Req_Con_RxВсегданет действияIdle_Req_State
Data_RxВсегданет действияIdle_Req_State
ConnectВсегдаОшибка - соединение уже установленоIdle_Req_State
DisconnectВсегдаEnabled = FALSE
Послать Disc_PduReset()
Idle_State
WriteВсегдаОшибка - нет соединенияIdle_Req_State
TimeoutEnabledПопытаться на другой скорости, если реализовано авто-определение скорости.
Послать Req_Req_Pdu
Запустить таймер перепосылки
Idle_Req_State
иначеReset()Idle_State

Idle_Ack_State

СобытиеУсловиеДействиеСледующее состояние
Ack_RxEnabledSeq_Tx = номер пакета
Seq_Rx = 0
Запустить таймер неактивности
Соединение установлено
Data_State
иначенет действияIdle_Ack_State
Disc_RxВсегдаReset()Idle_State
Req_RxEnabledВариант SIBO:
SeqTx = 0
Seq_Rx = 0
Послать Ack_Pdu с номером пакета Seq_Rx
Запустить таймер неактивности
Соединение установлено
Data_State
иначенет действияIdle_Ack_State
Req_Req_RxEnabledВариант EPOC:
Послать Req_Con с числом Magic в качестве данных
Запустить таймер перепосылки
Retries = 4
Idle_Ack_State
иначенет действияIdle_Ack_State
Req_Con_RxEnabled and (полученное "магическое" число не равно сгенерированному нами, magic number != Magic)Вариант EPOC:
Seq_Tx = 0
Seq_Rx = 0
Послать Ack_Pdu с номером пакета Seq_Rx
Запустить таймер неактивности
Соединение установлено
Data_State
иначенет действияIdle_Ack_State
Data_RxВсегданет действияIdle_Ack_State
ConnectВсегдаОшибка - соединение уже установленоIdle_Ack_State
DisconnectВсегдаEnabled = FALSE
Послать Disc_PduReset()
Idle_State
WriteВсегдаОшибка - нет соединенияIdle_Ack_State
TimeoutEnabled и (исчерпан счетчик повторов, 0 < Retries)Retries = Retries - 1Послать Req_Con с числом Magic в качестве данныхIdle_Ack_State
иначеReset()Idle_State

Data_State

СобытиеУсловиеДействиеСледующее состояние
Ack_RxВсегдаНет действияData_State
Disc_RxВсегдаReset()
Соединение разорвано
Idle_State
Req_RxВсегдаReset()
Соединение разорвано
Idle_State
Req_Req_RxВсегдаReset()
Соединение разорвано
Idle_State
Req_Con_RxВсегдаReset()
Соединение разорвано
Idle_State
Data_Rxувеличиваем номер пакета
sequence number == Inc(Seq_Rx)
Seq_Rx = Inc(Seq_Rx)Посылаем Ack_Pdu с номером пакета Seq_RxЗапустить таймер неактивностиData_State
иначеПослать Ack_Pdu с номером пакета Seq_RxData_State
ConnectВсегдаОшибка - соединение уже установленоData_State
DisconnectВсегдаEnabled = FALSE
Послать Disc_PduReset()
Соединение разорвано
Idle_State
WriteВсегдаSeq_Tx = Inc(Seq_Tx)
Послать Data_Pdu с номером пакета Seq_Tx
Запустить таймер перепосылки
Retries = 8
Data_Ack_State
TimeoutВсегдаПослать Disc_PduReset()
Соединение разорвано
Idle_State

Data_Ack_State

СобытиеУсловиеДействиеСледующее состояние
Ack_Rxзапоминаем номер пакета sequence number == Seq_TxЗапустить таймер неактивностиData_State
иначенет действияData_Ack_State
Disc_RxВсегдаReset()
Соединение разорвано
Idle_State
Req_RxВсегдаReset()
Соединение разорвано
Idle_State
Req_Req_RxВсегдаReset()
Соединение разорвано
Idle_State
Req_Con_RxВсегдаReset()
Соединение разорвано
Idle_State
Data_Rxувеличиваем номер пакета Inc(Seq_Rx)Seq_Rx = Inc(Seq_Rx)
Послать Ack_Pdu с номером пакета Seq_Rx
Запустить таймер перепосылки
Data_Ack_State
иначеПослать Ack_Pdu с номером пакета Seq_RxData_Ack_State
ConnectВсегдаОшибка - соединение уже установленоData_Ack_State
DisconnectВсегдаEnabled = FALSE
Послать Disc_PduReset()
Соединение разорвано
Idle_State
WriteВсегдаОшибка - соединение занятоData_Ack_State
Timeoutисчерпан счетчик перепосылок 0 < RetriesRetries = Retries - 1
Послать Data_Pdu с номером пакета Seq_Tx
Запустить таймер перепосылки
Data_Ack_State
иначеПослать Disc_PduReset()
Соединение разорвано
Idle_State

Андрей А. Породько


Интересные ссылки:
Комментариев к странице: 0 | Добавить комментарий
Домой | Проект ядро Core/2 | Проект OS/4 Download | Новости | Гостевая книга | Подробно обо всем | Нужные программы | Проекты | OS/2 FAQ | Всячина | За и Против | Металлолом | #OS2Russian | RDM/2 | Весёлые картинки | Наша галерея | Доска объявлений | Карта сайта | ПОИСК | ФОРУМ