В данной статье речь будет о локальной низкоскоростной сети взаимодействия блоков управления автомобиля BMW — I/K-bus. А точнее о том, как с ней могут взаимодействовать приложения из под Linux. На картинках проиллюстрирую созданный мною вариант.
Итак, передо мной встала задача расширить функциональность моего автомобиля в области информационно-развлекательной системы. Просто мне этого очень захотелось. Автомобиль хороший, но пожилой. Его создавали во времена, когда даже mp3 не был в обширном употреблении. Поэтому многих современных удобств он лишён. К тому же есть в голове дополнительные идеи, воплотив которые, я смогу подчеркнуть свою индивидуальность.
Информационно-развлекательная система выполняется на устройствах, в основе которых контроллеры с заложенными программами. Я буду здесь называть эти устройства блоками управления. Каждый такой блок управления несёт свою функциональную нагрузку, будь то поддержание температуры салона, регулировка положения сидений, воспроизведение музыки и видео, навигация и прочее. Весь этот набор блоков управления должен взаимодействовать друг с другом, управляться с места водителя и пассажиров, передавать диагностические данные. Для этой цели и была разработана сеть I-bus. В последствии появилась технически идентичная сеть K-bus и их объединение I/K-bus.
Архитектура сети I-bus выполнена по схеме «общая шина», т. е. импульсы данных от узлов (блоков управления) передаются по обычному медному проводу соединённых в одной точке. Поэтому узлы должны делить общую среду передачи и передавать данные по очереди. Как определяется эта очередь или приоритетность я не знаю, полагаю просто прослушивается шина на наличие занятости и с учётом защитного интервала и незанятости шины принимается решение о передачи. В «молчаливом» состоянии уровень потенциала на шине относительно корпуса составляет от 7 В до напряжения питания автомобиля. При подаче доминантного бита в шину потенциал снижается до 2 В и ниже. Битовая скорость взаимодействия узлов постоянная и составляет 9600 бит/с. Цифра знакомая из UART. Но не только в скорости передачи имеются сходства, также формат символов в I-bus соответствует одной из вариаций доступных в UART. Символ состоит из 11 бит: стартовый бит, 8 бит данных, бит чётности, стоповый бит. Эти особенности позволяют физически подключаться к шине через интерфейсы UART или RS-232. Только необходимо позаботиться о преобразовании уровней сигнала с помощью простенькой схемы или готового преобразователя. Для этой цели вполне сойдёт k-line адаптер известный в диагностических интерфейсах. На физическом уровне они полностью совместимы. Я кстати им и пользуюсь.
Про физический уровень сети I-bus я в общем рассказал, теперь опишу кратко канальный уровень, это если следовать последовательности многоуровневой модели OSI. Так будет логичнее. Как я упомянул ранее, для передачи используется общая среда, которую надо делить по времени и передавать данные различным адресатам. Тут можно провести аналогию с Ethernet — данные передаются кадрами в которых содержится адрес отправителя, адрес получателя, полезная нагрузка (данные) и контрольная сумма. Кадр не имеет фиксированного размера и лежит в пределах 5 — 37 символов. Формат кадра я нарисовал ниже:
![image](https://habrastorage.org/r/w1560/files/2e3/697/992/2e3697992c42455398acb5426b24fca8.png)
Здесь TX ID — адрес отправителя, 1 символ;
LEN — размер кадра с вычетом двух первых символов, 1 символ;
RX ID — адрес получателя, 1 символ;
DATA — полезная нагрузка, 1 — 33 символа;
CK SUM — контрольная сумма, 1 символ.
Корректность принятого кадра определяется символом контрольной суммы. Отправитель не проверяет корректность принятого кадра получателем. Возможно это делается на уровне приёма собственного кадра. Если не было коллизий и других сбоев на шине, то отправитель корректно примет собственный кадр и не предпримет попыток повторной отправки. По информации найденной мною во всемирной паутине сказано, что отправитель ждет 100 мс положительной квитанции от получателя. Увы, на практике я этого не встречал. Возможно это применяется для особенно важных сообщений и в протоколах более высокого уровня.
То что входит в полезную нагрузку кадра, относится к протоколу следующего уровня. Работу с этим протоколом лучше возложить на прикладной уровень и работать с ним в приложениях. Повторюсь ещё раз, я ищу применение взаимодействия сети I/K-bus в операционной системе на ядре Linux. Функции блоков управления будут выполнять приложения в пользовательском пространстве. Внутри операционной системы организовать взаимодействия между приложениями не сложно, есть механизмы межроцессного взаимодействия (IPC). Но главная задача связать их с процессами блоков управления автомобиля. За примером обратимся к более известному варианту сети взаимодействия контроллеров — CAN. В Linux эта технология развивается в двух проектах: SocketCAN и can4linux. Первый проект основывается на драйвере сетевого устройства и протоколов, выполняющих предварительную обработку кадров и связывающих сетевое устройство с интерфейсом сокетов. Второй вариант основан на символьном устройстве, подробности реализации этого проекта не знаю, так как не работал с ним. Но полагаю аналог can4linux для I/K-bus является драйвер tty. Достаточно настроить скорость, формат символов последовательного порта и путем чтения/записси ttyS файла будет выполняться прием/отправка данных в шину. Конечно если она подключена к последовательному порту адаптером.
Мне показался более привлекательным вариант SocketCAN, и я пошёл этим же путём. Объясню почему. Драйвер выполнен из двух независимых частей: сетевого устройства и сетевого протокола. В сетевом устройстве решаются вопросы взаимодействия с аппаратной частью и множественного доступа, а в модуле сетевого протокола — фильтрация сообщений и взаимодействия с процессами пользователя. Приложения подключаются к сети I/K-bus посредством сокетов и задачи множественного доступа и фильтрации снимаются. В принципе можно возложить фильтрацию и множественный доступ на какой-нибудь сервер, подключенный к tty устройству и не лезть в ядро. В общем то да, но все равно не обойтись без межпроцессорного взаимодействия, а это как вариант тот же сокет. К тому же в сетевом стеке Linux решены многие задачи с очередями сообщений, которые придётся реализовывать в сервере. И ко всему этому использование сетевого устройства гармонично вписывается в философию администрирования операционной системы. Например командой ifconfig можно посмотреть состояние интерфейса, остановить его или запустить.
Драйвер сетевого устройства для I/K-bus я выполнил на основе slcan, который выполнен на основе SLIP. Я не застал те времена, когда IP пакеты передавались между компьютерами по последовательному порту. Их и сейчас можно передавать таким способом, но это не актуально. А вот передавать I/K- bus кадры таким способом хороший вариант. Драйвер tty сложен и доступ к низкоуровневой его части можно получить через дисциплину линии. Так делается в SLIP и slcan, так поступил и я, написав драйвер slibus. Когда через tty устройство активизируется созданная дисциплина линии, в системе появится сетевое устройство ibusN, где N — 0,1,2… Что бы было понятнее приведу схему. В ней зелёным отмечены квадраты, функции которых выполняет модуль ядра slibus.
![image](https://habrastorage.org/r/w1560/files/984/4ac/732/9844ac732127443a8ee082c13e7859fe.png)
Оранжевым цветом отмечен функционал модуля сетевого протокола. Опять же не стал изобретать велосипед и по аналогии модулей can и can_raw создал модуль af_ibus_raw. При загрузке этот модуль регистрирует новое семейство протоколов PF_IBUS и в нем же реализован RAW-сокет для полного доступа к кадру. Посредством вызова setsockopt можно включить фильтр принимаемых сообщений по идентификаторам отправителя и получателя. По умолчанию сокет принимает все сообщения из шины.
Должен сказать, что есть одна неприятность, и заключается она в том, что для возможности загрузки этих модулей необходимо патчить ядро.
А теперь давайте посмотрим как это все работает. Загрузим модули ядра, инициализируем дисциплину линии под номером, соответствующем slibus, и поднимем сетевой интерфейс ibus0. Команда ifconfig в терминале покажет нам что то подобное:
![](https://habrastorage.org/r/w1560/files/82c/505/85e/82c50585ee894c54b0ef24918cef9d21.png)
Как видим сетевой интерфейс успешно запущен и имеет статистику по трафику. Прежде чем сделать скриншот, я специально погонял данные по интерфейсу. Пользуюсь сделанными драйверами несколько месяцев, сбоев не наблюдалось. Но есть недоработки, которые еще не устранил. К ним вернусь позже, а пока работаю над приложениями по мере свободного времени.
Сильные стороны данного подхода заключаются в ряде аспектов. Приложения запущенные в операционной системе имеют полноценный доступ к шине и через неё же взаимодействуют друг с другом. Допустим в комплектации моего автомобиля отсутствует CD-чейнджер. Мне достаточно написать приложение эмулирующее это устройство. При этом оно будет воспроизводить различные форматы файлов и онлайн радио. Затем я захочу доукомплектовать телефонным модулем, которого у меня нет или не нравиться штатный. Я просто напишу ещё программку, которая по блютуз подключится к смартфону и выполнит ввод-вывод голоса и информации в штатные места. Или создать что-нибудь свое, например игра световыми приборами e-light. Таким образом приложения разрабатываются независимо друг от друга, могут устанавливаться и удаляться по желанию владельца.
На рисунке ниже показана работа программ ibusdump и ibussend. Что делают эти команды, думаю понятно из названия. Последние две строчки ibusdump показывают, что по шине передавались сообщения, которые я отправил через ibussend.
![](https://habrastorage.org/r/w1560/files/0e6/273/72c/0e627372ce18415b8450718ee697aa89.png)
На этом остановлюсь, пожалуй. О том, что передаётся в полезной нагрузке кадра и для каких блоков управления я расскажу в другой раз.
Итак, передо мной встала задача расширить функциональность моего автомобиля в области информационно-развлекательной системы. Просто мне этого очень захотелось. Автомобиль хороший, но пожилой. Его создавали во времена, когда даже mp3 не был в обширном употреблении. Поэтому многих современных удобств он лишён. К тому же есть в голове дополнительные идеи, воплотив которые, я смогу подчеркнуть свою индивидуальность.
Информационно-развлекательная система выполняется на устройствах, в основе которых контроллеры с заложенными программами. Я буду здесь называть эти устройства блоками управления. Каждый такой блок управления несёт свою функциональную нагрузку, будь то поддержание температуры салона, регулировка положения сидений, воспроизведение музыки и видео, навигация и прочее. Весь этот набор блоков управления должен взаимодействовать друг с другом, управляться с места водителя и пассажиров, передавать диагностические данные. Для этой цели и была разработана сеть I-bus. В последствии появилась технически идентичная сеть K-bus и их объединение I/K-bus.
Архитектура сети I-bus выполнена по схеме «общая шина», т. е. импульсы данных от узлов (блоков управления) передаются по обычному медному проводу соединённых в одной точке. Поэтому узлы должны делить общую среду передачи и передавать данные по очереди. Как определяется эта очередь или приоритетность я не знаю, полагаю просто прослушивается шина на наличие занятости и с учётом защитного интервала и незанятости шины принимается решение о передачи. В «молчаливом» состоянии уровень потенциала на шине относительно корпуса составляет от 7 В до напряжения питания автомобиля. При подаче доминантного бита в шину потенциал снижается до 2 В и ниже. Битовая скорость взаимодействия узлов постоянная и составляет 9600 бит/с. Цифра знакомая из UART. Но не только в скорости передачи имеются сходства, также формат символов в I-bus соответствует одной из вариаций доступных в UART. Символ состоит из 11 бит: стартовый бит, 8 бит данных, бит чётности, стоповый бит. Эти особенности позволяют физически подключаться к шине через интерфейсы UART или RS-232. Только необходимо позаботиться о преобразовании уровней сигнала с помощью простенькой схемы или готового преобразователя. Для этой цели вполне сойдёт k-line адаптер известный в диагностических интерфейсах. На физическом уровне они полностью совместимы. Я кстати им и пользуюсь.
Про физический уровень сети I-bus я в общем рассказал, теперь опишу кратко канальный уровень, это если следовать последовательности многоуровневой модели OSI. Так будет логичнее. Как я упомянул ранее, для передачи используется общая среда, которую надо делить по времени и передавать данные различным адресатам. Тут можно провести аналогию с Ethernet — данные передаются кадрами в которых содержится адрес отправителя, адрес получателя, полезная нагрузка (данные) и контрольная сумма. Кадр не имеет фиксированного размера и лежит в пределах 5 — 37 символов. Формат кадра я нарисовал ниже:
![image](https://habrastorage.org/files/2e3/697/992/2e3697992c42455398acb5426b24fca8.png)
Здесь TX ID — адрес отправителя, 1 символ;
LEN — размер кадра с вычетом двух первых символов, 1 символ;
RX ID — адрес получателя, 1 символ;
DATA — полезная нагрузка, 1 — 33 символа;
CK SUM — контрольная сумма, 1 символ.
Корректность принятого кадра определяется символом контрольной суммы. Отправитель не проверяет корректность принятого кадра получателем. Возможно это делается на уровне приёма собственного кадра. Если не было коллизий и других сбоев на шине, то отправитель корректно примет собственный кадр и не предпримет попыток повторной отправки. По информации найденной мною во всемирной паутине сказано, что отправитель ждет 100 мс положительной квитанции от получателя. Увы, на практике я этого не встречал. Возможно это применяется для особенно важных сообщений и в протоколах более высокого уровня.
То что входит в полезную нагрузку кадра, относится к протоколу следующего уровня. Работу с этим протоколом лучше возложить на прикладной уровень и работать с ним в приложениях. Повторюсь ещё раз, я ищу применение взаимодействия сети I/K-bus в операционной системе на ядре Linux. Функции блоков управления будут выполнять приложения в пользовательском пространстве. Внутри операционной системы организовать взаимодействия между приложениями не сложно, есть механизмы межроцессного взаимодействия (IPC). Но главная задача связать их с процессами блоков управления автомобиля. За примером обратимся к более известному варианту сети взаимодействия контроллеров — CAN. В Linux эта технология развивается в двух проектах: SocketCAN и can4linux. Первый проект основывается на драйвере сетевого устройства и протоколов, выполняющих предварительную обработку кадров и связывающих сетевое устройство с интерфейсом сокетов. Второй вариант основан на символьном устройстве, подробности реализации этого проекта не знаю, так как не работал с ним. Но полагаю аналог can4linux для I/K-bus является драйвер tty. Достаточно настроить скорость, формат символов последовательного порта и путем чтения/записси ttyS файла будет выполняться прием/отправка данных в шину. Конечно если она подключена к последовательному порту адаптером.
Мне показался более привлекательным вариант SocketCAN, и я пошёл этим же путём. Объясню почему. Драйвер выполнен из двух независимых частей: сетевого устройства и сетевого протокола. В сетевом устройстве решаются вопросы взаимодействия с аппаратной частью и множественного доступа, а в модуле сетевого протокола — фильтрация сообщений и взаимодействия с процессами пользователя. Приложения подключаются к сети I/K-bus посредством сокетов и задачи множественного доступа и фильтрации снимаются. В принципе можно возложить фильтрацию и множественный доступ на какой-нибудь сервер, подключенный к tty устройству и не лезть в ядро. В общем то да, но все равно не обойтись без межпроцессорного взаимодействия, а это как вариант тот же сокет. К тому же в сетевом стеке Linux решены многие задачи с очередями сообщений, которые придётся реализовывать в сервере. И ко всему этому использование сетевого устройства гармонично вписывается в философию администрирования операционной системы. Например командой ifconfig можно посмотреть состояние интерфейса, остановить его или запустить.
Драйвер сетевого устройства для I/K-bus я выполнил на основе slcan, который выполнен на основе SLIP. Я не застал те времена, когда IP пакеты передавались между компьютерами по последовательному порту. Их и сейчас можно передавать таким способом, но это не актуально. А вот передавать I/K- bus кадры таким способом хороший вариант. Драйвер tty сложен и доступ к низкоуровневой его части можно получить через дисциплину линии. Так делается в SLIP и slcan, так поступил и я, написав драйвер slibus. Когда через tty устройство активизируется созданная дисциплина линии, в системе появится сетевое устройство ibusN, где N — 0,1,2… Что бы было понятнее приведу схему. В ней зелёным отмечены квадраты, функции которых выполняет модуль ядра slibus.
![image](https://habrastorage.org/files/984/4ac/732/9844ac732127443a8ee082c13e7859fe.png)
Оранжевым цветом отмечен функционал модуля сетевого протокола. Опять же не стал изобретать велосипед и по аналогии модулей can и can_raw создал модуль af_ibus_raw. При загрузке этот модуль регистрирует новое семейство протоколов PF_IBUS и в нем же реализован RAW-сокет для полного доступа к кадру. Посредством вызова setsockopt можно включить фильтр принимаемых сообщений по идентификаторам отправителя и получателя. По умолчанию сокет принимает все сообщения из шины.
Должен сказать, что есть одна неприятность, и заключается она в том, что для возможности загрузки этих модулей необходимо патчить ядро.
А теперь давайте посмотрим как это все работает. Загрузим модули ядра, инициализируем дисциплину линии под номером, соответствующем slibus, и поднимем сетевой интерфейс ibus0. Команда ifconfig в терминале покажет нам что то подобное:
![](https://habrastorage.org/files/82c/505/85e/82c50585ee894c54b0ef24918cef9d21.png)
Как видим сетевой интерфейс успешно запущен и имеет статистику по трафику. Прежде чем сделать скриншот, я специально погонял данные по интерфейсу. Пользуюсь сделанными драйверами несколько месяцев, сбоев не наблюдалось. Но есть недоработки, которые еще не устранил. К ним вернусь позже, а пока работаю над приложениями по мере свободного времени.
Сильные стороны данного подхода заключаются в ряде аспектов. Приложения запущенные в операционной системе имеют полноценный доступ к шине и через неё же взаимодействуют друг с другом. Допустим в комплектации моего автомобиля отсутствует CD-чейнджер. Мне достаточно написать приложение эмулирующее это устройство. При этом оно будет воспроизводить различные форматы файлов и онлайн радио. Затем я захочу доукомплектовать телефонным модулем, которого у меня нет или не нравиться штатный. Я просто напишу ещё программку, которая по блютуз подключится к смартфону и выполнит ввод-вывод голоса и информации в штатные места. Или создать что-нибудь свое, например игра световыми приборами e-light. Таким образом приложения разрабатываются независимо друг от друга, могут устанавливаться и удаляться по желанию владельца.
На рисунке ниже показана работа программ ibusdump и ibussend. Что делают эти команды, думаю понятно из названия. Последние две строчки ibusdump показывают, что по шине передавались сообщения, которые я отправил через ibussend.
![](https://habrastorage.org/files/0e6/273/72c/0e627372ce18415b8450718ee697aa89.png)
На этом остановлюсь, пожалуй. О том, что передаётся в полезной нагрузке кадра и для каких блоков управления я расскажу в другой раз.