Текущий раздел:

Описания RDS

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

Глава 2. Создание моделей блоков

§2.6. Динамические переменные

§2.6.3. Создание и удаление динамической переменной

Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, организующих передачу данных между частями схемы через динамическую переменную, имя которой задается пользователем в комментарии блока. Библиотека содержит две модели:

- TestTunnelIn – блок-передатчик;
- TestTunnelOut – блок-приемник.

      // Связь между блоками через динамическую переменную - п.2.6.3
      #include <windows.h>
      #include <math.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 TestTunnelIn(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)))
        // Вспомогательная переменная – указатель на структуру подписки
        RDS_PDYNVARLINK Link;
        // Вспомогательная переменная – структура описания блока
        RDS_BLOCKDESCRIPTION Descr;

        switch(CallMode)
          { // Очистка
            case RDS_BFM_CLEANUP:
              // Запомненный указатель на структуру подписки
              Link=(RDS_PDYNVARLINK)BlockData->BlockData;
              // Удалить созданную динамическую переменную
              rdsDeleteDVByLink(Link);
              break;

            // Проверка типа статических переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSD}")==0)
                return RDS_BFR_DONE;
              return RDS_BFR_BADVARSMSG;

            // Переход в режим моделирования
            case RDS_BFM_CALCMODE:
              // Запомненный указатель на структуру подписки
              Link=(RDS_PDYNVARLINK)BlockData->BlockData;
              if(Link!=NULL) // Динамическая переменная была создана
                { // Заполнить структуру описания блока
                  Descr.servSize=sizeof(Descr);
                  rdsGetBlockDescription(BlockData->Block,&Descr);
                  // Сравнить имя переменной с текстом комментария
                  if(strcmp(Link->VarName,Descr.BlockComment)!=0)
                    { // Имя переменной не совпадает с комментарием -
                      // переменная будет удалена
                      rdsDeleteDVByLink(Link);
                      // Очистить запомненный указатель на структуру подписки
                      BlockData->BlockData=NULL;
                    }
                }
              break;

            // Запуск расчета
            case RDS_BFM_STARTCALC:
              if(BlockData->BlockData!=NULL) // Переменная была создана
                break;
              // Динамической переменной нет (не было или удалена
              // в реакции на RDS_BFM_CALCMODE) - надо создать новую.
              // Сначала надо получить комментарий блока
              Descr.servSize=sizeof(Descr);
              rdsGetBlockDescription(BlockData->Block,&Descr);
              if(*Descr.BlockComment==0) // Комментарий пуст
                break;
              // Комментарий блока – не пустая строка. Создаем
              // переменную.

              Link=rdsCreateAndSubscribeDV(RDS_DVROOT,
                                           Descr.BlockComment,
                                           "D",
                                           TRUE,
                                           NULL);
              // Запомнить новый указатель на структуру подписки
              BlockData->BlockData=Link;
              // В конце реакции на запуск расчета нет оператора break,
              // поэтому сразу после нее выполнится реакция на
              // такт расчета (чтобы начальное значение входа
              // записалось в динамическую переменную)

            // Выполнение такта моделирования
           case RDS_BFM_MODEL:
              // Запомненный указатель на структуру подписки
              Link=(RDS_PDYNVARLINK)BlockData->BlockData;
              // Проверка существования переменной
              if(Link!=NULL && Link->Data!=NULL)
                { // Переменная существует – привести указатель
                  // на область данных переменной к типу "double*"
                  double *pV=(double*)Link->Data;
                  if(*pV!=x) // Значение входа изменилось
                    { // Записать в динамическую переменную новое
                      // значение входа
                      *pV=x;
                      // Уведомить всех подписчиков об изменении
                      // переменной
                      rdsNotifyDynVarSubscribers(Link);
                    }
                }
              break;
          }
        return RDS_BFR_DONE;
      // Отмена макроопределений
      #undef x
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=========================================

      //============ Блок-приемник ==============
      extern "C" __declspec(dllexport)
           int RDSCALL TestTunnelOut(int CallMode,
                                     RDS_PBLOCKDATA BlockData,
                                     LPVOID ExtParam)
      {
      // Макроопределения для статических переменных
      #define pStart  ((char *)(BlockData->VarTreeData))
      #define Start (*((char *)(pStart)))
      #define Ready (*((char *)(pStart+RDS_VSZ_S)))
      #define y (*((double *)(pStart+2*RDS_VSZ_S)))
        // Вспомогательная переменная – указатель на структуру подписки
        RDS_PDYNVARLINK Link;
        // Вспомогательная переменная – структура описания блока
        RDS_BLOCKDESCRIPTION Descr;

        switch(CallMode)
         { // Очистка
            case RDS_BFM_CLEANUP:
              // Запомненный указатель на структуру подписки
              Link=(RDS_PDYNVARLINK)BlockData->BlockData;
              // Прекратить подписку на переменную
              rdsUnsubscribeFromDynamicVar(Link);
              break;

            // Проверка типа статических переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSD}")==0)
                return RDS_BFR_DONE;
              return RDS_BFR_BADVARSMSG;

            // Запуск расчета
            case RDS_BFM_STARTCALC:
              // Запомненный указатель на структуру подписки
              Link=(RDS_PDYNVARLINK)BlockData->BlockData;
              // Получение описания блока (с комментарием)
              Descr.servSize=sizeof(Descr);
              rdsGetBlockDescription(BlockData->Block,&Descr);
              // Проверка наличия комментария
              if(*Descr.BlockComment==0) // Пустая строка
                { // Прекратить подписку на переменную
                  rdsUnsubscribeFromDynamicVar(Link);
                  // Очистить запомненный указатель на структуру подписки
                  BlockData->BlockData=NULL;
                  break;
                }
              // Если переменной нет (Link==NULL) или ее имя не
              // соответствует комментарию блока (strcmp... !=0),
              // нужно подписаться на новую переменную
              if(Link==NULL ||
                 strcmp(Link->VarName,Descr.BlockComment)!=0)
                { // Прекратить подписку на старую переменную
                  rdsUnsubscribeFromDynamicVar(Link);
                  // Подписаться на новую
                  Link=rdsSubscribeToDynamicVar(RDS_DVROOT,
                                                Descr.BlockComment,
                                                "D",
                                                FALSE);
                  // Запомнить новый указатель на структуру подписки
                  BlockData->BlockData=Link;
                }
              // В конце реакции на запуск расчета нет оператора break,
              // поэтому сразу после нее выполнится реакция на
              // изменение динамической переменной (чтобы ее значение
              // было немедленно передано на выход блока)

            // Реакция на изменение динамической переменной
            case RDS_BFM_DYNVARCHANGE:
              // Запомненный указатель на структуру подписки
              Link=(RDS_PDYNVARLINK)BlockData->BlockData;
              // Проверка существования переменной
              if(Link!=NULL && Link->Data!=NULL)
                { // Присвоить выходу блока значение динамической
                  // переменной
                  y=*(double*)Link->Data;
                  // Взвести сигнал Ready, чтобы значение выхода
                  // было передано по связям
                  Ready=1;
                }
              break;
          }

        return RDS_BFR_DONE;
      // Отмена макроопределений
      #undef y
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=========================================