📄 frame.c
字号:
//-----------------------------------------------------------------------------
// $Id: frame.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:
// ------
// Funkce pro praci s ramci sbernice Profibus.
//
//
// Funkce volane z vnejsku:
// ---------------------------
//
// PBFrame_DecodeFrame - urci typ ramce a dekoduje jej do jednotlivych
// promennych
// PBFrame_FindFrame - hleda vyskyt platneho ramce v bufferu a jako
// vysledek vraci jeho polohu a delku
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include "NTDDK.H"
#include "vardef.h"
#include "frame.h"
//*****************************************************************************
void PBFrame_Init( PTPBFrame PBF )
{
PBF->Valid = FALSE;
}
//*****************************************************************************
//** Urci typ ramce a dekoduje jej do promennych struktury
//**
//*****************************************************************************
// POZOR - Indexy do Stringu zacinaji na jednicce, nikoliv na nule!
void PBFrame_DecodeFrame( PTPBFrame PBF,
PUCHAR frame,
int FrameLen,
int TS,
int DefaultSAP )
{
int i;
int data_pos = 0; // ukazatel na pocatek dat ve framu - posune se pokud ma frame Address Extension
frame = frame - 1; // puvodne pouzivany String preveden na pole UCHAR (indexace se lisi o jednicku)
PBF->Valid = FALSE;
//!! String frame=_frame+ AnsiString::StringOfChar('\x00', 30); // doplneni delky pro moznost primeho testovani znaku bez chyby - out of range
//!! Nutno zajistit dostatecne dlouhy buffer
PBF->DA = frame[2]; // pokud je frame SD2 tak se jeste zmeni
PBF->SA = frame[3];
// delky uz by nemelo byt potreba kontrolovat
if ( frame[1] == DelimiterSD4 && FrameLen >= 3 ) // Token
{
PBF->FrameType = FT_Token;
PBF->Data_length = 0;
PBF->Valid = TRUE;
return; /* !! */
}
if ( frame[1] == DelimiterSC && FrameLen >= 1 ) // Short Acknowledge
{
PBF->FrameType = FT_ShortAcknowledge;
PBF->Data_length = 0;
PBF->Valid = TRUE;
PBF->ACK = ACK_OK; //muzu u Short Acknowledge ?
return; /* !! */
}
if ( frame[1] == DelimiterSD1 ) // Fixed length frame with NO data field
{
PBF->FC = frame[4];
PBF->FCS = frame[5];
PBF->ED = frame[6];
PBF->Data_length = 0;
// jeste pridat test na FCS (ED uz otestovan)
PBF->Valid = TRUE;
}
if ( frame[1] == DelimiterSD3 ) // Fixed length frame WITH Data field
{
PBF->FC = frame[4];
PBF->FCS = frame[13];
PBF->ED = frame[14];
data_pos = 5;
PBF->Data_length = 8;
//vycucnout data - az nakonec - jeste je treba zjistit offset pokud je Address Extension
PBF->Valid = TRUE;
}
if ( frame[1] == DelimiterSD2 ) // Variable length frame WITH Data field
{
PBF->LE = frame[2];
PBF->LEr = frame[3];
if ( PBF->LE == PBF->LEr && PBF->LE >= 4 && frame[4] == DelimiterSD2 )
{
PBF->DA = frame[5];
PBF->SA = frame[6];
PBF->FC = frame[7];
data_pos = 8;
PBF->Data_length = PBF->LE - 3; // snad OK?
//vycucnout data - az nakonec - jeste je treba zjistit offset pokud je Address Extension
PBF->Valid = TRUE;
}
}
if ( ( PBF->DA & 0x7F ) == BROADCAST )
PBF->DA = (UBYTE) TS; // zpusob jak vyresit prijem broadcastu
//pokud nema frame SAPy tak nastavi defaultni
PBF->DSAP = (UBYTE) DefaultSAP;
PBF->SSAP = (UBYTE) DefaultSAP;
if ( frame[1] == DelimiterSD2 || frame[1] == DelimiterSD3 ) // dekodovani Address Extension
{
if ( PBF->DA & 0x80 )
{
if ( frame[data_pos] & 0x80 )
{
data_pos++; PBF->Data_length--; PBF->DSAP = frame[data_pos];
}
else if ( !( frame[data_pos] & 0x40 ) )
PBF->DSAP = frame[data_pos];
data_pos++;PBF->Data_length--;
PBF->DA = PBF->DA & 0x7F;
}
if ( PBF->SA & 0x80 )
{
if ( frame[data_pos] & 0x80 )
{
data_pos++; PBF->Data_length--; PBF->SSAP = frame[data_pos];
}
else if ( !( frame[data_pos] & 0x40 ) )
PBF->SSAP = frame[data_pos];
data_pos++;PBF->Data_length--;
PBF->SA = PBF->SA & 0x7F;
}
// vycucnuti dat
for ( i = 0; i < PBF->Data_length; i++ )
PBF->Data[i] = frame[i + data_pos]; // puvodne bylo Data[i+1], ale ted by to melo byt spravne
}
if ( PBF->Valid && ( PBF->ED != DelimiterED /*|| !test CRC*/ ) )
{
PBF->Valid = FALSE;
}
if ( PBF->Valid )
{
/* dekoduj FC apod.*/
PBF->FC &= 0x7F; // odriznuti rezervovaneho osmeho bitu - nejspis neni potreba
if ( PBF->FC & 0x40 ) // Request, Send/Request Frame
{
switch ( ( PBF->FC & 0x0F ) )
{
case 4:
PBF->FrameType = FT_SDNLow; break;
case 6:
PBF->FrameType = FT_SDNHigh; break;
case 9:
PBF->FrameType = FT_RequestFDLStatuswithReply; break;
case 12:
PBF->FrameType = FT_SRDLow; break;
case 13:
PBF->FrameType = FT_SRDHigh; break;
case 14:
PBF->FrameType = FT_RequestIdentwithReply; break;
case 15:
PBF->FrameType = FT_RequestLSAPStatuswithReply; break;
default:
PBF->Valid = FALSE;
}
//if ((PBF->FC & 0x0F)==9) PBF->FrameType=FT_RequestFDLStatuswithReply;
}
else // Acknowledgement, Response Frame
{
PBF->FrameType = FT_Reply;
PBF->ACK = /*TACK*/ PBF->FC & 0x0F;
PBF->StnType = /*TStationStatus*/ ( PBF->FC & 0x30 ) >> 4 ;
}
}
}
//*****************************************************************************
//** Urci jestli dany retezec obsahuje na zacatku platny ramec (platnost se
//** urcuje pouze tim jestli zacina platnym Start Delimeterm a konci End
//** Delimiterem). Urci jak je tento ramec dlouhy (vyhledanim End Delimiteru).
//*****************************************************************************
BOOLEAN PBFrame_FindFrame( PUCHAR buffer, int BufLen, int *length )
{
buffer = buffer - 1; // puvodne pouzivany String preveden na pole UCHAR (indexace se lisi o jednicku)
if ( BufLen > 0 )
if ( buffer[1] == DelimiterSD1 ||
buffer[1] == DelimiterSD2 ||
buffer[1] == DelimiterSD3 ||
buffer[1] == DelimiterSD4 ||
buffer[1] == DelimiterSC )
{
if ( buffer[1] == DelimiterSD1 && BufLen >= 6 )
if ( buffer[6] == DelimiterED )
{
*length = 6; return TRUE;
}
if ( buffer[1] == DelimiterSD2 )
{
int L, EDpos;
if ( BufLen >= 2 )
{
L = buffer[2];
EDpos = 4 + L + 2;
if ( BufLen >= EDpos )
if ( buffer[EDpos] == DelimiterED )
{
*length = EDpos;
return TRUE;
}
}
} // pozor ED uz muze patrit k jinemu framu pokud je SD2 ramec poruseny
if ( buffer[1] == DelimiterSD3 && BufLen >= 14 )
if ( buffer[14] == DelimiterED )
{
*length = 14; return TRUE;
} // pozor testovani ED na 14 muze byt zradne a znicit napr dobry buffer po spatnem typu SD3
if ( buffer[1] == DelimiterSD4 && BufLen >= 3 )
{
*length = 3; return TRUE;
}
if ( buffer[1] == DelimiterSC && BufLen >= 1 )
{
*length = 1; return TRUE;
}
}
return FALSE;
}
//*****************************************************************************
//** Hleda v retezci vyskyt nektereho ze Start Delimiteru. Pri nalezeni vrati
//** jeho pozici v buffer. Pokud zadny neni nalezen vraci -1.
//**
//*****************************************************************************
int PBFrame_FindStartDelimiter( PUCHAR buffer, int BufLen )
{
int i;
buffer = buffer - 1; // puvodne pouzivany String preveden na pole UCHAR (indexace se lisi o jednicku)
for ( i = 1; i <= BufLen; i++ )
{
if ( buffer[i] == DelimiterSD1 ||
buffer[i] == DelimiterSD2 ||
buffer[i] == DelimiterSD3 ||
buffer[i] == DelimiterSD4 ||
buffer[i] == DelimiterSC )
return i;
}
return -1;
}
//*****************************************************************************
//** Urci je-li dany znak platnym Start Delimiterem SDx (pro SC vraci take
//** FALSE ).
//**
//*****************************************************************************
BOOLEAN IsStartDelimiterSDx( char ch )
{
return ( ch == DelimiterSD1 ||
ch == DelimiterSD2 ||
ch == DelimiterSD3 ||
ch == DelimiterSD4 );
}
/*
//*****************************************************************************
//** Prevede retezec tvoreny sekvenci hexadecimalnich cisel na retezec bytu,
//** kde kazdy odpovida jednomu hex. cislu.
//**
//** format vstupniho retezce "xx xx xx...xx xx xx" napr. "1C CE 46 F2"
//*****************************************************************************
String HexStringToString(String hs)
{
int count;
int hi,lo,ch;
if (hs.Length()>=2)
if ( (hs.Length()-2)%3==0)
{
count=(hs.Length()-2)/3 + 1;
String s=AnsiString::StringOfChar(' ',count);
for (int i=0; i<count; i++)
{
ch=hs[i*3+1];
if (ch>='0' && ch<='9') hi=ch-'0';
if (ch>='a' && ch<='f') hi=ch-'a'+10;
if (ch>='A' && ch<='F') hi=ch-'A'+10;
ch=hs[i*3+2];
if (ch>='0' && ch<='9') lo=ch-'0';
if (ch>='a' && ch<='f') lo=ch-'a'+10;
if (ch>='A' && ch<='F') lo=ch-'A'+10;
s[i+1]=(hi<<4)+lo;
}
return s;
}
return "";
}
//*****************************************************************************
//** Prevede data ulozena v retezci (po bytech) na retezec s hexadecimalnim
//** vypisem dat
//**
//*****************************************************************************
String StringDataToHex(String frame)
{
String out="";
for (int i=1; i<=frame.Length(); i++) out=out+IntToHex( ((unsigned char)(frame[i])) ,2)+" ";
return out;
}
//*****************************************************************************
// UNSUSED ??
String BuildFrameNoData(int _DA, int _SA, int _FC)
{
String s=AnsiString::StringOfChar(' ',6);
s[1]=DelimiterSD1;
s[2]=_DA;
s[3]=_SA;
s[4]=_FC;
s[5]= (_DA+_SA+_FC)%256 ;
s[6]=DelimiterED;
return s;
}
*/
//*****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -