Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, иллюстрирующих отдельный расчет подсистемы. Библиотека содержит три модели:
- SetExclusiveCalc – блок, включающий и выключающий отдельный расчет родительской подсистемы по входным сигналам;
- ChgCalcTickCount – блок, увеличивающий свой выход на единицу каждый такт после изменения своего вещественного входа (нужен для построения графика «выбросов»);
- TestKxC – блок, вычисляющий значение выхода «y» по формуле «y=K×x+C» (копия модели из §2.7.4, сюда она включена для того, чтобы все модели из рассматриваемых примеров схем находились в одной библиотеке).
// Отдельный расчет подсистемы #include <windows.h> #include <RdsDef.h> // Подготовка описаний сервисных функций #define RDS_SERV_FUNC_BODY GetInterfaceFunctions #include <RdsFunc.h> //========== Главная функция DLL ========== int WINAPI DllMain(HINSTANCE /*hinst*/, unsigned long reason, void* /*lpReserved*/) { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL { // Получение доступа к функциям RDS if(!GetInterfaceFunctions()) RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS } return 1; } //========= Конец главной функции ========= //========================================= // Включение/выключение отдельного расчета //========================================= extern "C" __declspec(dllexport) int RDSCALL SetExclusiveCalc(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define Lock (*((char *)(pStart+2*RDS_VSZ_S))) #define Unlock (*((char *)(pStart+3*RDS_VSZ_S))) #define Locked (*((char *)(pStart+4*RDS_VSZ_S))) switch(CallMode) { // Проверка типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSSSL}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Такт расчета case RDS_BFM_MODEL: if(Lock) // Поступил сигнал включения отдельного расчета { if(Locked) // Отдельный расчет уже включен { Lock=0; // Сбрасываем сигнал, завершаем модель break; } // Включаем отдельный расчет родительской подсистемы if(rdsSetExclusiveCalc(BlockData->Parent,TRUE)) { // Включить удалось Lock=0; // Сбрасываем сигнал Locked=1; // Запоминаем факт включения } } if(Unlock) // Поступил сигнал выключения { if(Locked) // Отдельный расчет был включен - выключаем rdsSetExclusiveCalc(BlockData->Parent,FALSE); Locked=Lock=Unlock=0; // Сбрасываем сигналы и состояние } break; } return RDS_BFR_DONE; // Отмена макроопределений #undef Locked #undef Unlock #undef Lock #undef Ready #undef Start #undef pStart } //========================================= //========================================= // Счетчик тактов //========================================= extern "C" __declspec(dllexport) int RDSCALL ChgCalcTickCount(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define Count (*((RDSINT32 *)(pStart+2*RDS_VSZ_S))) #define Stop (*((RDSINT32 *)(pStart+2*RDS_VSZ_S+RDS_VSZ_I))) #define Enabled (*((char *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_I))) #define x (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_I+RDS_VSZ_L))) #define xold (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_I+RDS_VSZ_L+RDS_VSZ_D))) switch(CallMode) { // Проверка типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSIILDD}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Запуск расчета case RDS_BFM_STARTCALC: Start=1; // Принудительный запуск модели в следующем такте break; // Один такт моделирования case RDS_BFM_MODEL: if(!Enabled) // Работа блока не разрешена { xold=x; // Запоминаем значение входа break; } // Работа блока разрешена if(xold==x && Count==0) break; // Вход не изменился или счет не идет // Изменился вход (x!=xold) или уже считаем (Count!=0) Count++; // Увеличиваем число тактов if(Count>Stop) // Пора остановить расчет rdsStopCalc(); Start=1; // Принудительный перезапуск модели break; } return RDS_BFR_DONE; // Отмена макроопределений #undef xold #undef x #undef Enabled #undef Stop #undef Count #undef Ready #undef Start #undef pStart } //========================================= //========================================================================= // Блок y=Kx+C из прошлых примеров (нужен только как пример алгебраического // блока, в его модель после §2.7.4 не внесено никаких изменений) //========================================================================= // Проверка наличия связи у входа блока BOOL CheckBlockInputConnection( RDS_BHANDLE Block, // Идентификатор блока int num, // Номер входа RDS_PVARDESCRIPTION pVarDescr)// Указатель на структуру // описания переменной { RDS_CHANDLE c; // Идентификатор связи RDS_POINTDESCRIPTION PtDescr; // Структура описания точки связи // Заполнение служебных полей структур их размерами PtDescr.servSize=sizeof(PtDescr); pVarDescr->servSize=sizeof(RDS_VARDESCRIPTION); // Получение описания переменной блока по номеру if(rdsGetBlockVar(Block,num,pVarDescr)==NULL) return FALSE; // Нет такой переменной // Перебор всех связей, подключенных к этому блоку c=NULL; for(;;) { // Найти связь, следующую за c, и заполнить структуру // описания точки соединения PtDescr c=rdsGetBlockLink(Block,c,TRUE,FALSE,&PtDescr); if(c==NULL) // Больше нет связей break; // Найдена очередная связь – сравнение имени заданной // переменной с именем переменной точки этой связи if(strcmp(PtDescr.VarName,pVarDescr->Name)==0) return TRUE; // Имена совпали – есть связь, соединенная // с переменной блока } // Все подключенные связи перебраны, а связь, подключенная // к заданной переменной так и не была найдена return FALSE; } //========================================= // Добавление поля для ввода или индикации вещественного параметра // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" BOOL AddWinEditOrDisplayDouble( RDS_HOBJECT window, // Идентификатор объекта-окна RDS_BHANDLE Block, // Блок int varnum, // Номер переменной в блоке int ctrlnum, // Идентификатор поля ввода в окне char *title) // Заголовок поля или NULL { // Структура описания переменной блока RDS_VARDESCRIPTION VarDescr; // Проверка наличия связи у переменной varnum в блоке Block // и заполнение структуры VarDescr описанием переменной BOOL conn=CheckBlockInputConnection(Block,varnum,&VarDescr); if(conn) // К переменной подключена связь { // Вспомогательные переменные char *caption; // Заголовок поля double *cur; // Указатель на данные переменной // Заголовок поля формируется из имени переменной и // текста “подключена связь" caption=rdsDynStrCat(title?title:VarDescr.Name, " (подключена связь)", FALSE); // Добавление поля для индикации текущего значения rdsFORMAddEdit(window,0,ctrlnum,RDS_FORMCTRL_DISPLAY, caption,80); // Освобождение динамически сформированной строки заголовка поля rdsFree(caption); // Получение указателя на данные переменной cur=(double*)rdsGetBlockVarBase(Block,varnum,NULL); // Проверка – переменная должна существовать и иметь тип double if(cur!=NULL && VarDescr.Type=='D') // Занесение текущего значения переменной в поле rdsSetObjectDouble(window,ctrlnum,RDS_FORMVAL_VALUE, *cur); } else // К переменной не подключена связь { // Вспомогательная переменная для значения по умолчанию char *defval; // Получение строки со значением переменной по умолчанию // (необходимо потом освободить при помощи rdsFree) defval=rdsGetBlockVarDefValueStr(Block,varnum,NULL); // Добавление поля для ввода параметра rdsFORMAddEdit(window,0,ctrlnum,RDS_FORMCTRL_EDIT, title?title:VarDescr.Name,80); // Занесение в поле ввода значения перменной по умолчанию rdsSetObjectStr(window,ctrlnum,RDS_FORMVAL_VALUE,defval); // Освобождение динамически сформированной строки rdsFree(defval); } // Возврат: TRUE – есть связь, FALSE – нет связи return conn; } //========================================= // Функция настройки K и C для модели блока y=Kx+C // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" BOOL TestKxCSetup( RDS_BHANDLE Block, // Идентификатор блока int numK, // Номер переменной K в блоке int numC) // Номер переменной C в блоке { RDS_HOBJECT window; // Идентификатор вспомогательного объекта BOOL ok; // Пользователь нажал "OK" BOOL K_conn,C_conn; // Флаги наличия связей у K и C // Создание окна window=rdsFORMCreate(FALSE,-1,-1,"Kx+C"); // Добавление полей для ввода или индикации K и C // (в зависимости от наличия связей) K_conn=AddWinEditOrDisplayDouble(window,Block,numK,1,NULL); C_conn=AddWinEditOrDisplayDouble(window,Block,numC,2,NULL); // Открытие окна ok=rdsFORMShowModalEx(window,NULL); if(ok) { // Нажата кнопка OK – запись параметров в блок if(!K_conn) // У K нет связи { // Получение строки из поля ввода char *str=rdsGetObjectStr(window,1,RDS_FORMVAL_VALUE); // Установка значения переменной K по умолчанию rdsSetBlockVarDefValueStr(Block,numK,str); } if(!C_conn) // У С нет связи { // Получение строки из поля ввода char *str=rdsGetObjectStr(window,2,RDS_FORMVAL_VALUE); // Установка значения переменной C по умолчанию rdsSetBlockVarDefValueStr(Block,numC,str); } } // Уничтожение окна rdsDeleteObject(window); // Возвращаемое значение – истина, если нажата "OK" return ok; } //========================================= // Функция модели блока extern "C" __declspec(dllexport) int RDSCALL TestKxC(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define x (*((double *)(pStart+2*RDS_VSZ_S))) #define K (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define C (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define y (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) switch(CallMode) { // Проверка типа переменных case RDS_BFM_VARCHECK: if(strcmp((char*)ExtParam,"{SSDDDD}")==0) return RDS_BFR_DONE; return RDS_BFR_BADVARSMSG; // Запуск расчета case RDS_BFM_STARTCALC: // Если это запуск с начала, взвести Start if(((RDS_PSTARTSTOPDATA)ExtParam)->FirstStart) Start=1; // Модель запустится в первом же такте break; // Такт расчета case RDS_BFM_MODEL: y=K*x+C; break; // Функция настройки case RDS_BFM_SETUP: if(TestKxCSetup(BlockData->Block,3,4)) { // Нажата “OK" Start=1; // Запустить модель в следующем такте return RDS_BFR_MODIFIED; } } return RDS_BFR_DONE; // Отмена макроопределений #undef y #undef C #undef K #undef x #undef Ready #undef Start #undef pStart } //=========================================