[080]Введение в DoIP
[080]Введение в DoIP

1. Введение

DoIP — это аббревиатура диагностической связи по интернет-протоколу. На самом деле это передача данных на основе протокола UDS Ethernet. Это также протокол сам по себе, стандартизированный в стандарте ISO13400. Поскольку DoIP может передавать большой объем данных, имеет высокую скорость отклика и может выполнять удаленную диагностику, прошивку, OTA и другие задачи через Ethernet, DoIP постепенно стал заменой традиционного CAN.

2. Схема связи автомобиля

Главный компьютер диагностики может получить доступ к целевому чипу в соответствующем домене через шлюз и doip для выполнения таких задач, как диагностика, перепрошивка и OTA.

2.1

3. Формат протокола DoIP

2.2

3.1 DoIP-сообщение состоит из заголовка + полезной нагрузки.

Заголовок протокола[8 byte] состоит из следующих четырех полей Protocol version [1 byte] Inverse protocol version [1 byte] Payload type [2 byte] Payload length [4 byte]

3.2 Полезная нагрузка DoIP состоит из адреса источника/цели DoIP и сообщения UDS.

Адрес источника/цели DoIP представляет собой идентификатор обоих концов этой связи UDS, что несколько похоже на IP в Интернет-связи. Поскольку самый ранний протокол UDS работал на CAN, адрес источника/цели DoIP эквивалентен IP на CAN.

4. доип-симулятор

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

4.1 Скачать код

Язык кода:javascript
копировать
git clone https://gitlab.com/rohfle/doip-simulator.git

Изменить уровень журнала

Язык кода:javascript
копировать
diff --git a/doipclient.py b/doipclient.py
index 1c77d03..06247ef 100644
--- a/doipclient.py
+++ b/doipclient.py
@@ -36,7 +36,7 @@ STEERING_MULTIPLIER = float(os.environ.get("APP_STEERING_MULTIPLIER", 14)) # 14
 STEERING_DEADZONE_CAR = int(os.environ.get("APP_STEERING_DEADZONE_CAR", 0)) # 0
 STEERING_DEADZONE_XBOX = int(os.environ.get("APP_STEERING_DEADZONE_XBOX", 10000)) # 10000

-logging.basicConfig(level=logging.WARNING)
+logging.basicConfig(level=logging.INFO)

 def debug_parser(func):
     def print_args(*args, **kwargs):
diff --git a/doipserver.py b/doipserver.py
index a738a8d..31d3e91 100644
--- a/doipserver.py
+++ b/doipserver.py
@@ -23,7 +23,7 @@ from lib import utils
 from lib.simulator import fstep, framp, fsine, IdentifierDataSimulator

 import logging
-logging.basicConfig(level=logging.WARNING)
+logging.basicConfig(level=logging.INFO)


 def accelerator_format(n):

4.2 Результаты выполнения

Откройте два окна и выполните следующие команды соответственно,Конечно, лучше всего выполнить его на двух устройствах отдельно.,Потому что я столкнулся с этим на компьютере Mac,Address already in use!вопрос。 в моем WSL Ubuntu может работать на одном устройстве, потому что Ubuntu 20.04 поддерживает SO_REUSEADDR, но Mac не поддерживает SO_REUSEADDR.

Используйте параметр SO_REUSEADDR: вы можете установить параметр SO_REUSEADDR при создании объекта сокета, чтобы разрешить привязку порта нескольким процессам или потокам одновременно.

Это эквивалентно шлюзу на автомобиле, показанному на рисунке 2.1.

Язык кода:javascript
копировать
python3 doipserver.py

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

Язык кода:javascript
копировать
python3 doipclient.py

Результат на стороне сервера

Язык кода:javascript
копировать
kobe@41001005-26-0:~/study/doip/doip-simulator$ python3 doipserver.py
INFO:discovery:Starting UDP discovery thread
Serving on ('0.0.0.0', 13400) //Прослушиваем порт 13400, чтобы узнать, есть ли запрос VehicleIdentityRequest
INFO:discovery:Vehicle identity requested by IP 172.31.68.132. Responding with vehicle объявление.//Нашел запрос, ответьте с объявлением
INFO:server:Connection established with ('172.31.68.132', 43292)//Официально установлено соединение
INFO:simulator:Generating value for Dummy Accelerator (0x3200 on target 0x3300)
INFO:simulator:Dummy Accelerator value at time 1683682540.2956088 is bytearray(b'\xcc')

Результат на стороне клиента

Язык кода:javascript
копировать
kobe@41001005-26-0:~/study/doip/doip-simulator$ python3 doipclient.py
INFO:root:Looking for DOIP gateway... //Находим шлюз автомобиля
INFO:root:Received Vehicle Announcement from 172.31.68.132! //получатьсерверная Трансляция из части
INFO:root:Routing activated successfully. //Активация маршрута успешна
INFO:root:Data read loop time 2.91 milliseconds with length 3
INFO:root:Data read loop time 1.95 milliseconds with length 3

5. Анализ кода

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

5.1 Обнаружение службы и установление соединения

5.1.1 серверная часть

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

Язык кода:javascript
копировать
while  {
     Прослушивайте запросы от порта 13400 и возвращайте информацию об объявлении, если есть запрос.
     время тайм-аута истекло
     Анонс трансляции
}
Язык кода:javascript
копировать
def run(self, *args, **kwargs):
        logger.info('Starting UDP discovery thread')
        self.sock.bind(('', 13400))//Прослушиваем '0.0.0.0:13400', чтобы увидеть, есть ли какой-либо запрос клиента с ним на соединение.
        self.sock.settimeout(0.5)//Устанавливаем время ожидания прослушивания
        self.running = True
        self.announcement = self.generate_announcement(self.address, self.config).render()
        self.last_broadcast_time = time.time() - self.broadcast_interval
        while self.running:
            try:
                //Прослушиваем, есть ли с ним клиент соединяться
                data, addr = self.sock.recvfrom(1024)
                message, used = doip.parse(bytearray(data))
                logger.debug("Message received from %s:%i : %s", addr[0], addr[1], message)
                if type(message) is doip.VehicleIdentityRequest:
                    logger.info('Vehicle identity requested by IP {}. '
                                'Responding with vehicle announcement.'.format(addr[0]))
                    //Если запрос найден, отправляем объявление клиенту
                    self.sock.sendto(self.announcement, addr)
            except SocketTimeout:
                pass
            except Exception as err:
                logger.error('Error:', str(err))
                logger.exception('Trace:')
            //время тайм-аута истекает трансляции
            now_time = time.time()
            if now_time - self.last_broadcast_time > self.broadcast_interval:
                self.last_broadcast_time = now_time
                self.sock.sendto(self.announcement, ('255.255.255.255', 13400))

Самое важное содержание объявления — это IP, vin (идентификатор автомобиля) и Mac автомобиля.

Язык кода:javascript
копировать
def generate_announcement(self, address, config):
        vin = config['vin']
        mac = config['mac']
        return doip.VehicleAnnouncement(vin=vin, logical_address=address, eid=mac, gid=mac)//ключевой контент

config = {
    'vin': 'TESTVIN0000012345',
    'mac': int('123456789ABC', 16),
    ....
}
5.1.2 Клиентская часть

Транслируйте запрос на порт 13400, потому что в предыдущей версии 5.1 сервер прослушивал собственный порт 13400 и получал весь запрос, а затем возвращал IP сервера, чтобы клиент мог позвонить после получения IP

Язык кода:javascript
копировать
def discover_doip():
    """Find the IP of the DOIP gateway"""
    # errors and their response:
    # - TimeoutException - cooldown before resend vehicle identity request
    # - network unreachable - caught by parent function
    s = socket(AF_INET, SOCK_DGRAM)
    s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
    if NETWORK_INTERFACE is not None:
        s.setsockopt(SOL_SOCKET, 25, str(NETWORK_INTERFACE + '\0').encode('utf-8'))
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    s.settimeout(DOIP_TIMEOUT)
    s.bind(('', 13400))

    logging.info("Looking for DOIP gateway...")

    while True:
        request = doip.VehicleIdentityRequest()
        logging.debug('SEND: %s', request)
        s.sendto(request.render(), ('255.255.255.255', 13400)) // Широковещательный запрос VehicleIdentityRequest
        try:
            start = time.time()
            while True:
                data, addr =  s.recvfrom(1024)
                data = bytearray(data)
                response, used = doip.parse(data)
                logging.debug('RECV: %s', response)
                //Получаем информацию об объявлении транспортного средства и возвращаем IP
                if type(response) is doip.VehicleAnnouncement:
                    logging.info('Received Vehicle Announcement from %s!' % (addr[0]))
                    return addr[0]
                if time.time() - start > DOIP_TIMEOUT:
                    logging.warning('No vehicle announcement received. Requesting identity again immediately...')
                    break
        except timeout:
            logging.warning('No vehicle announcement received. Waiting 2 seconds before trying again...')
            time.sleep(2)

Как только вы получите IP-адрес сервера, вы сможете установить соединение и с радостью передавать данные doip.

Язык кода:javascript
копировать
while True:
    try:
        gateway_addr = discover_doip()//получатьсерверная частьизIP        setup_doip(gateway_addr)//Задаем адрес шлюза doip, то есть кому клиент должен отправлять данные.
    except OSError as err:
        logging.error("Error: %s", str(err))
        time.sleep(5)

def setup_doip(gateway_addr):
    while True:
        try:
            s = socket(AF_INET, SOCK_STREAM)
            s.settimeout(DOIP_TIMEOUT)
            s.connect((gateway_addr, 13400))
5.1.3 Ключевые моменты

Обнаружили ли вы, что основная идея серверной стороны заключается в том, что обе стороны договорились о порте 13400, обе прослушивают этот порт и отправляют запросы на обслуживание на этот порт для обеспечения широковещательной передачи услуг, чтобы клиент мог получить IP-адрес сервера? а затем установите соединение. Зачем использовать этот порт? Это связано с правилами ISO-13400.

Отправной точкой любого межпроцессного и междевайсного взаимодействия на самом деле является некое соглашение. Doip — это соглашение о порте 13400, объявлении и VehicleIdentityRequest. По аналогии с биндером в системе Android фактически договорились, что формат служебной String-Binder предоставляется через ServiceManager, а служебная строка запрашивается. Например, протокол и обнаружение служб someip также реализованы в соответствии с определенным соглашением. Подробно об этом я расскажу позже, когда представлю someip.

5.1.3

5.2 Отправка и получение данных UDS

5.2.1 Отправка смоделированных запросов UDS в карте данных в бесконечном цикле
Язык кода:javascript
копировать
def run_doip(s):
    while True:
        data_payload = {}
        start = time.time()
        for target_address, identifiers in config['datamap'].items():
            for identifier, meta in identifiers.items():
                label, key, parser = meta
                logging.debug('Getting identifier 0x{:04x} ({})'.format(identifier, label))
                uds_request = uds.ReadDataByIdentifier(identifier)
                data = uds_request.render() //Создаем пакет данных uds
                request = doip.DiagnosticMessage(target_address, DOIP_SOURCE_ADDRESS, data) //Переходим на 5.2.2
                logging.debug("SEND %s", str(request))
                s.send(request.render())
                value = receive_doip(s, identifier, parser)
                if value is not None:
                    data_payload[key] = value
        if len(data_payload) > 0:
            serial_thread.send(data_payload)
        else:
            logging.warning('Data read loop result is empty')
        time_taken = time.time() - start
        logging.info('Data read loop time %.2f milliseconds with length %i', time_taken * 1000, len(data_payload))

config = {
    'datamap': {
        # target_address (hex) : {
        #   identifier (hex) : tuple(label (str), key (str), parser (func))
        # }
        0x3300: {
            0x3200: ('Dummy Accelerator', 'accelerator', parse_accelerator),
            0x3230: ('Dummy Brake', 'brake', parse_brake_pressure),
        },
        0x3301: {
            0x3250: ('Dummy Steering', 'steering', parse_steering_angle),
        }
    }
}
5.2.2 Пакеты данных, упакованные в DoIP

Можно обратиться кФормат протокола DoIPглава,Упаковка пакета данных DoIP также относительно проста.

Язык кода:javascript
копировать
class DiagnosticMessage(DOIPMessage):

    def render(self):
        source_address = self.params['source_address']
        target_address = self.params['target_address']
        userdata = self.params['userdata']
        data = bytearray(utils.num_to_bytes(source_address, 2))
        data += bytearray(utils.num_to_bytes(target_address, 2))
        data += bytearray(userdata)
        if len(data) < 5:
            raise InvalidMessage('Rendered diagnostic message is less than 5 bytes long')
        else:
            return super().render(data)

class DOIPMessage(object):

    def render(self, data):
        if self.payload_type is None:
            raise Exception('DOIPMessage subclass has no payload_type value')
        header = bytearray([0x2, 0xfd])
        header += bytearray(utils.num_to_bytes(self.payload_type, 2))
        header += bytearray(utils.num_to_bytes(len(data), 4))
        return header + data
5.2.3 Серверная часть

Сервер получит DoIP-пакет, а затем распакует его по правилам, и код дальше интерпретироваться не будет.

6. Резюме

Это моя первая настоящая техническая статья после перехода с мобильных телефонов на автомобильную сферу. Я поделюсь некоторыми своими ощущениями.

От одного чипа и одной системы до многочиповой мультисистемы, каждый чип имеет соответствующее ядро, промежуточное программное обеспечение и приложения. Чтобы стандартизировать поведение всех чиповых систем в автомобиле, есть такие вещи, как Doip. UDS Существует множество спецификаций протоколов, которые необходимо читать при работе в автомобильной сфере, поэтому необходимо совершенствовать умение читать англоязычные документы.

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

Поскольку я только начал заниматься автомобилестроением, если в этой статье есть что-то не так, пожалуйста, поправьте меня.

Ссылки https://gitlab.com/rohfle/doip-simulator

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода