Навигация:
<< >> Оглавление Указатель

Руководство программиста

Глава 1. Устройство RDS

§1.6. Взаимодействие блоков между собой

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

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

Если нескольким блокам требуется получить доступ к одной, общей для всех, переменной (например, к значению текущего времени при моделировании в динамике), они могут использовать динамическую переменную. Динамическая переменная создается одним из блоков, после чего остальные блоки могут найти ее по имени и типу и получить к ней доступ – подписаться на переменную. Динамическая переменная всегда принадлежит какому-нибудь блоку, при этом не обязательно тому, который ее создал. Например, если эта переменная нужна всем блокам какой-либо подсистемы, ее целесообразно создать в этой подсистеме, чтобы все заинтересованные блоки могли ее найти. Блок может создать динамическую переменную в себе самом, в родительской подсистеме или в корневой подсистеме. При подписке на переменную можно указать режим поиска – в этом случае блок попытается найти переменную в родительской подсистеме, и, если ее там не окажется, будет двигаться вверх по иерархии до тех пор, пока не найдет переменную с заданными именем и типом или пока не дойдет до корневой подсистемы. Блок также может подписаться на переменную, которой еще не существует. Факт подписки будет запомнен, и, как только переменная будет создана, блок получит к ней доступ. Сервисные функции для работы с динамическими переменными рассмотрены в §2.6.

Если блоку необходимо передать информацию одному или нескольким другим блокам и получить ответ, можно использовать механизм вызова функций блоков. Можно вызвать функцию конкретного блока (для этого нужно знать его идентификатор) или всех блоков какой-либо подсистемы (при этом можно включать вложенные подсистемы или ограничиться только одним уровнем иерархии). Каждая функция в схеме должна иметь уникальное имя-строку, поэтому целесообразно давать им длинные осмысленные имена с указанием имени библиотеки, блоки которой ее используют ( например, функция уведомления органов управления об изменении значения, которую используют блоки из стандартной библиотеки «Common.dll», называется «Common.ControlValueChanged»). Для того, чтобы вызвать функцию блока или ввести в блок реакцию на вызываемую функцию, ее сначала нужно зарегистрировать в RDS при помощи сервисной функции rdsRegisterFunction. Она присвоит функции блока уникальный целый идентификатор, который будет использоваться для вызова. Регистрировать функции блоков можно при загрузке DLL или при создании блока, использующего функцию. Повторная регистрация функции с тем же именем не приведет к ошибке, будет возвращен целый идентификатор, присвоенный этой функции при первой регистрации.

В модель блока, функция которого вызвана, передается структура, содержащая уникальный целый идентификатор функции, идентификатор вызвавшего блока и указатель на параметры функции. Параметры функции – это область данных (обычно структура или класс), в которой находятся входные параметры функции блока. При необходимости, туда же помещаются результаты возврата функции. Такая структура создается при написании модели блока для каждой конкретной функции. RDS никак не контролирует правильность передачи параметров, указанный при вызове функции адрес передается в модель блока без изменений. По этой причине очень важно следить за уникальностью имен функций – если параметры двух функций с одинаковыми именами будут различаться, блок может принять одну функцию за другую, и либо считать неверные значения параметров, либо, если размеры структур отличаются, обратиться к не отводившейся памяти и вызвать ошибку общей защиты. Для исключения таких ситуаций имеет смысл во все структуры параметров всех функций включать специальное поле, содержащее размер переданной структуры (причем лучше всего делать это поле самым первым в структуре), как это делается во многих функциях Windows API и сервисных функциях RDS. Несоответствие значения этого поля ожиданиям модели блока будет говорить о неправильном вызове функции.

Соединение рукоятки и поля ввода

Рис. 11. Соединение
рукоятки и поля ввода

Механизм вызова функций блоков можно использовать по-разному. Например, блок может активировать передачу данных по своим выходным связям при помощи сервисной функции rdsActivateOutputConnections, после чего получить из RDS список блоков, соединенных с его выходами, и информировать каждый из них об изменении входных данных вызовом функции (естественно, в моделях этих блоков должна быть реакция на эту функцию). Именно так работает функция «Common.ControlValueChanged», которую поддерживают стандартные поля ввода и индикаторы из библиотеки «Common.dll». Если, например, соединить связями вертикальную рукоятку и поле ввода (рис. 11), то в режиме моделирования (без запуска расчета) при перемещении рукоятки будет автоматически изменяться значение в поле ввода. Как только пользователь переместит рукоятку в другое положение, модель блока, отображающего рукоятку, вызовет сервисную функцию rdsActivateOutputConnections, что приведет к передаче по связи нового значения в блок, отображающий поле ввода. После этого модель рукоятки вызовет функцию «Common.ControlValueChanged» для соединенных с ней блоков, то есть для поля ввода. Модель поля ввода, реагируя на функцию, считает новое значение со своего входа и отобразит его. Эта же функция, вызываемая моделью поля ввода, приведет к тому, что при изменении значения в поле ввода рукоятка будет перемещаться в новое положение.

При помощи вызова функций можно также реализовать поиск блока по какому-нибудь значению, хранящемуся в личной области данных. Для этого следует зарегистрировать функцию поиска и вызвать ее для всех блоков схемы, передав в структуре параметров искомое значение. Модель блока, реагирующего на эту функцию, должна сравнить переданное значение с хранящимся в личной области данных, и, при совпадении, записать в структуру параметров функции идентификатор блока. Примеры взаимодействия блоков при помощи вызова функций рассмотрены в §2.13.


<< >> Оглавление Указатель