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):
- Один ко многим (One-to-Many) — один клиент управляет несколькими серверами TSMaster: для одновременного управления несколькими тестовыми средами или устройствами.
- Многие к одному (Many-to-One) — несколько клиентов подключаются к одному серверу TSMaster: разные пользователи или тестовые системы разделяют ресурсы одного сервера.
- Многие ко многим (Many-to-Many) — несколько клиентов и серверов свободно взаимодействуют, образуя сложные распределённые тестовые системы для крупных проектов.

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» |