⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 profibus.c

📁 SPC3 SETUP PROGRAMS SP C3 SETUP PROGRAMS
💻 C
📖 第 1 页 / 共 5 页
字号:



//*****************************************************************************
//**  K dosazeni dobreho casovani by tato funkce mela byt vyvolavana s periodou
//**  priblizne rouvnou Tbit. S touto periodou se vola pouze pokud je vystupni
//**  buffer pro vysilani DAT prazdny. 
//**
//**  Vyuziti pro zjistovani time-outu.
//**
//**  Volani zajistuje nizsi vrstva s navaznosti na hardwarove moznosti.
//**
//** ZMENA:
//**  Tato funkce je volana az pote, co jsou odvysilany vsechny casovaci znaky
//**  viz. param "pocet" u funkce "PB_SendNextTimingChars"
//**
//*****************************************************************************

void PB_TimeTick( PTProfibus PB )
{
  __int64 now;  
  int     i;

  if ( PB->TimeOutState == TO_Running )
  {
    now = GetCurrentTicks();

    if ( now < PB->TimeOutTicks )
    {
      // pokud casovac jeste nevyprsel - vysleme dalsi casovaci znaky
      PB_SendNextTimingChars( PB,
                              ( int )
                              ( ( PB->TimeOutTicks - now ) / PB->Tbit ) /
                              11 );
    }
    else
    {
      ////RS_DbgPrint("PB: Time Out !!\n");
      // Time Out !!!
      PB->TimeOutState = TO_Stopped;
      //Message= "TimeOut \'prestrelen\' o "+IntToStr( (now-TimeOutTicks)/Tbit )+" Tbit.";
      
      if ( ! ProfiM_RxFIFOEmpty( PB->DeviceExtension ) )
      {
        //
        // Time-out cekani na prijeti odpovedi na pozadavek je normalne
        // zastaven prijmem prvniho znaku pres funkci PB_RxByte. Pouziva-li
        // vsak UART pri prijmu FIFO pamet dozvime se o prichozim ramci az
        // tehdy je-li prijat cely. Proto jeste pred vygenerovanim time-outu
        // zjistime, zda-li ve FIFO jiz nejsou nejaka data. Jsou-li je 
        // time-out zastaven. Tim ovsem nenastane time-out pokud data ve
        // FIFO netvori odpoved na kterou cekame.
        //
        return;
        //
        // Lepsi by zrejme bylo v tomto miste poslat vsechny zatim prijate
        // znaky z FIFO do PB_RxByte a pak zjistit koreknost zatim prijatych
        // dat.
        //
      }              
      
      switch ( PB->MasterState )
      {
        
        //*************************************************************
        
        case Listen_Token:
          //
          // Na sbernici nebyl zaznamenan zadny provoz -> claim token
          //
          PB_DbgPrintL2( "PB: Zadny provoz na sbernici - prechod do Claim_Token (TS=%d)\n", PB->TS );
          PB_ChangeMasterState( PB, Claim_Token );
          break;
          
        //*************************************************************          

        case Active_Idle:
               
          if ( PB->LastState == Claim_Token )
          {
            //
            // Stanice s nejnizsi adresou nerestartovala vymenu tokenu
            //
            int LAS_PS;            
            int i=0;
            
            while ( i<=PB->HSA && PB->LAS.LAS[i]==LAS_Passive )
            {
              i++;
            }
            
            if (PB->LAS.LAS[i]==LAS_Active)
            {
              DbgPrint("PB: Stanice %d nerestartovala okruh nebo vypadla.", i);
              PB->LAS.LAS[i]=LAS_Passive;
            }
              
            LAS_PS = LAS_PreviousStation( &PB->LAS, PB->TS );
            if (LAS_PS >= PB->TS)
              PB_ChangeMasterState( PB, Use_Token );
            else
            PB_SetTimeOut( PB, Tto, TO_StartNow );  // pro pripad dalsiho vypadku
            
            break;
          }
          
          //
          // Na sbernici nebyl zaznamenan zadny provoz -> claim token
          //                                
          PB_DbgPrintL2( "PB: Na sbernici ustal provoz - prechod do Claim_Token (TS=%d)\n", PB->TS );
          PB_ChangeMasterState( PB, Claim_Token );
          break;                                                     

        //*************************************************************          

        case Await_Data_Resp:
          //
          // Na pozadavek vyslany na sbernici neprisla odpoved
          //    
                                         
          if ( PB->RLL_Status == RLL_TestNext )
          {
            //
            // Bezi pozadavek vytvareni Remote Life Listu
            //
            PB_DbgPrintL2( "PB: Stanice %d neodpovida (vytvareni Remote LASu)\n",
                           PB->RLL_Station );
            PB->RLL_LAS[PB->RLL_Station] = STATION_NON_EXISTENT;
            PB->RLL_Station++;
            if ( PB->RLL_Station == PB->TS )
            {
              PB->RLL_LAS[PB->RLL_Station] = PB->StationStatus << 4; PB->RLL_Station++;
            }
            if ( PB->RLL_Station > PB->HSA )
            {
              PB->RLL_Status = RLL_Stopped;
              build_conf( PB->ActualRequest, ok );
              for ( i = 0; i < 127; i++ )
                PB->ActualRequest->user_data_1[i] = PB->RLL_LAS[i];
              PB->ActualRequest->rb2_header.fill_length_1 = 127;
              PB->ActualRequest->application_block.receive_l_sdu.length = 127;
              ResB_Add( &PB->ResB, PB->ActualRequest );
            }
            else
              PB->RLL_Status = RLL_WaitNextCycle;

            PB_ChangeMasterState( PB, Use_Token );
          }
          else
          {
            //
            // Stanice neodpovida na vyslany pozadavek (SRD, SDN, Ident,...)
            //
            PB_DbgPrintL2( "PB: Stanice %d neodpovida na pozadavek!",
                           PB->ActualRequest->application_block.rem_add.station );
            PB->FrameRepeatCounter++;
            if ( PB->FrameRepeatCounter <= PB->retry_ctr )
            {
              //
              // Zkusime pozadavek zopakovat
              //
              PB_ProcessRequest( PB, PB->ActualRequest );
            }
            else
            {
              //
              // Pocet opakovani pozadavku vyprsel. Stanice je v GAPu oznacena za
              // neaktivni a aplikacni vrstve je vracen negativni vysledek.
              //
              PB_DbgPrintL2( "PB: Stanice %d oznacena v GAPu za neaktivni.",
                             PB->ActualRequest->application_block.rem_add.station );
              PB->GAPL.GAPL[PB->ActualRequest->application_block.rem_add.station].StationState = GAP_Unused;
              PB->FrameRepeatCounter = 0;                                       
              build_conf( PB->ActualRequest, na );
              ResB_Add( &PB->ResB, PB->ActualRequest );                                                       
              PB_ChangeMasterState( PB, Use_Token );
            }
          }

          break;

        //*************************************************************          

        case Pass_Token:
          //
          // Stanice neodpovida na FDL Status Request pri vytvareni GAPL po studenem
          // startu logickeho okruhu.
          //
          
          if ( PB->ColdStart )
          {
            /* 
               // Stanice neodpovida na zadost FDL Request
               #ifdef VYPISY
                 Form1->LB->Items->Add(Format("FDL Status Timeout. Station %d marked as Unused.", ARRAYOFCONST(( GAPL->NextToTest() )) ));
                 Form1->OutLB->Items->Add("");
               #endif
               */

            GAPL_Update( &PB->GAPL, GAPL_NextToTest( &PB->GAPL ), GAP_Unused );
            if ( GAPL_NextToTest( &PB->GAPL ) == PB->TS + 1 ||                  // +1, jelikoz NextToTest preskakuje TS
                 ( PB->TS == PB->HSA && GAPL_NextToTest( &PB->GAPL ) == 0 ) )
            {
              // Jsme jedinym masterem na sbernici
              PB->NS = PB->TS;
              GAPL_UpdateNS( &PB->GAPL, PB->NS );
              PB->PS = PB->TS;
              PB->ColdStart = FALSE;
              PB_DbgPrintL2( "PB: Vytvoren GAP list studenym startem a jedeme dal.\n" );
              PB_SendToken( PB, PB->TS, PB->TS );
              PB_ChangeMasterState( PB, Check_Token_Pass );
            }
            else
              PB_SendRequestFDLStatuswithReply( PB,
                                                GAPL_NextToTest( &PB->GAPL ) ); // hledani dalsi stanice

          }
          break;

        //*************************************************************          

        case Await_Status_Resp:
          //
          // Update GAPu - stanice neodpovida na pozadavek FDL Status
          //
                    
          GAPL_Update( &PB->GAPL, GAPL_NextToTest( &PB->GAPL ), GAP_Unused );
          PB_ChangeMasterState( PB, Pass_Token );
          break;

        //*************************************************************          

        case Check_Token_Pass:
          //
          // Stanice, ktere jsme predali Token nejevi zadnou aktivitu.
          // Je oznacena v LASu za neaktivni a zkousime predat Token dalsi
          // stanici v logickem kruhu. Pokud zadna stanice Token neprijme
          // predavame Token sami sobe.
          //
                   
          PB_DbgPrintL2( "PB: NS master s adresou %d neprijal token", PB->NS );
          PB->LAS.LAS[PB->NS] = LAS_Passive;
          PB->NS = LAS_NextStation( &PB->LAS, PB->TS );
          GAPL_UpdateNS( &PB->GAPL, PB->NS );
          PB_DbgPrintL2( "PB:   Nova NS je stanice %d.", PB->NS );          
          if ( PB->NS == PB->TS )
          {
            PB->PS = PB->TS;
            PB_SendToken( PB, PB->TS, PB->TS );
            PB_ChangeMasterState( PB, Active_Idle );
          }
          else
          {
            PB_SendToken( PB, PB->NS, PB->TS );
            PB_ChangeMasterState( PB, Check_Token_Pass );
          }
          break;
          
        //*************************************************************          
          
      }
    }
  }
}


//*****************************************************************************
//**  Vyvola se po odeslani celeho ramce - zajistuje spusteni timeoutu, pokud
//**  je o nej zadano.
//**
//**  POZOR - funguje pouze pokud je datovy ramec v bufferu jako posledni a 
//**          vyvola se az od posledniho datoveho ramce !!! (pokud by nestacilo
//**          tak lze vyresit zavednim dalsiho typu znaku napr. TIMEMARK_CHAR )
//**
//*****************************************************************************

void PB_FrameOut( PTProfibus PB )
{
  //RS_DbgPrint("PB: Frame out\n");

  // melo by byt vykonano az potom  co posledni znak odejde cely z vystupniho bufferu
  if ( PB->TimeOutState == TO_WaittingTxEmpty )
  {
    PB->LastTicks = GetCurrentTicks();
    PB->TimeOutTicks = PB->LastTicks + PB->TO_Interval * PB->Tbit;
    PB_StartTimeOut( PB );
  }
}


//*****************************************************************************
//**  Zjistuje, zdali jeste zbyva cas pro vysilani zprav, aby byl dodrezen
//**  interval Ttr (Time To Reach).
//**
//*****************************************************************************

BOOLEAN PB_IsTimeForSending( PTProfibus PB )
{
  return ( ( GetCurrentTicks() - PB->LastUseTokenEntryTicks ) < PB->ttr );
}






