?? profibus.c
字號:
//*****************************************************************************
//** 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 ) ) ||
( Tx_DA > 126 ) ||
( ( DSAP > 62 ) &&
( DSAP < 255 ) &&
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -