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


//----------------------------------------------------------------------------- 
// $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; // TODO - je to OK? 
      } 
      //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; 
} 
*/ 
//*****************************************************************************