//*****************************************************************************
//**  Zacne zpracovavat vybrany pozadavek. Pokud jeho vyrizeni nevyzaduje komu-
//**  nikaci z vnejskem, je oznacen jako Local a po odeslani odpovedi aplikacni
//**  vrstve (Confirmation) nasleduje prechod zpet do stavu Use_Token pro vyber
//**  dalsiho pozadavku (pokud zbyvajici cas dovoli).
//**  Vyzaduje-li vyrizeni pozadavku kominikaci z vnejskem je oznacen jako Re-
//**  mote a po vyslani zadosti na sbernici je ocekavana odpoved prechodem do
//**  stavu Await_Data_Resp.
//**
//**  Parametry:
//**  ----------
//**  Request - ukazatel na Request Block pozadavku ke zpracovani. Ten je vyb-
//**            ran ve stavu Use_Token
//*****************************************************************************

void PB_ProcessRequest( PTProfibus PB, fdl_rb *Request )
{
  int                         i;
  //  UBYTE data_unit[260];
  int                         h_offset;
  UBYTE                       Class;
  UBYTE                       SSAP, DSAP;
  UBYTE                       Tx_FC = 0x40;
  UBYTE                       Tx_DA;
  struct fdl_sap *            ptr;              
  struct bus_parameter_block *bus_prm_ptr;
  struct fdl_l_stat *         sptr;
  struct event_indication *   Event_ptr;
  struct statistic_ctr_list * c_list; 
  
  BYTE  *data;  


  PB->ActualRequest = Request;    // lepe prekopirovat data

 
  PB_DbgPrintL2("PB: Pozadavek CODE=%x", Request->application_block.service.code);
    
  switch ( Request->application_block.service.code )
  {
      
      
      //***************************************************************************      
      
    case srd:
      /* SRD request z aplikacni vrstvy */
      PB_DbgPrintL2( "PB:    pozadavek SRD\n" );
      PB->Service = Remote;                 /*remote sluzba*/                                           
      
      if ( PB->StationStatus != Master_in_logical_ring )
      {
        build_conf_srd( Request, 0, 0, ds );          /*L_status ds*/
        ResB_Add( &PB->ResB, Request );
        PB->Service = Local;
        break;
      }         

      DSAP = Request -> application_block.dsap ;    /*priprava SAPu*/
      if ( DSAP == DEFAULT_SAP )
        DSAP = (unsigned char) PB->default_sap;       
      
      SSAP = Request -> application_block.ssap ;
      if ( SSAP == DEFAULT_SAP )
        SSAP = (unsigned char) PB->default_sap;       
        
      

      if ( ( SSAP<0 || SSAP>63 ) && SSAP != DEFAULT_SAP/*SAPNIL*/ )
      {
        build_conf_srd( Request, 0, 0, ls );          /*L_status ds*/           
        ResB_Add( &PB->ResB, Request );
        PB->Service = Local;
        break;
      }
      //je local SAP vubec aktivovany

      
      if ( PB->SAP.SAPItem[SSAP].SRD == SERVICE_NOT_ACTIVATED )  
      {
        build_conf_srd(Request,0,0,ls);          // L_status ls
        ResB_Add(&PB->ResB, Request);
        PB->Service=Local;
        break;            
      }


      Class = Request -> rb2_header.priority;
      Tx_DA = Request -> application_block.rem_add.station;
      h_offset = Request -> user_data_1[0];
      if ( Class == low )
        Tx_FC = Tx_FC | 0x0c;   /*SRD Lo*/
      else
        Tx_FC = Tx_FC | 0x0d;                  /*Hi */

      if ( ( ( Class != low ) && ( Class != high ) ) ||
           

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -