www.pudn.com > PROFIBUS_DP_protocol_source.ZIP > lists.c, change:2004-03-17,size:12953b


//----------------------------------------------------------------------------- 
// $Id: lists.c,v 1.0.0                                             2004/01/13 
//----------------------------------------------------------------------------- 
// 
//      ProfiM - PROFIBUS MASTER DRIVER FOR WINDOWS NT/2000 
// 
// Author:   
//      Pavel Trnka, CTU FEE 
//      trnkap@seznam.cz 
// With help and advices from: 
//      Ing. Petr Smolik, CTU FEE 
//      Ing. Pavel Pisa, CTU FEE 
//      Ing. Pavel Burget, CTU FEE 
// 
//----------------------------------------------------------------------------- 
// 
// Popis: 
// ------ 
// Definuje seznamy LAS a GAP pro Profibus. 
// 
// Vyznam seznamu LAS a GAP: 
// ------------------------- 
// 
//  LAS - ke kazde adrese (v celem rozsahu adres 0..HSA) uvadi jestli je: 
//          Active - aktivni master v logickem podilejici se na predavani 
//                   tokenu 
//          Passive - stanice nepripojena, stanice typu slave nebo stanice 
//                    typu master, ktera jeste neni v zaclenena logickemu 
//                    ringu masteru predavajicich si token 
//        LAS se aktualizuje s kazdym obehem tokenu (z datoveho toku na sbernici). 
// 
//  GAP - je mnohem konkretnejsi nez LAS, ale je udrzovan pouze pro adresy 
//        v rozsahu TS+1..NS-1 (pro mono-master system ovsem pro cely 
//        adresni prostor) 
//        Stavy: 
//           Slave 
//           MasterNotReady 
//           Unused 
//        Cely se zaktualizuje vzdu az po nekolika obezich tokenu a to 
//        podle hodnoty koeficientu G (priblizne po G*(pocet stanic mezi 
//        TS a NS) ) 
// 
//--------------------------------------------------------------------------- 
//--------------------------------------------------------------------------- 
 
#include "NTDDK.H" 
 
#include "lists.h" 
#include "vardef.h" 
 
 
//***************************************************************************** 
 
void LAS_Init( PTLAS LAS, int size ) 
{ 
  LAS->length = size; 
  LAS_Clear( LAS ); 
  LAS->NewState = Stop; 
  LAS->LastActive = -1; 
} 
 
//***************************************************************************** 
 
void LAS_Close( PTLAS LAS ) 
{ 
} 
 
 
//***************************************************************************** 
//**  Zajistuje update LASu po jeho vytvoreni 
//** 
//***************************************************************************** 
 
void LAS_Update( PTLAS LAS, int adr ) 
{ 
  int i; 
  if ( adr < LAS->length && adr != LAS->LastActive ) 
  { 
    LAS->LAS[adr] = LAS_Active; 
    if ( adr > LAS->LastActive ) 
      for ( i = LAS->LastActive + 1; i < adr; i++ ) 
        LAS->LAS[i] = LAS_Passive; 
    else 
    { 
      for ( i = LAS->LastActive + 1; i < LAS->length; i++ ) 
        LAS->LAS[i] = LAS_Passive; 
      for ( i = 0; i < adr; i++ ) 
        LAS->LAS[i] = LAS_Passive; 
    } 
    LAS->LastActive = adr; 
  } 
} 
 
 
//***************************************************************************** 
//**  Vola se pri vytvareni LASu, pokud je master ve stavu Listen_Token. 
//**  Vrati true pokud pridavane stanice vytvorili dva identicke cykly. 
//** 
//***************************************************************************** 
 
int LAS_CreatingAdd( PTLAS LAS, int adr ) 
{ 
  int i; 
 
  if ( adr < LAS->length ) 
  { 
    LAS->LastActive = adr;  // pozor - spis by mel byt na konci 
 
    if ( LAS->NewState == Stop ) 
    { 
      LAS->NewState = First_Cycle; 
    } 
    if ( LAS->NewState == Done ) 
    { 
      LAS_Clear( LAS ); 
      LAS->NewState = First_Cycle; 
    } 
 
    if ( LAS->LAS[adr] == LAS_Active ) 
    { 
      if ( LAS->NewState == Second_Cycle ) 
      { 
        int Equal = 1; 
        for ( i = 0; i < LAS->length; i++ ) 
          Equal *= ( LAS->TestLAS[i] == LAS->LAS[i] ); 
        if ( Equal )                      // Oba pruchody jsou stejne 
        { 
          LAS->NewState = Done; 
          return TRUE; 
        } 
        else                            // Pruchody se lisi 
        { 
          LAS->NewState = Second_Cycle; 
          for ( i = 0; i < LAS->length; i++ ) 
            LAS->TestLAS[i] = LAS->LAS[i]; 
          LAS_Clear( LAS ); 
        } 
      } 
      if ( LAS->NewState == First_Cycle ) 
      { 
        for ( i = 0; i < LAS->length; i++ ) 
          LAS->TestLAS[i] = LAS->LAS[i]; 
        LAS_Clear( LAS ); 
        LAS->NewState = Second_Cycle; 
      } 
    } 
 
    LAS->LAS[adr] = LAS_Active; 
  } 
  return FALSE; 
} 
 
