Вы здесь

Протокол LC-1. Update 30.11.2011

Протокол обмена с ШДК innovate LC-1 оказался на удивление простым. Несмотря на это, для полного понимания структуры сообщений при реализации эмулятора ШДК, пришлось потратить достаточно времени.  Связано это с убогостью описания протокола от самого innovatemotorsports, датащиты очень краткие, примеры использования отсутствуют.

Тут следует сказать, что у innovate есть свой SDK для подключения своих ШДК, но как показала практика, использование этого SDK не совсем хорошая идея, это хорошо видно по софту OnlineTuner от SMS, где частенько пропадает связь с ШДК и для ее восстановления приходится выполнять танец с бубном. Форум SMS просто пестрит сообщениями о постоянных потерях связи софта с ШДК, а разработчик говорит, что всему виной SDK от innovate, а мы все в шоколаде. Данное суждение не голословное, так как я сам являюсь обладателем комплекта инженерного ЭБУ от SMS и периодически наблюдаю данную проблему. В общем я за прямое подключение к ШДК. Это конечно немного сложнее, так как надо парсить протокол и реализовывать дополнительную логику опроса ШДК, но в последствии это с лихвой окупится стабильной связью и приемлемым быстродействием.

И так, протокол обмена основан на передаче пакетов, организованных в слова длиной 16 бит. Сначала передается заголовок пакета, из которого мы получаем служебную информацию. Далее следуют непосредственно сами данные. Выдача данных ШДК происходит постоянно на скорости 19200 бод каждые 81,92 мс. То есть, начиная прослушивать СОМ порт мы можем попасть в середину пакета. Поэтому, задача номер один обнаружить в потоке данных заголовок пакета. Описание протокола можно посмотреть в датащитах innovate, доступных у них на сайте. И так, для обнаружения заголовка пакета будет читать поток данных из СОМ порта побайтно! Так  проще всего проверить маркер заголовка.

Признаком обнаружения маркера начала заголовка является выполнение следующего условия:

(data & 0xA2) == 0xA2
(data & 0xB2) == 0xB2

Далее необходимо проверить следующий байт на выполнения условия:
(data & 0x80) == 0x80
(data & 0x82) == 0x82

Если оба условия выполняются, то мы прочитали заголовок и далее будут данные ШДК. Пример поиска маркера заголовка и чтения данных ШДК представлен ниже, это конечно упрощенный код, который не учитывает, что в цепочке могут присутствовать другие устройства от innovate и читает только протокол LC-1:

                    var lambdaBuffer = new byte[4];
                    var data = (byte) serialPort.ReadByte();
                    if ((data & 0xA2) == 0xA2)
                    {
                        data = (byte) serialPort.ReadByte();
                        if ((data & 0x80) == 0x80)
                        {
                            var count = serialPort.Read(lambdaBuffer, 0, lambdaBuffer.Length);
                            if (count == lambdaBuffer.Length)
                            {
                                GetAFR(lambdaBuffer);
                            }
                        }
                    }

                    if ((data & 0xB2) == 0xB2)
                    {
                        data = (byte) serialPort.ReadByte();
                        if ((data & 0x82) == 0x82)
                        {
                            var count = serialPort.Read(lambdaBuffer, 0, lambdaBuffer.Length);
                            if (count == lambdaBuffer.Length)
                            {
                                ParseLambdaBuffer(lambdaBuffer);
                                Connected = true;
                                continue;
                            }
                        }
                    }

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

        private void ParseLambdaBuffer(byte[] lambdaBuffer)
        {
            State = (LambdaState) (lambdaBuffer[0] >> 2 & 0x7);
            ErrorCode = 0;            
            
            switch (State)
            {
                case LambdaState.LambdaValue:
                    AF = (((lambdaBuffer[0] & 1) << 7) + (lambdaBuffer[1] & 0x7F))/10f;
                    Lambda = (((lambdaBuffer[2] & 0x7F) << 7) + (lambdaBuffer[3] & 0x7F) + 500f)/1000f;
                    AFR = Lambda*AF;
                    Available = true;
                    break;

                case LambdaState.O2Level:
                    O2Level = (((lambdaBuffer[2] & 0x7F) << 7) + (lambdaBuffer[3] & 0x7F)) / 10;

                    Available = false;
                    break;

                case LambdaState.ErrorCode:
                    ErrorCode = (((lambdaBuffer[2] & 0x7F) << 7) + (lambdaBuffer[3] & 0x7F));
                    Available = false;
                    break;
            }
        }

В функции, в соответствии с форматом, происходит выделение коэффициента AFR multiplier, непосредственно значения лямбда зонда и выполняется расчет значения AFR.

В случае использования LC-1 все выше перечисленное имеет место быть и код по вычислению значения AFR работоспособен. Остается только реализовать реакцию на возникновении различного рода ошибок, возвращаемых контроллером ШДК.