1. О связи программного обеспечения автомобиля
Традиционное программное обеспечение транспортного средства использует классические протоколы шины (такие как CAN, LIN, FlexRay). Эти шины используют сигнально-ориентированную передачу данных (на основе сигналов) и обмениваются данными на основе передачи сигналов по витым парам. Однако пропускная способность передачи и передача данных. Скорость этих протоколов ограничена, и удовлетворить потребности в обновлении программного обеспечения транспортных средств (OTA) на основе беспроводных сетей непросто. Таким образом, новое поколение связи программного обеспечения автомобиля использует больше протоколов SOME/IP в рамках архитектуры SOA. Этот протокол использует сервис-ориентированную передачу данных (сервисно-ориентированные услуги), которые запрашиваются или подписываются в Ethernet автомобиля.
2. Введение в SOME/IP
SOME/IP — это протокол связи промежуточного программного обеспечения, основанный на Ethernet. SOME/IP — это аббревиатура от «Масштабируемое сервисно-ориентированное промежуточное программное обеспечение через IP».
В многоуровневой модели Ethernet SOME/IP расположен над транспортным уровнем TCP/UDP и принадлежит прикладному уровню.
3. Характеристики НЕКОТОРЫХ/ИП
1. Поддержка операций сериализации. ЭБУ, служащие узлами связи, могут иметь различную архитектуру программного обеспечения или операционные системы. Чтобы обеспечить согласованность механизма передачи, SOME/IP позволяет сериализовать сообщения UDP/TCP.
2. Поддержка удаленного вызова процедур (RPC). Клиент может удаленно запрашивать данные с сервера, а также может удаленно выполнять определенные функции на сервере.
3. Обнаружение службы (SD). В сервис-ориентированной архитектуре сервисы должны быть доступны для обнаружения, и у SOME/IP есть отдельный модуль SD, отвечающий за реализацию сервисов.
4. Поддержка публикации/подписки. Клиент может подписаться на контент сервера, тем самым динамически получая обновленные данные с сервера.
4. Формат сообщения SOME/IP
Формат заголовка данных сериализованного сообщения SOME/IP следующий:
Message ID: Используется для идентификации метода или события, участвующего в удаленном вызове.
Request ID: Используется для идентификации разных объектов «Клиент» или разных сеансов сеанса, инициированных одним и тем же объектом «Клиент».
Message Type: Используется для различения типов тела сообщения.
Распространенные типы тела сообщения: запрос/ответ/уведомление/ошибка.
Return Code: Обычно возвращается E_OK (0x00). Если возвращается тип тела ответа или сообщения об ошибке, это не так. 0x0
5. Основной режим связи SOME/IP.
1.Request/Response Methods
Клиент отправляет запросы на сервер, а ответы возвращаются с сервера клиенту. Ответ сервера об ошибке также возвращается клиенту.
2.Fire and Forget Methods
Клиент отправляет запрос серверу, а сервер не возвращает ответ.
3.Notification Events
Клиент подписывается на контент сервера и уведомляет подписанного клиента всякий раз, когда на сервере изменяются данные или выполняется определенная задача. Какие клиенты должны быть подписаны, определяется SOME/IP-SD.
4.Field
Поле представляет состояние, и клиенты, подписавшиеся на это поле, получают значение поля в качестве начального события. О каждом последующем обновлении значения поля будет сообщаться клиенту.
6. Процесс обнаружения службы SD
1.SD имеет два механизма:
Первый механизм — «предложение», который сервер может использовать для предоставления доступных услуг сети. Другой — «поиск услуг», который позволяет клиентам запрашивать доступные услуги.
2. Конкретный процесс обнаружения службы:
1. Сервер публикует сообщения посредством широковещательной рассылки.
2. Клиент находит сообщение посредством трансляции.
3. После того, как клиент находит сообщение, он подписывается и подтверждает (Subscribe – Ack)
3. Режим работы процесса SD:
Два режима клиента: запрос и прослушивание (Request and Listen)
Два режима на стороне сервера: Offer и Silent
7. Распространенные реализации с открытым исходным кодом — на основе vSomeIP.
Компания BMW внедрила платформу vsomeip с открытым исходным кодом, основанную на стандарте SOME/IP. vsomeip можно независимо интегрировать в различные операционные системы.
Пример кода — режим запроса/ответа:
Серверная часть:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
#define SAMPLE_METHOD_ID 0x0421
std::shared_ptr<vsomeip::application> app;
void on_message(const std::shared_ptr<vsomeip::message> &_request) {
std::shared_ptr<vsomeip::payload> its_payload = _request->get_payload();
vsomeip::length_t l = its_payload->get_length();
// Get payload
std::stringstream ss;
for (vsomeip::length_t i=0; i<l; i++) {
ss << std::setw(2) << std::setfill('0') << std::hex
<< (int)*(its_payload->get_data()+i) << " ";
}
std::cout << "SERVICE: Received message with Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
<< ss.str() << std::endl;
// Create response
std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()->create_response(_request);
its_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> its_payload_data;
for (int i=9; i>=0; i--) {
its_payload_data.push_back(i % 256);
}
its_payload->set_data(its_payload_data);
its_response->set_payload(its_payload);
app->send(its_response, true);
}
int main() {
app = vsomeip::runtime::get()->create_application("World");
app->init();
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, on_message);
app->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->start();
}
Клиент:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <condition_variable>
#include <thread>
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
#define SAMPLE_METHOD_ID 0x0421
std::shared_ptr< vsomeip::application > app;
std::mutex mutex;
std::condition_variable condition;
void run() {
std::unique_lock<std::mutex> its_lock(mutex);
condition.wait(its_lock);
std::shared_ptr< vsomeip::message > request;
request = vsomeip::runtime::get()->create_request();
request->set_service(SAMPLE_SERVICE_ID);
request->set_instance(SAMPLE_INSTANCE_ID);
request->set_method(SAMPLE_METHOD_ID);
std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload();
std::vector< vsomeip::byte_t > its_payload_data;
for (vsomeip::byte_t i=0; i<10; i++) {
its_payload_data.push_back(i % 256);
}
its_payload->set_data(its_payload_data);
request->set_payload(its_payload);
app->send(request, true);
}
void on_message(const std::shared_ptr<vsomeip::message> &_response) {
std::shared_ptr<vsomeip::payload> its_payload = _response->get_payload();
vsomeip::length_t l = its_payload->get_length();
// Get payload
std::stringstream ss;
for (vsomeip::length_t i=0; i<l; i++) {
ss << std::setw(2) << std::setfill('0') << std::hex
<< (int)*(its_payload->get_data()+i) << " ";
}
std::cout << "CLIENT: Received message with Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _response->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _response->get_session() << "] "
<< ss.str() << std::endl;
}
void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::cout << "CLIENT: Service ["
<< std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
<< "] is "
<< (_is_available ? "available." : "NOT available.")
<< std::endl;
condition.notify_one();
}
int main() {
app = vsomeip::runtime::get()->create_application("Hello");
app->init();
app->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, on_availability);
app->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, on_message);
std::thread sender(run);
app->start();
}
Конфигурация на стороне сервера:
{
"unicast" : "172.17.0.2",
"logging" :
{
"level" : "debug",
"console" : "true",
"file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
"dlt" : "false"
},
"applications" :
[
{
"name" : "World",
"id" : "0x1212"
}
],
"services" :
[
{
"service" : "0x1234",
"instance" : "0x5678",
"unreliable" : "30509"
}
],
"routing" : "World",
"service-discovery" :
{
"enable" : "true",
"multicast" : "224.224.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"repetitions_base_delay" : "200",
"repetitions_max" : "3",
"ttl" : "3",
"cyclic_offer_delay" : "2000",
"request_response_delay" : "1500"
}
}
Конфигурация клиента:
{
"unicast" : "172.17.0.1",
"logging" :
{
"level" : "debug",
"console" : "true",
"file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" },
"dlt" : "false"
},
"applications" :
[
{
"name" : "Hello",
"id" : "0x1313"
}
],
"routing" : "Hello",
"service-discovery" :
{
"enable" : "true",
"multicast" : "224.224.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"repetitions_base_delay" : "200",
"repetitions_max" : "3",
"ttl" : "3",
"cyclic_offer_delay" : "2000",
"request_response_delay" : "1500"
}
}
Справочное чтение:
1.https://inspiredhobbyist.org/what-is-some-ip-in-autosar/
2.https://mdnice.com/writing/6c21d60b8e74456b8d84004ced9baae2
3.https://github.com/COVESA/vsomeip/wiki/vsomeip-in-10-minutes
Продвигайтесь медленно, ожидая и надеясь.