//***************************************************************************** 
 
void LAS_Clear( PTLAS LAS ) 
{ 
  int i; 
  if ( LAS->length > 1 ) 
    for ( i = 0; i < LAS->length; i++ ) 
      LAS->LAS[i] = LAS_Passive; 
} 
 
//***************************************************************************** 
 
int LAS_Complete( PTLAS LAS ) 
{ 
  return ( LAS->NewState == Done ); 
} 
 
 
//***************************************************************************** 
//**  Vraci adresu predchoziho mastera k TS podle LASu. Pokud neexistuje 
//**  tak vraci TS. 
//** 
//**  Predchozi stanice PS podle aktualniho LAS - nikoliv podle Mastera. 
//** 
//***************************************************************************** 
 
int LAS_PreviousStation( PTLAS LAS, int TS )        
{ 
  /* 
  int i; 
  if ( TS < LAS->length ) 
  { 
    if ( TS > 0 ) 
      for ( i = TS - 1; i >= 0; i-- ) 
        if ( LAS->LAS[i] == LAS_Active ) 
          return i; 
    if ( TS < LAS->length - 1 ) 
      for ( i = LAS->length - 1; i > TS; i-- ) 
        if ( LAS->LAS[i] == LAS_Active ) 
          return i; 
  } 
  */ 
   
  int i;   
   
  if ( TS < 0 || TS >= LAS->length ) 
    return 0;   // TS ma chybnou hodnotu  
   
  i = TS-1; 
  if ( i < 0 ) 
    i = LAS->length - 1;   
 
  while ( LAS->LAS[i] != LAS_Active && i != TS )   
  {   
    i--; 
    if ( i < 0 ) 
      i = LAS->length - 1;       
  } 
   
  if ( LAS->LAS[i] == LAS_Active ) 
    return i;   
     
  return TS;      // zadna jina aktivni stanice v LAS neni 
} 
 
 
//***************************************************************************** 
//**  Vraci adresu mastera mastera k TS podle LASu. Pokud neexistuje 
//**  tak vraci TS. 
//** 
//**  Nasledujici stanice PS podle aktualniho LAS - nikoliv podle Mastera. 
//** 
//***************************************************************************** 
 
int LAS_NextStation( PTLAS LAS, int TS )        
{ 
  /* 
  int i; 
  if ( TS < LAS->length ) 
  { 
    if ( TS < LAS->length - 1 ) 
      for ( i = TS + 1; i < LAS->length; i++ ) 
        if ( LAS->LAS[i] == LAS_Active ) 
          return i; 
    if ( TS > 0 ) 
      for ( i = 0; i < TS; i++ ) 
        if ( LAS->LAS[i] == LAS_Active ) 
          return i; 
  } 
  */ 
   
  int i; 
   
  if ( TS < 0 || TS >= LAS->length ) 
    return 0;   // TS ma chybnou hodnotu 
   
  i = TS+1; 
  if ( i >= LAS->length ) 
    i = 0;   
 
  while ( LAS->LAS[i] != LAS_Active && i != TS )   
  {   
    i++; 
    if ( i >= LAS->length ) 
      i = 0; 
  } 
   
  if ( LAS->LAS[i] == LAS_Active ) 
    return i;   
   
  return TS;      // zadna jina aktivni stanice v LAS neni 
} 
 
 
//***************************************************************************** 
//**  Prevede LAS na retezec - vypise ty adresy, kterym odpovida aktivni 
//**  master. 
//** 
//***************************************************************************** 
 
/* 
Z puvodni verze - neprevedeno 
 
String TLAS::ToString() 
{ 
        String  S=""; 
        for (int i=0; i<length; i++) 
         if (LAS[i]==LAS_Active) S+=" "+IntToStr(i); 
          else S+="  "; 
 
        return S; 
} 
*/ 
 
//***************************************************************************** 
//**  Vymaze vsechny zaznamy aktivnich stanic mezi TS a PS (pro PS<TS i PS>TS) 
//** 
//***************************************************************************** 
 
void LAS_VymazStanice( PTLAS LAS, int TS, int PS ) 
{ 
  int i; 
  if ( PS < TS ) 
  { 
    for ( i = PS + 1; i < TS; i++ ) 
      LAS->LAS[i] = LAS_Passive; 
  } 
  else if ( PS > TS ) 
  { 
    for ( i = 0; i < TS; i++ ) 
      LAS->LAS[i] = LAS_Passive; 
    for ( i = PS + 1; i < LAS->length; i++ ) 
      LAS->LAS[i] = LAS_Passive; 
  } 
  else  // PS=TS 
  { 
    LAS_Clear( LAS ); 
    LAS->LAS[TS] = LAS_Active;             // snad OK - zalezi odkud se mazani TS,TS vola 
  } 
} 
 
 
//***************************************************************************** 
//**  Vola se pri Claim_Token - master je na sbernici sam. 
//** 
//***************************************************************************** 
 
void LAS_NoStations( PTLAS LAS ) 
{ 
  LAS_Clear( LAS ); 
  LAS->NewState = Done; 
} 
 
 
 
 
//***************************************************************************** 
//***************************************************************************** 
//***************************************************************************** 
 
 
 
 
//***************************************************************************** 
//**  Inicializce GAPListu - dulezite predani adresy TS 
//** 
//***************************************************************************** 
 
void GAPL_Init( PTGAPL GAPL, int _length, int _TS ) 
{ 
  GAPL->length = _length; 
  GAPL->TS = _TS; 
  GAPL->NS = -1; 
  GAPL_Clear( GAPL ); 
  GAPL->LastTested = GAPL->TS;  // pristi testovanou tak bude nasledujici po TS 
} 
 
//***************************************************************************** 
 
void GAPL_Close( PTGAPL GAPL ) 
{ 
} 
 
//***************************************************************************** 
 
void GAPL_Clear( PTGAPL GAPL ) 
{ 
  int i; 
  for ( i = 0; i < GAPL->length; i++ ) 
  { 
    GAPL->GAPL[i].StationState = GAP_Unused; 
    GAPL->GAPL[i].FCV = FALSE; 
    GAPL->GAPL[i].FCB = TRUE; 
  } 
} 
 
 
//***************************************************************************** 
//**  Zajisti aby dalsi testovanou stanici z GAPL byla TS+1 
//** 
//***************************************************************************** 
 
void GAPL_RestartTest( PTGAPL GAPL ) 
{ 
  GAPL->LastTested = GAPL->TS;  // pristi testovanou tak bude nasledujici po TS 
} 
 
//***************************************************************************** 
 
void GAPL_UpdateNS( PTGAPL GAPL, int _NS ) 
{ 
  GAPL->NS = _NS; 
} 
 
 
//***************************************************************************** 
//**  Vybere z GAPu adresu dalsi stanice, ktera by se mela testovat dotazem 
//**  FDL Status. 
//**  Opetovne volani vrati uz dalsi adresu. 
//** 
//***************************************************************************** 
 
int GAPL_NextToTest( PTGAPL GAPL ) 
{ 
  int next; 
   
  if ( (GAPL->TS+1 == GAPL->NS) || 
       ((GAPL->TS == GAPL->length-1) && (GAPL->NS==0)) ) 
  { 
    // 
    // mezi TS a NS nelezi zadne stanice 
    // 
    return -1;    
  } 
   
  next = GAPL->LastTested + 1; 
   
  if ( next >= GAPL->length - 1 ) 
    next = 0; 
       
  if ( next == GAPL->NS ) 
    next = GAPL->TS + 1; 
     
  if ( next == GAPL->TS ) 
    next = GAPL->TS + 1;   
    
/*   
  // 
  // je-li master na sbernici sam - potom NS=-1, spis NS=TS 
  // 
 
   
  if ( GAPL->NS > GAPL->TS )               
  { 
    if ( GAPL->LastTested < ( GAPL->NS - 1 ) ) 
      next = GAPL->LastTested + 1; 
    else 
      next = GAPL->TS + 1; 
  } 
  else 
  { 
    if ( GAPL->LastTested >= GAPL->TS )                 // i = ??? 
    { 
      if ( GAPL->LastTested >= GAPL->length - 1 ) 
        next = 0; 
      else 
        next = GAPL->LastTested + 1; 
    } 
    else 
    { 
      if ( GAPL->LastTested == GAPL->TS - 1 ) 
        next = GAPL->TS + 1; 
      else 
        next = GAPL->LastTested + 1; 
    } 
  } 
*/ 
 
  return next; 
} 
 
 
//***************************************************************************** 
//**  Ulozi do GAPu aktualizovany stav stanice na adrese adr. A zaznamena jeji 
//**  adresu jako posledni testovanou. 
//** 
//***************************************************************************** 
 
void GAPL_Update( PTGAPL GAPL, int adr, TGAPState _StationState ) 
{ 
  //        if ( adr!=NextToTest() ) ToByNemeloNastat !!! 
  if ( adr >= 0 && adr < GAPL->length ) 
  { 
    GAPL->GAPL[adr].StationState = _StationState; 
 
    GAPL->LastTested = adr; 
  } 
} 
 
 
//***************************************************************************** 
//** Invertuje FCB 
//** Pokud je FCV==false predpoklada, ze doslo k vyslani prvni ramce s urcenim 
//** pocatecni hodnoty FCB a tak nastavuje FCV=true 
//** 
//***************************************************************************** 
 
void GAPL_FCBToggle( PTGAPL GAPL, int adr ) 
{ 
  if ( !GAPL->GAPL[adr].FCV ) 
    GAPL->GAPL[adr].FCV = TRUE; 
  GAPL->GAPL[adr].FCB = !GAPL->GAPL[adr].FCB;  // nemusi tady fungovat 
} 
 
//*****************************************************************************