Библиотека StdPyApp

Библиотека StdPyApp (Standard Python Application) служит для поддержки клиент-серверных программ на языке Python со стороны crwdaq. Предполагается, что программа python работает как консольный драйвер (сервер), запускаемый из клиентской программы daqpascal, в которую включается библиотека StdPyApp. Взаимодействие клиента daqpascal и сервера python происходит через анонимный канал, подключенный к потокам stdin, stdout серверной программы. Ввод-вывод происходит асинхронно, без блокировки, поэтому на строне сервера python крутится цикл опроса, который принимает от клиента daqpascal команды и данные, а в ответ передает другие команды и данные. В качестве протокола обычно используется формат команд DaqScript, кратко описанный ниже.

Клиентская библиотека StdPyApp содержит включаемые файлы:

которые надо включить в прикладную программу, как описано далее.

См. также пример demo_pycon.


Поддержка Python в пакете crwdaq

Python является популярным языком программирования и имеет много преимуществ: наличие большого числа библиотек, сообщество, хорошая документация. Иметь его в своем арсенале полезно.

В пакете crwdaq есть средства поддержки python, рассчитанные на автономную (без подключения Internet) установку, т.к. в закрытых корпоративных сетях другой возможности просто нет.

Пакет daqgroup-pylibs

Пакет daqgroup-pylibs - это набор библиотек python для автономной установки в режиме offline, а также набор средств для их инсталляции и использования. Состав библиотек связан с текущими потребностями и может быть расширен по мере необходимости.

Для установки под Windows есть инсталлятор install-daqgroup-engines.exe, в который входит как сам python, так и библиотеки pylibs. Его надо просто запустить и установить пакеты.

Для установки под Linux есть инсталлятор install-daqgroup-pylibs.run, который устанавливает библиотеки pylibs. Сам python устанавливать не надо, он уже (обычно) есть в системе. Также для работы библиотек python потребуется установить crwkit, т.к. он будет нужен для запуска программ на python.

Установка библиотеки pylibs идет в каталог /opt/daqgroup/share/pylibs.

Модуль pycrwkit

В библиотеки pylibs входит модуль python под названием pycrwkit. Это библиотека на языке python для поддержки приложений DaqApplication, включая асинхронный ввод-вывод, поддержку команд формата DaqScript и т.д. Она написана А.К. специально для работы в составе пакета crwdaq. Краткое описание модуля см. readme.html. Для примера использования модуля pycrwkit см. демонстрационную программу demoapp.py.

Утилита unix pyvenv

Программы python из соображений безопасности устанавливаются и выполняются в так называемой виртуальной среде окружения (virtual environment), сокращенно venv. Это нужно для того, чтобы избежать конфликта версий и повреждения системы при установке библиотек python. То есть библиотеки устанавливаются не в системный каталог python, а в отдельную папку, а запускаются с помощью специальной утилиты, создающей при запуске свою среду окружения.

Для запуска программ python в виртуальной среде окружения, нужной для библиотек pylibs, создана утилита unix pyvenv, входящая в состав пакета crwkit. Запуск программ выполняется как

unix pyvenv /path/demoapp.py # запуск сценария demoapp.py из папки /path/

При ином способе запуска программы работать не будут, т.к. не найдут нужных библиотек.


Использование библиотеки StdPyApp

Библиотеку StdPyApp можно использовать в любой программе DaqPascal, выполенной по шаблону. Надо лишь правильно включить её в программу.


Включение библиотеки StdPyApp в программу

Библиотеку StdPyApp включают примерно так:

program xxxx;
const
 {------------------------------}{ Declare uses program constants:  }
 {$I _con_StdLibrary}            { Include all Standard constants,  }
 {------------------------------}{ And add User defined constants:  }
 {$I _con_StdPyApp}              { <-- Standard Python Application  }
...
var
 {------------------------------}{ Declare uses program variables:  }
 {$I _var_StdLibrary}            { Include all Standard variables,  }
 {------------------------------}{ And add User defined variables:  }
 {$I _var_StdPyApp}              { <-- Standard Python Application  }
...
 {------------------------------}{ Declare procedures & functions:  }
 {$I _fun_StdLibrary}            { Include all Standard functions,  }
 {------------------------------}{ And add User defined functions:  }
 {$I _fun_StdPyApp}              { <-- Standard Python Application  }
...
 {
 Clear user application strings...
 }
 procedure ClearApplication;
 begin
  ClearStdPyApp;
  ...
 end;
...
 {
 User application Finalization...
 }
 procedure FreeApplication;
 begin
  ...
  FreeStdPyApp;
 end;
...
 {
 User application Polling...
 }
 procedure PollApplication;
 begin
  ...
  PollStdPyApp;
 end;
...
 {
 Process data coming from standard input...
 }
 procedure StdIn_Processor(var Data:String);
 var cmd,arg:String; cmdid:Integer;
  procedure Cleanup;
  begin
   cmd:=''; arg:='';
  end;
 begin
  Cleanup;
  ViewImp('CON: '+Data);
  {
  User PyApp Hook
  }
  if StdPyApp_UserHookStdIn(Data) then begin
   Data:=''; // Data was hooked and handled
  end else
  {
  Handle "@cmd=arg" or "@cmd arg" commands:
  }
  if GotCommandId(Data,cmd,arg,cmdid) then begin
   ...
   ...
   {
   Default PyApp Hook to handle:
   @PyApp Start
   @PyAsk @PollCount
   @PyAns @PollCount 123
   @PyInf Started ...
   }
   if StdPyApp_DefaultHookStdIn(Data) then begin
    Data:=''; // Data was hooked and handled
   end else
   {
   Handle other commands by default handler...
   }
   StdIn_DefaultHandler(Data,cmd,arg);
  end;
  Data:='';
  Cleanup;
 end;

Здесь все функции, кроме StdPyApp_UserHookStdIn, являются библиотечными и просто используются в готовом виде. Функция StdPyApp_UserHookStdIn пишется (если надо) для перехвата (Hook) команд PyApp, с целью их особой (специфической для конкретного приложения) обработки перед выполнением стандартной обработки команд.


Принципы использования библиотеки StdPyApp

На библиотеку StdPyApp можно смотреть как на “черный ящик”, взаимодействие с которым происхлодит путем посылки в консоль сообщений и обработки поступающих ответных команд. Команд немного, и они несложные.


Команды и сообщения StdPyApp

Взаимодействия с исполнительной системой StdPyApp происходит с помощью слдующих команд:

############### команды взаимодействия с исполнительной системой StdPyApp
< @PyApp a    # команда управления состоянием PyApp с передачей аргумента a
> @PyAsk m    # команда пересылки сообщения m в консоль stdin сервера PyApp
> @PyAns m    # ответная строка сообщения m из консоли stdout сервера PyApp
> @PyInf m    # информационное сообщение от StdPyApp на изменение состояния
############### здесь < - посылка в консоль, > - обработка сообщений

Вот, собственно, и все команды StdPyApp. Дальше начинаются детали.

############################################# управление сервером
< @PyApp Start                              # запуск  сервера, т.е. программы python
< @PyApp Stop                               # останов сервера, т.е. программы python
< @PyApp Status                             # печатает статус (состояние) сервера
< @PyApp Set Launch unix pyvenv             # задает команду запуска сценария
< @PyApp Set Script ..\daqpas\demo_pycon.py # задает имя файла сценария
< @PyApp Set Params                         # задает параметры сценария
< @PyApp Set PingCall @PollCount            # задает команду Ping
< @PyApp Set AutoStart 1                    # разрешить АвтоЗапуск
< @PyApp Set PipeSizeKb 64                  # размер буфера канала, КБ
< @PyApp Set PreferToSend 0                 # 0:devPost, 1:devSend
< @PyApp Set TimeOutToSend 100              # таймаут для посылки данных, ms
< @PyApp Set TimeOutToStop 1000             # таймаут на остановку задач, ms
< @PyApp Set GuardTimerPeriod 1000          # период проверки АвтоЗапуска
< @PyApp Set PingTimerPeriod 1000           # таймер для посылки Ping
< @PyApp Set CalcPing 1                     # флаг: нужен расчет Ping
############################################# посылка сообщений
< @PyAsk @PollCount                         # посылка @PollCount в консоль сервера
> @PyAns @PollCount 123                     # ответ сервера с запрошенными данными
############################################# уведомления от сервера
> @PyInf Started PID 234                    # уведомление о старте сервера
> @PyInf Stopped PID 234 CODE 1             # уведомление об остановке сервера

С помощью этого нехитрого набора команд можно достаточно гибко управлять сервером PyApp. Обратите внимание, что команды самой программы python вложены в команды @PyAsk, PyAns. Это позволяет использовать неограниченное число команд сервера, имея всего 4 команды-обёртки @PyApp, @PyAsk, PyAns, @PyInf.

Обратите также внимание, что ответные команды от сервер (от программы python) можно перехватывать и обрабатывать по-своему. Для этого команды перехватываются в самом начале обработки команд функцией StdPyApp_UserHookStdIn. Для стандарной обработки используется перехват команд библиотечной функцией StdPyApp_DefaultHookStdIn непосредственно перед вызовом стандартного обработчика.

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

Функция перехвата StdPyApp_UserHookStdIn

Ниже приведен пример пользовательской функции перехвата, которая перехватывает только команды @PyAns, @PyInf и обрабатывает их, пропуская другие команды. Для уведомления о перехвате функция возвращает True, что означает, что команда была обработана и уже не требует дальнешей обработки.

{
StdPyApp - User specific Hook for StdIn commands.
Handle only @PyAns, @PyInf for Application specific stuff.
}
function StdPyApp_UserHookStdIn(var Data:String):Boolean;
var cmd,arg:String; cmdid:Integer; Hook:Boolean; ts,tm,si,co:Real;
begin
 cmd:=''; arg:='';
 Hook:=False; cmdid:=0;
 if GotCommandId(Data,cmd,arg,cmdid) then begin
  if (cmdid=cmd_Std_PyAns) then begin
   if IsSameText(ExtractWord(1,arg),'@Para') then begin
    Success(arg);
    Hook:=True;
   end;
   if IsSameText(ExtractWord(1,arg),'@Wave') then begin
    ts:=rVal(ExtractWord(2,arg));
    si:=rVal(ExtractWord(3,arg));
    co:=rVal(ExtractWord(4,arg));
    tm:=1e3*ts/timeunits;
    UpdateAo(0,tm,si);
    UpdateAo(1,tm,co);
    Hook:=True;
   end;
  end else
  if (cmdid=cmd_Std_PyInf) then begin
   // On (started,stopped) show tooltip
   // After start send parameters to server
   if WordIndex(ExtractWord(1,arg),'Started,Stopped')>0 then begin
    if IsSameText(ExtractWord(1,arg),'Started') then begin
     SendParaToPyApp(True);
    end;
    ShowTooltip('text "PyApp: '+arg+'" preset stdNotify delay 15000');
    Success('PyApp: '+arg);
    Hook:=True;
   end;
  end;
 end;
 StdPyApp_UserHookStdIn:=Hook;
 cmd:=''; arg:='';
end;

Соображения производительности

Использование команд @PyApp, @PyAsk, @PyAns, PyInf позволяет довольно просто работать с сервером, не влезая в детали реализации и API. Однако следует иметь в виду, что ценой этого упрощения является некоторое снижение производительности, т.к. данные передаются не сразу в консоль сервера, а проходят цикл обработки через консоль DAQ-устройства. Если производительности не хватает, надо использовать функции API. В случае проблем с производительностью можно, например, вместо посылки @PyAsk data непосредственно вызывать процедуру StdPyApp_Send(data).

Описание API библиотеки StdPyApp здесь не рассматривается, т.к. есть исходники - можно разобраться. Без особых причин (если нет серьезных проблем с производительностью) лучше ограничиться использованием команд @PyApp, @PyAsk, @PyAns, PyInf.


Формат команд DaqScript

В пакете crwdaq обычно используются команды в формате DaqScript. Этот формат используется и в библиотеке StdPyApp.

Определение формата DaqScript

Примеры команд формата DaqScript

@Exit                   # команда без параметров
@Exit 1                 # команда с одним параметром
@PyAns Set AutoStart 1  # команда с рядом параметров
@PyAsk @Exit 1          # команда вложенная в команду
@Data 43AFF0DC456       # команда с данными в HEX

Написание приложений DaqApplication

Здесь нет возможности изложить курс программирования на python, поэтому очень кратко.


Желаем приятного использования библиотеки StdPyApp.


CRW-DAQ Copyright (c) 2001-2025 Alexey Kuryakin daqgroup@mail.ru