RPC (Remote Procedure Call) — протокол сетевого взаимодействия, позволяющий программе вызывать процедуры на другом компьютере так, словно они локальные. Механизм RPC в TSMaster даёт внешней программе автоматизированное управление TSMaster: чтение и запись системных переменных и сигналов CAN/LIN/FlexRay, вызов системных функций. Руководство рассчитано на режимы «TSMaster1 управляет TSMaster2» и «внешний процесс управляет TSMaster через TSMaster.dll», языки — C++, Python, C# и др.

Ключевые слова: TSMaster, RPC, удалённый вызов процедур, TSMaster.dll, rpc_tsmaster_create_client, системные переменные.

Статья полезна, если вы разработали прикладной проект на базе TSMaster и хотите автоматически управлять им из внешней программы. (Кроме RPC, TSMaster предоставляет интерфейс на базе COM — о нём см. соответствующие материалы.)

1. Базовые понятия RPC

  • Клиент — программа, инициирующая RPC-запрос. Сервер — программа, принимающая RPC-запрос и выполняющая соответствующую процедуру.
  • Прокси клиента — упаковывает запрос и отправляет его на сервер. Прокси сервера — принимает запрос, распаковывает и вызывает локальную процедуру, затем возвращает результат прокси клиента.
  • Транспортный протокол — нижележащий протокол, например TCP или UDP. Сериализация данных — преобразование структур данных и объектов в передаваемый формат: JSON, XML, Protocol Buffers.

Поток работы RPC: клиент вызывает метод локального прокси → прокси клиента сериализует запрос (имя метода, параметры) → сообщение передаётся по сети → прокси сервера распаковывает запрос и вызывает реальный локальный метод → метод выполняется и формирует ответ → прокси сервера упаковывает ответ и отправляет клиенту → прокси клиента распаковывает ответ и возвращает результат клиенту.

2. Применение RPC в TSMaster

На механизме RPC пользователь строит в среде TSMaster полный проект: от разработки тестовых случаев до управления программируемыми устройствами, конфигурации шин и работы с платами. Клиент удалённо управляет сервером TSMaster: читает и пишет системные переменные, сигналы CAN, LIN, FlexRay и Ethernet (ETH), а также вызывает функции, определённые на сервере TSMaster, расширяя и настраивая систему.

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

RPC-механизм TSMaster поддерживает несколько топологий — не только «один клиент — один сервер», но и (рис. 2-1):

  1. Один ко многим (One-to-Many) — один клиент управляет несколькими серверами TSMaster: для одновременного управления несколькими тестовыми средами или устройствами.
  2. Многие к одному (Many-to-One) — несколько клиентов подключаются к одному серверу TSMaster: разные пользователи или тестовые системы разделяют ресурсы одного сервера.
  3. Многие ко многим (Many-to-Many) — несколько клиентов и серверов свободно взаимодействуют, образуя сложные распределённые тестовые системы для крупных проектов.
Топологии RPC в TSMaster
Рис. 2-1. Топологии RPC в TSMaster: один-ко-многим, многие-к-одному, многие-ко-многим

3. Использование RPC в TSMaster

По механизму RPC в TSMaster предусмотрены соответствующие интерфейсы: в проекте, которым нужно управлять программно, активируется RPC-сервер, предоставляющий ресурсы управляющим скриптам.

3.1. Активация сервера

Создайте C-скрипт и в событии запуска введите следующий код — он активирует RPC-сервер текущего проекта:

rpc_tsmaster_activate_server(true);

Фактически, начиная с версии TSMaster v2024.06.05.1124, функция RPC во всех проектах активирована по умолчанию.

3.2. Активация клиента

native_int h; // дескриптор клиента
// параметр 1 — имя приложения TSMaster, предоставляющего RPC-сервис
com.rpc_tsmaster_create_client("TSMaster", &h);
// активация клиента
com.rpc_tsmaster_activate_client(h, true);

3.3. Изменение данных на сервере

Запуск и остановка проекта сервера. Запуск проекта:

// мини-программа TSMaster:
com.rpc_tsmaster_cmd_start_simulation(h);
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_start_simulation(h);

Чтение и запись системных переменных. Установка системной переменной:

// мини-программа TSMaster:
com.rpc_tsmaster_cmd_write_system_var(h, "Var1", "1.2345");
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_write_system_var(h, "Var1", "1.2345");

Получение системной переменной:

// мини-программа TSMaster:
com.rpc_tsmaster_cmd_read_system_var(h, "Var1", "1.2345");
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_read_system_var(h, "Var1", "1.2345");

Чтение и запись сигналов CAN. Установка сигнала CAN:

// мини-программа TSMaster:
com.rpc_tsmaster_cmd_set_can_signal(h, "chnidx/net/node/msg/signal", 1234);
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_set_can_signal(h, "chnidx/net/node/msg/signal", 1234);

Получение сигнала CAN:

double d = 0;
// мини-программа TSMaster:
com.rpc_tsmaster_cmd_get_can_signal(h, "chnidx/net/node/msg/signal", &d);
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_get_can_signal(h, "chnidx/net/node/msg/signal", &d);

Чтение и запись сигналов LIN. Установка сигнала LIN:

// мини-программа TSMaster:
com.rpc_tsmaster_cmd_set_lin_signal(h, "chnidx/net/node/msg/signal", 1234);
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_set_lin_signal(h, "chnidx/net/node/msg/signal", 1234);

Получение сигнала LIN:

double d = 0;
// мини-программа TSMaster:
com.rpc_tsmaster_cmd_get_lin_signal(h, "chnidx/net/node/msg/signal", &d);
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_get_lin_signal(h, "chnidx/net/node/msg/signal", &d);

Чтение и запись сигналов FlexRay. Установка сигнала FlexRay:

// мини-программа TSMaster:
com.rpc_tsmaster_cmd_set_flexray_signal(h, "chnidx/net/node/msg/signal", 1234);
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_set_flexray_signal(h, "chnidx/net/node/msg/signal", 1234);

Получение сигнала FlexRay:

double d = 0;
// мини-программа TSMaster:
com.rpc_tsmaster_cmd_get_flexray_signal(h, "chnidx/net/node/msg/signal", &d);
// API (C/C++/C#/Python):
rpc_tsmaster_cmd_get_flexray_signal(h, "chnidx/net/node/msg/signal", &d);

Вызов системных функций TSMaster через RPC:

// шаг 1: подготовка входных параметров вызываемой функции
#define STR_BUFFER_SIZE 1024
char args[4][STR_BUFFER_SIZE];
char* pArgs[4] = {&args[0][0], &args[1][0], &args[2][0], &args[3][0]};
sprintf_s(pArgs[0], STR_BUFFER_SIZE, "%s", "var1");
sprintf_s(pArgs[1], STR_BUFFER_SIZE, "%d", svtString);
sprintf_s(pArgs[2], STR_BUFFER_SIZE, "%s", "string default value");
sprintf_s(pArgs[3], STR_BUFFER_SIZE, "%s", "this is a comment");

// шаг 2: вызов произвольного API
s32 ret;
ret = com.rpc_tsmaster_call_system_api(h, "app.create_system_var", 4, STR_BUFFER_SIZE,
&pArgs[0]);

// шаг 3: обработка возвращённых в параметрах значений (если есть)
s32 i;
log("API call result = %d", ret);
for (i = 0; i < 4; i++) {
    log("Argument %d: %s", i + 1, pArgs[i]);
}

Этот код эквивалентен созданию системной переменной вызовом app.create_system_var в процессе TSMaster: app.create_system_var(var1, svtString, "string default value", "this is a comment");. Учтите: таким способом нельзя вызывать системные функции, у которых параметры — указатели (кроме типов сообщений).

Вызов функций библиотек мини-программ через RPC:

// шаг 1: подготовка входных параметров вызываемой функции
#define STR_BUFFER_SIZE 1024
char args[4][STR_BUFFER_SIZE];
char* pArgs[4] = {&args[0][0], &args[1][0], &args[2][0], &args[3][0]};
sprintf_s(pArgs[0], STR_BUFFER_SIZE, "%s", "var1");
sprintf_s(pArgs[1], STR_BUFFER_SIZE, "%d", svtString);
sprintf_s(pArgs[2], STR_BUFFER_SIZE, "%s", "string default value");
sprintf_s(pArgs[3], STR_BUFFER_SIZE, "%s", "this is a comment");

// шаг 2: вызов произвольного API
s32 ret;
ret = com.rpc_tsmaster_call_library_api(h, "mylib.create_system_var", 4, STR_BUFFER_SIZE,
&pArgs[0]);

// шаг 3: обработка возвращённых в параметрах значений (если есть)
s32 i;
log("API call result = %d", ret);
for (i = 0; i < 4; i++) {
    log("Argument %d: %s", i + 1, pArgs[i]);
}

4. Справочник функций TSMaster RPC

4.1. rpc_tsmaster_create_client

ФункцияUInt32 rpc_tsmaster_create_client(const char* ATSMasterAppName, const psize_t AHandle)
НазначениеСоздать RPC-клиент TSMaster
Когда вызыватьПосле инициализации библиотеки tsmaster lib
Входные параметрыATSMasterAppName — имя приложения на стороне сервера TSMaster; AHandle — дескриптор RPC-клиента TSMaster
Возвращаемое значение==0: успех; другие значения: ошибка
Примерs32 h; rpc_tsmaster_create_client("TSMaster1", &h)

4.2. rpc_tsmaster_activate_client

ФункцияUInt32 rpc_tsmaster_activate_client(const size_t AHandle, const bool AActivate)
НазначениеАктивировать или деактивировать RPC-клиент TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; AActivate: true = активировать, false = деактивировать
Возвращаемое значение==0: успех; другие значения: ошибка
Примерrpc_tsmaster_activate_client(h, true)

4.3. rpc_tsmaster_is_simulation_running

ФункцияUInt32 rpc_tsmaster_is_simulation_running(const size_t AHandle, const pbool AIsRunning)
НазначениеПолучить состояние симуляции удалённого TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; AIsRunning — указатель на состояние симуляции: true = выполняется, false = не выполняется
Возвращаемое значение==0: успех; другие значения: ошибка
Примерbool b; if (0 == com.rpc_tsmaster_is_simulation_running(h, &b)) { if (b) { /* симуляция выполняется */ } }

4.4. rpc_tsmaster_cmd_set_mode_realtime

ФункцияUInt32 rpc_tsmaster_cmd_set_mode_realtime(const size_t AHandle)
НазначениеПеревести RPC-сервер TSMaster в режим реального времени
Когда вызыватьПосле создания RPC-клиента, до запуска симуляции
Входные параметрыAHandle — дескриптор RPC-клиента
Возвращаемое значение==0: успех; другие значения: ошибка
Примерrpc_tsmaster_cmd_set_mode_realtime(h)

4.5. rpc_tsmaster_cmd_set_mode_sim

ФункцияUInt32 rpc_tsmaster_cmd_set_mode_sim(const size_t AHandle)
НазначениеПеревести RPC-сервер TSMaster в режим симуляции
Когда вызыватьПосле создания RPC-клиента, до запуска симуляции
Входные параметрыAHandle — дескриптор RPC-клиента
Возвращаемое значение==0: успех; другие значения: ошибка
Примерrpc_tsmaster_cmd_set_mode_sim(h)

4.6. rpc_tsmaster_cmd_start_simulation

ФункцияUInt32 rpc_tsmaster_cmd_start_simulation(const size_t AHandle)
НазначениеЗапустить симуляцию на RPC-сервере TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента
Возвращаемое значение==0: успех; другие значения: ошибка
Примерrpc_tsmaster_cmd_start_simulation(h)

4.7. rpc_tsmaster_cmd_set_can_signal

ФункцияUInt32 rpc_tsmaster_cmd_set_can_signal(const size_t AHandle, const char* ASgnAddress, const double AValue)
НазначениеИзменить значение сигнала CAN из базы данных на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ASgnAddress — путь сигнала в базе данных; AValue — значение сигнала
Возвращаемое значение==0: успех; другие значения: ошибка
Примерif (0 == rpc_tsmaster_cmd_set_can_signal(h, "0/CAN_FD_Powertrain/Engine/EngineData/EngSpeed", 1234)) { /* сигнал записан */ }

4.8. rpc_tsmaster_cmd_get_can_signal

ФункцияUInt32 rpc_tsmaster_cmd_get_can_signal(const size_t AHandle, const char* ASgnAddress, const pdouble AValue)
НазначениеПолучить значение сигнала CAN из базы данных на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ASgnAddress — путь сигнала в базе данных; AValue — указатель на значение сигнала
Возвращаемое значение==0: успех; другие значения: ошибка
Примерdouble d; if (0 == rpc_tsmaster_cmd_get_can_signal(h, "0/CAN_FD_Powertrain/Engine/EngineData/EngSpeed", &d)) { /* сигнал получен */ }

4.9. rpc_tsmaster_cmd_set_lin_signal

ФункцияUInt32 rpc_tsmaster_cmd_set_lin_signal(const size_t AHandle, const char* ASgnAddress, const double AValue)
НазначениеИзменить значение сигнала LIN из базы данных на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ASgnAddress — путь сигнала в базе данных; AValue — значение сигнала
Возвращаемое значение==0: успех; другие значения: ошибка
Примерif (0 == rpc_tsmaster_cmd_set_lin_signal(h, "chnidx/net/node/msg/signal", 1234)) { /* сигнал записан */ }

4.10. rpc_tsmaster_cmd_get_lin_signal

ФункцияUInt32 rpc_tsmaster_cmd_get_lin_signal(const size_t AHandle, const char* ASgnAddress, const pdouble AValue)
НазначениеПолучить значение сигнала LIN из базы данных на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ASgnAddress — путь сигнала в базе данных; AValue — указатель на значение сигнала
Возвращаемое значение==0: успех; другие значения: ошибка
Примерdouble d; if (0 == rpc_tsmaster_cmd_get_lin_signal(h, "chnidx/net/node/msg/signal", &d)) { /* сигнал получен */ }

4.11. rpc_tsmaster_cmd_set_flexray_signal

ФункцияUInt32 rpc_tsmaster_cmd_set_flexray_signal(const size_t AHandle, const char* ASgnAddress, const double AValue)
НазначениеИзменить значение сигнала FlexRay из базы данных на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ASgnAddress — путь сигнала в базе данных; AValue — значение сигнала
Возвращаемое значение==0: успех; другие значения: ошибка
Примерif (0 == rpc_tsmaster_cmd_set_flexray_signal(h, "chnidx/net/node/msg/signal", 1234)) { /* сигнал записан */ }

4.12. rpc_tsmaster_cmd_get_flexray_signal

ФункцияUInt32 rpc_tsmaster_cmd_get_flexray_signal(const size_t AHandle, const char* ASgnAddress, const pdouble AValue)
НазначениеПолучить значение сигнала FlexRay из базы данных на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ASgnAddress — путь сигнала в базе данных; AValue — указатель на значение сигнала
Возвращаемое значение==0: успех; другие значения: ошибка
Примерdouble d; if (0 == rpc_tsmaster_cmd_get_flexray_signal(h, "chnidx/net/node/msg/signal", &d)) { /* сигнал получен */ }

4.13. rpc_tsmaster_cmd_write_system_var

ФункцияUInt32 rpc_tsmaster_cmd_write_system_var(const size_t AHandle, const char* ACompleteName, const char* AValue)
НазначениеЗаписать системную переменную по имени на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ACompleteName — имя системной переменной; AValue — значение данных
Возвращаемое значение==0: успех; другие значения: ошибка
Примерrpc_tsmaster_cmd_write_system_var(h, "v1", "1.2345")

4.14. rpc_tsmaster_cmd_read_system_var

ФункцияUInt32 rpc_tsmaster_cmd_read_system_var(const size_t AHandle, const char* ASysVarName, const pdouble AValue)
НазначениеПрочитать системную переменную по имени на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ASysVarName — имя системной переменной; AValue — указатель на значение данных
Возвращаемое значение==0: успех; другие значения: ошибка
Примерdouble d; if (0 == rpc_tsmaster_cmd_read_system_var(h, "v1", &d)) { log("value = %f", d); }

4.15. rpc_tsmaster_cmd_write_signal

ФункцияUInt32 rpc_tsmaster_cmd_write_signal(const size_t AHandle, const TLIBApplicationChannelType ABusType, const char* AAddr, const double AValue)
НазначениеЗаписать значение сигнала по имени на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ABusType — тип шины; AAddr — путь сигнала в базе данных; AValue — значение данных
Возвращаемое значение==0: успех; другие значения: ошибка
Примерif (0 == rpc_tsmaster_cmd_write_signal(h, APP_CAN, "0/Powertrain/Engine/EngSpeed", 1234)) { /* значение записано */ }

4.16. rpc_tsmaster_cmd_read_signal

ФункцияUInt32 rpc_tsmaster_cmd_read_signal(const size_t AHandle, const TLIBApplicationChannelType ABusType, const char* AAddr, const pdouble AValue)
НазначениеПрочитать сигнал по имени на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; ABusType — тип шины; AAddr — путь сигнала в базе данных; AValue — указатель на значение данных
Возвращаемое значение==0: успех; другие значения: ошибка
Примерdouble d; if (0 == rpc_tsmaster_cmd_read_signal(h, APP_CAN, "0/Powertrain/Engine/EngSpeed", &d)) { log("signal value = %f", d); }

4.17. rpc_tsmaster_delete_client

ФункцияUInt32 rpc_tsmaster_delete_client(const size_t AHandle)
НазначениеУдалить RPC-клиент
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента
Возвращаемое значение==0: успех; другие значения: ошибка
Примерrpc_tsmaster_delete_client(h)

4.18. rpc_tsmaster_cmd_stop_simulation

ФункцияUInt32 rpc_tsmaster_cmd_stop_simulation(const size_t AHandle)
НазначениеОстановить симуляцию на удалённом TSMaster
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента
Возвращаемое значение==0: успех; другие значения: ошибка
Примерrpc_tsmaster_cmd_stop_simulation(h)

4.19. rpc_tsmaster_call_system_api

ФункцияUInt32 rpc_tsmaster_call_system_api(const size_t AHandle, const char* AAPIName, const s32 AArgCount, const s32 AArgCapacity, const char** AArgs)
НазначениеВызов клиентом системной функции на сервере
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; AAPIName — имя системной функции, например "app.create_system_var"; AArgCount — количество параметров функции; AArgCapacity — длина строки параметра; AArgs — массив строк параметров
Возвращаемое значение==0: успех; другие значения: ошибка
Примерсм. код в разделе 3.3 «Вызов системных функций TSMaster через RPC»

4.20. rpc_tsmaster_call_library_api

ФункцияUInt32 rpc_tsmaster_call_library_api(const size_t AHandle, const char* AAPIName, const s32 AArgCount, const s32 AArgCapacity, const char** AArgs)
НазначениеВызов клиентом функции библиотеки мини-программ на сервере
Когда вызыватьПосле создания RPC-клиента TSMaster
Входные параметрыAHandle — дескриптор RPC-клиента; AAPIName — имя функции библиотеки мини-программ, например "mylib.create_system_var"; AArgCount — количество параметров функции; AArgCapacity — длина строки параметра; AArgs — массив строк параметров
Возвращаемое значение==0: успех; другие значения: ошибка
Примерсм. код в разделе 3.3 «Вызов функций библиотек мини-программ через RPC»