2014년 5월 12일 월요일

TCP/IP Stack for Embedded MCU (atmega128)


Original Article : http://blog.naver.com/simonsayz/120212895522

 
코드는 제가...
The time to share with the pascal ... :)
CPU : Atmega128 tested
 
//******************************************************************************
//
//  ** **** PPP Driver
//
//  2011.08.08 Rcv오류 수정 (-20 대신 xor 사용)
//
//
//  -------------------------------------------------------------------------
//
//  API
//  -------------------------------------------------------------------------
//
//  1. Function PPP_Open ('s=2')
//  2. Function PPP_Close;
//  3. Function Svr_Open (TCP,80,'
www.maxpaper.com' )
//  4. Function Svr_Close;
//  5. Function Svr_Snd  (
//  6. Function Svr_Rcv  (
//
//
//
//  To Do.
//
//    1. 접속,해제 관련 State 정리
//
//
//
//  중요한 부분
//   1. IPCP 의 경우, Address 0.0.0.0 의 Request에 대하여, Nak을 주면서,
//                    사용자 PC의 IP를 줌
//                    기본적으로는 서버 IP를 되돌려줌.
//
//  To Do
//  -------------------------------------------------------------------------
//
//
//  Ref.
//   #1. Intenet
//      
http://www.apps.ietf.org/rfc/rfc1331.html
//       http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/TCP_IP/IP_Header
//
//   #2. Book
//         PPP Design Implementation and Debugging 2nd Ed
//           p57       A Request ID 1
//                     B Reject  ID 1
//                     A Request ID 2
//                     B Nak     ID 2
//                     A Request ID 3
//                     B Ack     ID 3
//                     B Request ID 1
//                     A Ack     ID 1
//
//
//******************************************************************************

unit PPP_Drv;
interface
Uses
 StdCtrls,SysUtils,Windows,VCL_Uart,Forms;

Const
 _cFCS_Init                 = $ffff; // Initial FCS value
 //
 _cPPPFlag                  =   $7E;
 _cEscape                   =   $7D; // 111:1101 -> 뒷 문자 X - $20
 _cMaxBuf                   =  1600;
 _cMaxOpts                  =     7;
 // RFC 1331
 _cPktLCP                   = $C021;
 _cPktCHAP                  = $C223;
 _cPktIPCP                  = $8021;
 _cPktCTCP                  = $002D;
 _cPktUTCP                  = $002F;
 // LCP,IPCP
 _cConf_Req                 =     1;
 _cConf_Ack                 =     2;
 _cConf_Nak                 =     3;
 _cConf_Rej                 =     4;
 _cTerm_Req                 =     5;
 _cTerm_Ack                 =     6;
 _cCode_Rej                 =     7;
 _cProt_Rej                 =     8;
 _cEcho_Req                 =     9;
 _cEcho_Rep                 =    10;
 _cDisc_Req                 =    11;
 _cReserved                 =    12;
 //
 _cLCP_MRU                  =     1; // Maximum_Receive_Unit
 _cLCP_ACCM                 =     2; // Asynchronous Control Character Map
 _cLCP_Auth                 =     3; // Authentication_Protocol
 _cLCP_Quality              =     4; // Quality_Protocol
 _cLCP_Magic                =     5; // Magic_Number
 _cLCP_PFC                  =     7; // Protocol_Field_Compression
 _cLCP_ACFC                 =     8; // Address_Control_Field_Compression
 _cLCP_MLP                  =    12; // Deprecated (Multi-Link-Procedure)
 _cLCP_CallBack             =    13; // $0D CallBack RFC1570
 //
 _cIPCP_IPComp              =     2; // L:6 IP_Compress_Protocol
 _cIPCP_IPAddr              =     3; // L:6 IP_Address
 _cIPCP_1DNSAddr            =   $81; // L:6 Primary_DNS_Addr
 _cIPCP_1NBNSAddr           =   $82; // L:6 Primary_NBNS_Addr
 _cIPCP_2DNSAddr            =   $83; // L:6 Secondary_DNS_Addr
 _cIPCP_2NBNSAddr           =   $84; // L:6 Secondary_NBNS_Addr
 //
 _cIP_TCP                   =   $06;
 _cIP_UDP                   =   $11;
 //
 _cProto_DNS                =   $35;
 _cProto_Web                =   $50;
 //
 _cURG                      =   $20;
 _cACK                      =   $10;
 _cPSH                      =   $08;
 _cRST                      =   $04;
 _cSYN                      =   $02;
 _cFIN                      =   $01;


Type
 //
 TStepState     = (ns0_Init,       // 초기 상태
                   ns1_LCP_Req,    // 서버 -> PC
                   nsLCP_1Rcv,     // 첫번째 LCP 읽고,
                   nsLCP_1Ack,     // Ack 보내고,
                   nsIPCP_1Req);
 //
 TBuf4          = Packed Array[0.. 3] of Byte;
 TBufTcpIp      = Packed Array[0..39] of Byte; // Header
 TStr           = String[60];
 TFCSWork       = (fwStart,
                   fwWork,
                   fwEnd);
 TCodeState     = (csCmd,
                   csLen,
                   csDat);
 TCRCType       = (ctTCP,
                   ctIP,
                   ctUDP);
 TTcpState      = (tsOpen,       // Flag 2 UAPRSF (Sync)
                   tsWork,       // Flag
                   tsClose);
 //
 TPktType       = (ptNone,
                   ptLCP,        // Frame Packet Type
                   ptCHAP,
                   ptIPCP,
                   ptTCP);
 TPktState      = (psStart,      // Frame State
                   psAddr,
                   psControl,
                   psProtocol,
                   psData,
                   psFCS,
                   psStop);
 TPktData       = Packed Record  // Frame Data
                   Len         : Word;
                   Data        : Array[0.._cMaxBuf-1] of Byte;
                  End;
 //
 TIPCP_Cmd      = (icUnknown,    //
                   icIP_Addr,    // IP Addr
                   icIP_Comp,
                   icIP_DNS1,
                   icIP_DNS2);
 TOpt           = Record
                   Cmd : Byte;
                   Len : Byte;
                   Dat : TBuf4;
                  End;
 TOpts          = Record
                   Cnt : Integer;
                   DB  : Array[0.._cMaxOpts-1] of TOpt;
                  End;
 //
 TState_Frame   = (sfCode,
                   sfID,
                   sfLen,
                   sfData);
 //
 TState_TcpIp   = (stVerLen,     // IP  ------------
                   stTOS,
                   stLen,
                   stID,
                   stFlagIP,
                   stTTL,
                   stProtocol,
                   stChkSumIP,
                   stSrcIP,
                   stDstIP,
                   stSrcPort,    // TCP ------------
                   stDstPort,
                   stSeqNum,
                   stAck,
                   stHLen,
                   stFlagTCP,
                   stWin,
                   stChkSumTCP,
                   stUrgent,
                   stData);      // Data -----------
 //
 TPktFrame      = Record
                   State       : TState_Frame;
                   Code        : Byte;
                   ID          : Byte;
                   Len         : Word;     // Code + ID + Len + Data (ex. Data : 16-> 20)
                   Opts        : TOpts;
                  End;
 TPktTcpIp      = Record
                   State       : TState_TCPIP;
                   // IP ------------------------------------------------------
                   VerLen      : Byte;     //  1 $45            : IPV4 / IHL : 5 x 32b = 20 Bytes
                   TOS         : Byte;     //  2 $00            : Type of Service
                   Length      : Word;     //  4 $00,$2C [44]   : Ver ~ Data (TCP+ Data)
                   ID          : Word;     //  6 $73,$49
                   FlagIP      : Word;     //  7 $40,$00        : 0100:0000
                   TTL         : Byte;     //  9 $40,           :
                   Protocol    : Byte;     // 10 $06,           : TCP , $11 : UDP
                   ChkSumIP    : Word;     // 12 $74,$74
                   SrcIP       : TBuf4;    // 16 $0A,$17,$06,$04
                   DstIP       : TBuf4;    // 20 $7C,$D9,$C6,$1A
                   // TCP -----------------------------------------------------
                   SrcPort     : Word;     //  2 $5C,$7A
                   DstPort     : Word;     //  4 $00,$50
                   SegNum      : TBuf4;    //  8 $B1,$14,$19,$B2
                   Ack         : TBuf4;    // 12 $DE,$AC,$94,$D1
                   HLen        : Byte;     // 13 $60 [0110:0000 ->
                   FlagTCP     : Byte;     // 14 $02  UAPRSF ->Sync
                   Win         : Word;     // 16 $01,$FF
                   ChkSumTCP   : Word;     // 18 $AC,$EB,
                   Urgent      : Word;     // 20 $00,$00
                  End;
 TPktDNS        = Record
                   ID          : Word; //
                   Flags       : Word; // 0100  Recursion Desired
                   QuestionRR  : Word; // 0001 Question 1
                   AnswerRR    : Word; // 0000 Query시 0
                   AuthorityRR : Word; // 0000 Query시 0
                   AdditionRR  : Word; // 0000 Query시 0
                   // Addr     : String[50];
                   QueryType   : Word; // 0001 : IP
                   QueryClass  : Word; // 0001 : Internet
                   Name        : Word; // C00C : Name
                   TypeRR      : Word; // 0001 : Type / A
                   //ClassRR   : Word; // 0001 : Class / In
                   TTL         : TBuf4;// 00000000 :
                   Length      : Word; // 0004 : IP경우 4
                   //IP        : TBuf4;//        IP Address
                  End;
{
         //
         $01,$EF, // 02  ID
         $81,$80, // 04  Flag   1000:0001
         $00,$01, // 06  Question Rec
         $00,$01, // 08  Answer Rec
         $00,$05, // 10  Authority Rec
         $00,$05, // 12  Additonal Rec
         $03,$77,$77,$77,                     // Question www
         $08,$6D,$61,$78,$70,$61,$70,$65,$72, //          maxpaper
         $03,$63,$6F,$6D,$00,                 //           com
         $00,$01,                             // Query    Type
         $00,$01,                             // Query    Class
         $C0,$0C,                             // 06 Name --------------------
         $00,$01,                             // 02 Type A
         $00,$01,                             // 02 Clasee / In
         $00,$00,$12,$C1,                     // 04 TTL
         $00,$04,                             // Length
         $7C,$D9,$C6,$1A,                     // Addr
}                                              // ...

 TEnv           = Record
                   ID          : Byte;
                   MagicCode   : TBuf4;
                   IPServer    : TBuf4;    //
                   IPClient    : TBuf4;    // My IP
                   IPHost      : TBuf4;    // Host IP
                   IPComp      : TBuf4;
                   DNS1        : TBuf4;
                   DNS2        : TBuf4;
                   TCPState    : TTCPState;
                  End;
 TPkt           = Record
                   iEscaped    : Boolean;  // 내부 변수
                   iInx        : Word;     // 내부 변수
                   iBuf        : TBuf4;    //
                   iBufTCP     : TBufTcpIp;// TCP/IP Header
                   iFCS        : Word;     // 계산 FCS
                   rFCS        : Word;     // 실제 FCS
                   iStep       : TStepState;

                   //
                   Env         : TEnv;
                   //
                   Type_       : TPktType;
                   State       : TPktState;
                   // PPP Packet
                   Frame       : TPktFrame;
                   TCPIP       : TPktTcpIp;
                   DNS         : TPktDNS;
                   //
                   Data        : TPktData;
                  End;

Var
 _gPkt  : TPkt;       // 패킷 정보
 //
 _gDbg  : TMemo;      // Debug
 _gDStr : String;     // Debug String
 _gUart : TUart;      // Hw


 // Dev Function
 Procedure hwInit        (Uart  : TUart; Dbg : TMemo);
 Procedure hwSndEsc      (sByte : Byte  ); // PPP Escape
 Procedure hwSnd         (sByte : Byte  ); // PPP Direct
 Procedure hwSndBuf      (sData : Pointer; sSize : Integer);

 // Utility Function
 Procedure Dbg            (dsStr : String);
 Function  B2H            (ub  : Byte ) : String;
 Function  B2Buf4         (uA,uB,uC,uD : Byte ) : TBuf4;
 Function  IsSet          (inB : TBuf4) : Boolean;
 Function  B4ToDW         (Buf : TBuf4 ) : DWord;
 Function  DWToB4         (dB : DWord) : TBuf4;

 //
 Procedure IPCP_Data2Opts (Var Pkt : TPkt);
 Procedure IPCP_Opts2Env  (ForceEdit : Boolean; Var Pkt : TPkt);
 Function  IPCP_OptsExist (Var Pkt : TPkt; Cmd : Byte) : Boolean;
 Function  IPCP_OptsComp  (Var Pkt : TPkt; Cmd : Byte; Buf4 : TBuf4) : Boolean;
 Procedure IPCP_Env2Data  (Var Pkt : TPkt);
 Procedure IPCP_Env2DataReject(Var Pkt : TPkt);
 //
 Function  DNS_Query      (Var Pkt : TPkt; Host : TStr) : Boolean;
 Function  DNS_IpPos      (Const Buf : TPktData) : Word;

 //
 Procedure TCP_Send       (Var Pkt : TPkt);
 Procedure TCP_Open       (Var Pkt : TPkt; Ip : TBuf4; Port : Word;Flag : Byte);
 Procedure TCP_Reply      (Var Pkt : TPkt);
 //
 Procedure ppp_Init       (Var Pkt : TPkt);
 Function  ppp_Receive    (Var Pkt : TPkt; InData : Byte) : Boolean;
 //
 Function  ppp_process    (Var Pkt : TPkt; InData : Byte) : Boolean;
 //
 Procedure Send_IPCP_Req;

Const
 //
 _cLCP_Req  : Packed Array[0..55] of Byte =
               ($7E,                                            // Start
                $FF,                                            //  Address
                $7D,$23,                                        //  Control
                $C0,$21,                                        //  Protocol : LCP
                $7D,$21,                                        //  Code : Request
                $7D,$21,                                        //  ID   : 1
                $7D,$20,$7D,$38,                                //  Len  : 18
                $7D,$21,$7D,$24,$7D,$25,$AC,                    //   MRU   01 04 05 AC
                $7D,$22,$7D,$26,$7D,$20,$7D,$20,$7D,$20,$7D,$20,//   ACCM  02 06 00 00 00 00
                $7D,$25,$7D,$26,$7D,$26,$7D,$29,$7D,$22,$7D,$20,//   Magic 05 06 06 09 02 00
                $7D,$27,$7D,$22,                                //   PFC   02 02 (C0 21)
                $7D,$28,$7D,$22,                                //   ACFC  08 02 (FF 03)
                $67,$61,                                        // FCS : Field Check Sequence
                $7E);                                           // End

  _cChap_Res : Packed Array [0..47] of Byte =
               ($7e,
                $c2,$23,                         // CHAP
                $02,                             // Response
                $01,                             // ID
                $00,$2a,                         // (02) Len (42)
                $10,                             // (01) Value-Size (16)
                $95,$38,$af,$c3,$e0,$e0,$7a,$8c, // (16) Option
                $8d,$94,$8e,$43,$ed,$bd,$fd,$3a,
                $30,$31,$30,$35,$37,$34,$30,$31, // (21)
01057401886@lgt.co.kr
                $38,$38,$36,$40,$6c,$67,$74,$2e,
                $63,$6f,$2e,$6b,$72,
                $72,$b6,                         // (02) CRC
                $7e);

 _cIPCP_Req : Packed Array[0..39] of Byte =
               ($7E,                                            // Start
                $FF,                                            //  Address
                $7D,$23,                                        //  Control
                $80,$21,                                        //  Protocol : IPCP
                $7D,$21,                                        //  Code     : Req
                $7D,$30,                                        //  ID       : 10
                $7D,$20,$7D,$30,                                //  Len      : 18 ( Code ~ Data )
                $7D,$22,$7D,$26,$7D,$20,$2D,$7D,$2F,$7D,$21,    //  IP Compress Protocol
                $7D,$23,$7D,$26,$7D,$20,$7D,$20,$7D,$20,$7D,$20,//  IP Addr
                $E3,$73,                                        // FCS
                $7E);                                           // End

 _cIPCP_Req2: Packed Array[0..28] of Byte =
               ($7E,                                            // Start
                $FF,                                            //  Address
                $7D,$23,                                        //  Control
                $80,$21,                                        //  Protocol : IPCP
                $7D,$21,                                        //  Code     : Req
                $7D,$30,                                        //  ID       : 10
                $7D,$20,$7D,$2A,                                //  Len      : 10 ( Code ~ Data )
                $7D,$23,$7D,$26,$7D,$20,$7D,$20,$7D,$20,$7D,$20,//  IP Addr
                $7A,$9A,                                        // FCS
                $7E);                                           // End

implementation
Uses
 PPP_Help;

Const
 _cFCSTbl  : Array[0..255] of Word =
                               ($0000,$1189,$2312,$329b,$4624,$57ad,$6536,$74bf,
                                $8c48,$9dc1,$af5a,$bed3,$ca6c,$dbe5,$e97e,$f8f7,
                                $1081,$0108,$3393,$221a,$56a5,$472c,$75b7,$643e,
                                $9cc9,$8d40,$bfdb,$ae52,$daed,$cb64,$f9ff,$e876,
                                $2102,$308b,$0210,$1399,$6726,$76af,$4434,$55bd,
                                $ad4a,$bcc3,$8e58,$9fd1,$eb6e,$fae7,$c87c,$d9f5,
                                $3183,$200a,$1291,$0318,$77a7,$662e,$54b5,$453c,
                                $bdcb,$ac42,$9ed9,$8f50,$fbef,$ea66,$d8fd,$c974,
                                $4204,$538d,$6116,$709f,$0420,$15a9,$2732,$36bb,
                                $ce4c,$dfc5,$ed5e,$fcd7,$8868,$99e1,$ab7a,$baf3,
                                $5285,$430c,$7197,$601e,$14a1,$0528,$37b3,$263a,
                                $decd,$cf44,$fddf,$ec56,$98e9,$8960,$bbfb,$aa72,
                                $6306,$728f,$4014,$519d,$2522,$34ab,$0630,$17b9,
                                $ef4e,$fec7,$cc5c,$ddd5,$a96a,$b8e3,$8a78,$9bf1,
                                $7387,$620e,$5095,$411c,$35a3,$242a,$16b1,$0738,
                                $ffcf,$ee46,$dcdd,$cd54,$b9eb,$a862,$9af9,$8b70,
                                $8408,$9581,$a71a,$b693,$c22c,$d3a5,$e13e,$f0b7,
                                $0840,$19c9,$2b52,$3adb,$4e64,$5fed,$6d76,$7cff,
                                $9489,$8500,$b79b,$a612,$d2ad,$c324,$f1bf,$e036,
                                $18c1,$0948,$3bd3,$2a5a,$5ee5,$4f6c,$7df7,$6c7e,
                                $a50a,$b483,$8618,$9791,$e32e,$f2a7,$c03c,$d1b5,
                                $2942,$38cb,$0a50,$1bd9,$6f66,$7eef,$4c74,$5dfd,
                                $b58b,$a402,$9699,$8710,$f3af,$e226,$d0bd,$c134,
                                $39c3,$284a,$1ad1,$0b58,$7fe7,$6e6e,$5cf5,$4d7c,
                                $c60c,$d785,$e51e,$f497,$8028,$91a1,$a33a,$b2b3,
                                $4a44,$5bcd,$6956,$78df,$0c60,$1de9,$2f72,$3efb,
                                $d68d,$c704,$f59f,$e416,$90a9,$8120,$b3bb,$a232,
                                $5ac5,$4b4c,$79d7,$685e,$1ce1,$0d68,$3ff3,$2e7a,
                                $e70e,$f687,$c41c,$d595,$a12a,$b0a3,$8238,$93b1,
                                $6b46,$7acf,$4854,$59dd,$2d62,$3ceb,$0e70,$1ff9,
                                $f78f,$e606,$d49d,$c514,$b1ab,$a022,$92b9,$8330,
                                $7bc7,$6a4e,$58d5,$495c,$3de3,$2c6a,$1ef1,$0f78);

//*****************************************************************************
//
//  HardWare Driver Function
//  -------------------------------------------------------------------------
//  추후 HW 환경에 맞도록 Layer 분리
//
//
//*****************************************************************************

// Dev Function
Procedure hwInit  (Uart  : TUart; Dbg : TMemo);
 begin
  //
  _gUart := Uart;
  _gDbg  := Dbg;
  _gDStr := '';
 end;

// PPP Escape
Procedure hwSndEsc(sByte : Byte);
 begin
  Case (sByte in [$0..$20,$7d,$7e]) of
   True  : Begin
            _gUart.SendByte($7D          );
            _gUart.SendByte(sByte xor $20);
            _gDStr := _gDStr + B2H($7D)+',$' + B2H(sByte xor $20) + ',$';
           End;
   False : Begin
            _gUart.SendByte(sByte);
            _gDStr := _gDStr + B2H(sByte) + ',$';
           End;
  End;
 end;

// PPP Direct
Procedure hwSnd   (sByte : Byte);
 begin
  _gUart.SendByte(sByte);
  _gDStr := _gDStr + B2H(sByte) + ',$';
 end;

//
Procedure hwSndBuf      (sData : Pointer; sSize : Integer);
 begin
  _gUart.SendData(sData,sSize);
 end;

//*****************************************************************************
//
//  Utility Function
//  -------------------------------------------------------------------------
//
//
//*****************************************************************************

//
Procedure Dbg(dsStr : String);
 begin
  _gDbg.Lines.Add(dsStr);
 end;

//
Function  B2H (ub : Byte) : String;
 begin
  Result := IntToHex(ub,2);
 end;

//
Function  W2H (uW : Word) : String;
 begin
  Result := IntToHex(uW,4);
 end;

//
Function IsSet(inB : TBuf4) : Boolean;
 begin
  Result := (inB[0] + inB[1] + inB[2] + inB[3]) > 0;
 end;

//
Function B4ToDW(Buf : TBuf4 ) : DWord;
 begin
  Result := (Buf[0] shl 24) or
            (Buf[1] shl 16) or
            (Buf[2] shl  8) or
            (Buf[3] shl  0);
 end;

//
Function DWToB4(dB : DWord) : TBuf4;
 begin
  Result[0] := (db shr 24) and $FF;
  Result[1] := (db shr 16) and $FF;
  Result[2] := (db shr  8) and $FF;
  Result[3] := (db shr  0) and $FF;
 end;

//
Function  B2Buf4(uA,uB,uC,uD : Byte ) : TBuf4;
 begin
  Result[0] := uA;
  Result[1] := uB;
  Result[2] := uC;
  Result[3] := uD;
 end;

// FCS [Protocol ~ Data]
Procedure hwSndCRC(fcIn : Byte; Work  : TFCSWork; Var FCS : Word);
 Begin
  //
  Case fcIn of
   _cPPPFlag : begin
                hwSnd($7D);
                hwSnd(fcIn xor $20);
               end;
   else        hwSnd(fcIn);
  End;
  //
  Case Work of
   fwStart,
   fwWork   : begin
               If Work = fwStart then FCS := _cFCS_Init;
               FCS := (FCS shr 8) xor _cFCSTbl[(FCS xor fcIn) and $FF];
              end;
   fwEnd    :  FCS := Swap((FCS xor $FFFF));
  End;
 End;

// FCS [Protocol ~ Data]
Procedure CRC_PPP(Work  : TFCSWork; fcIn : Byte; Var FCS : Word);
 Begin
  //
  Case Work of
   fwStart,
   fwWork   : begin
               If Work = fwStart then FCS := _cFCS_Init;
               FCS := (FCS shr 8) xor _cFCSTbl[(FCS xor fcIn) and $FF];
              end;
   fwEnd    :  FCS := Swap((FCS xor $FFFF));
  End;
 End;


// Data : IP 첫번쨰 위치
// IpCSum := CRC_IP(@_cExIP);
Function CRC_IP  (data:pointer):word;
var
 pw   : Pword;
 x    : word;
 csum : longint;

Begin
 csum := 0;
 //
 pw := data;
 For x := 1 to 10 do
  Begin
   csum := csum + pw^;
   inc(pw);
  end;
 //
 csum   := (csum and $ffff) + (csum shr 16);
 csum   := csum + (csum shr 16);
 csum   := (csum and $00ff) shl 8 + (csum shr 8);
 Result := csum xor $FFFF;
end;

// Pseudo IP Sum
Function CRC_PseudoIP_Sum(pIP : Pointer) : LongInt;
 Var
  pw  : PWord;
  X   : Byte;
 Begin
  // 초기화
  Result := 0;
  // IP Sum
  pw := pIP;
  For x := 1 to 6 do
   Begin
    Result := Result + pw^;
    inc(pw);
   End;
 End;

// TCP :  CRC_TcpUdp(cSum, Pkt, 20);
// UDP :  CRC_TcpUdp(cSum, Pkt,  8);
Function CRC_TcpUdpCalc(cSum    : LongInt;
                        Var Pkt : TPkt; HdrLen : Integer) : Word;
var
 pw    : Pword;
 x     : word;
Begin
 // Step #01. Header (IP+TCP,IP+UDP) ------------------------------------------
 pw := @Pkt.iBufTCP;
 For x := 1 to (HdrLen shr 1) do
  Begin
   csum := csum + pw^;
   inc(pw);
  End;
 // Step #02. Data  -----------------------------------------------------------
 pw := @Pkt.Data.Data;
 For x := 1 to (Pkt.Data.Len shr 1) do
  Begin
   csum := csum + pw^;
   inc(pw);
  End;

 If (Pkt.Data.Len mod 2=1) then
  Begin
   X    := PByte(pw)^;
   csum := csum + X;
  end;

 csum   := (csum and $ffff) + (csum shr 16);
 csum   := csum + (csum shr 16);
 csum   := (csum and $00ff) shl 8 + (csum shr 8);
 Result := csum xor $FFFF;
end;

// 전제 조건 : TCPIP ,Data.Len 값이 정확해야 함
Function CRC_TcpUdp(Var Pkt : TPkt; CrcType : TCRCType) : Word;
 var
  IpSum : LongInt;
 begin
  //
  Case CrcType of
   ctIP  : begin
            // IP
            Pkt.iBufTCP[ 0] :=     Pkt.TCPIP.VerLen;
            Pkt.iBufTCP[ 1] :=     Pkt.TCPIP.TOS;
            Pkt.iBufTCP[ 2] :=  Hi(Pkt.TCPIP.Length);
            Pkt.iBufTCP[ 3] :=  Lo(Pkt.TCPIP.Length);
            Pkt.iBufTCP[ 4] :=  Hi(Pkt.TCPIP.ID    );
            Pkt.iBufTCP[ 5] :=  Lo(Pkt.TCPIP.ID    );
            Pkt.iBufTCP[ 6] :=  Hi(Pkt.TCPIP.FlagIP);
            Pkt.iBufTCP[ 7] :=  Lo(Pkt.TCPIP.FlagIP);
            Pkt.iBufTCP[ 8] :=     Pkt.TCPIP.TTL;
            Pkt.iBufTCP[ 9] :=     Pkt.TCPIP.Protocol;
            Pkt.iBufTCP[10] :=  0; // ChkSumIP
            Pkt.iBufTCP[11] :=  0; // ChkSumIP
            Pkt.iBufTCP[12] :=     Pkt.TCPIP.SrcIP[0];
            Pkt.iBufTCP[13] :=     Pkt.TCPIP.SrcIP[1];
            Pkt.iBufTCP[14] :=     Pkt.TCPIP.SrcIP[2];
            Pkt.iBufTCP[15] :=     Pkt.TCPIP.SrcIP[3];
            Pkt.iBufTCP[16] :=     Pkt.TCPIP.DstIP[0];
            Pkt.iBufTCP[17] :=     Pkt.TCPIP.DstIP[1];
            Pkt.iBufTCP[18] :=     Pkt.TCPIP.DstIP[2];
            Pkt.iBufTCP[19] :=     Pkt.TCPIP.DstIP[3];
            //
            Result  := CRC_IP  (@Pkt.iBufTCP);
           end;
   ctTCP,
   ctUDP : begin
            // Calc Pseudo Sum
            Pkt.iBufTCP[ 0] :=     Pkt.TCPIP.SrcIP[0];
            Pkt.iBufTCP[ 1] :=     Pkt.TCPIP.SrcIP[1];
            Pkt.iBufTCP[ 2] :=     Pkt.TCPIP.SrcIP[2];
            Pkt.iBufTCP[ 3] :=     Pkt.TCPIP.SrcIP[3];
            Pkt.iBufTCP[ 4] :=     Pkt.TCPIP.DstIP[0];
            Pkt.iBufTCP[ 5] :=     Pkt.TCPIP.DstIP[1];
            Pkt.iBufTCP[ 6] :=     Pkt.TCPIP.DstIP[2];
            Pkt.iBufTCP[ 7] :=     Pkt.TCPIP.DstIP[3];
            Pkt.iBufTCP[ 8] :=     0; // Pad
            Pkt.iBufTCP[ 9] :=     Pkt.TCPIP.Protocol;
            // TCP
            Case CrcType of
             ctTCP : begin
                      Pkt.iBufTCP[10] :=  Hi(20 + Pkt.Data.Len); // TCP + Data Length
                      Pkt.iBufTCP[11] :=  Lo(20 + Pkt.Data.Len); // TCP + Data Length
                      IpSum   := CRC_PseudoIP_Sum(@Pkt.iBufTCP);
                      //
                      Pkt.iBufTCP[ 0] :=  Hi(Pkt.TCPIP.SrcPort);
                      Pkt.iBufTCP[ 1] :=  Lo(Pkt.TCPIP.SrcPort);
                      Pkt.iBufTCP[ 2] :=  Hi(Pkt.TCPIP.DstPort);
                      Pkt.iBufTCP[ 3] :=  Lo(Pkt.TCPIP.DstPort);
                      Pkt.iBufTCP[ 4] :=     Pkt.TCPIP.SegNum[0];
                      Pkt.iBufTCP[ 5] :=     Pkt.TCPIP.SegNum[1];
                      Pkt.iBufTCP[ 6] :=     Pkt.TCPIP.SegNum[2];
                      Pkt.iBufTCP[ 7] :=     Pkt.TCPIP.SegNum[3];
                      Pkt.iBufTCP[ 8] :=     Pkt.TCPIP.Ack   [0];
                      Pkt.iBufTCP[ 9] :=     Pkt.TCPIP.Ack   [1];
                      Pkt.iBufTCP[10] :=     Pkt.TCPIP.Ack   [2];
                      Pkt.iBufTCP[11] :=     Pkt.TCPIP.Ack   [3];
                      Pkt.iBufTCP[12] :=     Pkt.TCPIP.HLen;
                      Pkt.iBufTCP[13] :=     Pkt.TCPIP.FlagTCP;
                      Pkt.iBufTCP[14] :=  Hi(Pkt.TCPIP.Win    );
                      Pkt.iBufTCP[15] :=  Lo(Pkt.TCPIP.Win    );
                      Pkt.iBufTCP[16] :=  0; // TCP Check Sum
                      Pkt.iBufTCP[17] :=  0;
                      Pkt.iBufTCP[18] :=  Hi(Pkt.TCPIP.Urgent );
                      Pkt.iBufTCP[19] :=  Lo(Pkt.TCPIP.Urgent );
                      Result := CRC_TcpUdpCalc(IpSum,Pkt,20);
                     end;
             ctUDP : begin
                      Pkt.iBufTCP[10] :=  Hi(8 + Pkt.Data.Len); // TCP + Data Length
                      Pkt.iBufTCP[11] :=  Lo(8 + Pkt.Data.Len); // TCP + Data Length
                      IpSum   := CRC_PseudoIP_Sum(@Pkt.iBufTCP);
                      //
                      Pkt.iBufTCP[ 0] :=  Hi(Pkt.TCPIP.SrcPort);
                      Pkt.iBufTCP[ 1] :=  Lo(Pkt.TCPIP.SrcPort);
                      Pkt.iBufTCP[ 2] :=  Hi(Pkt.TCPIP.DstPort);
                      Pkt.iBufTCP[ 3] :=  Lo(Pkt.TCPIP.DstPort);
                      Pkt.iBufTCP[ 4] :=  Hi(Pkt.TCPIP.Win    );
                      Pkt.iBufTCP[ 5] :=  Lo(Pkt.TCPIP.Win    );
                      Pkt.iBufTCP[ 6] :=  0; // UDP Check Sum
                      Pkt.iBufTCP[ 7] :=  0;
                      Result := CRC_TcpUdpCalc(IpSum,Pkt,8);
                     end;
            End;
            //
           end;
  End;
 end;

// Raw 데이터를 Pkt.Frame.Opts에...
// Pkt.Data -> Pkt.Frame.Opts
Procedure IPCP_Data2Opts(Var Pkt : TPkt);
 Var
  Lp     : Integer;
  CState : TCodeState;
  Dat    : Byte;
  Inx    : Integer;
 begin
  // 초기화
  cState             := csCmd;
  Inx                := 0;
  Pkt.Frame.Opts.Cnt := 0;
  //
  For Lp := 0 to Pkt.Data.Len-1 do
   begin
    Dat := Pkt.Data.Data[Lp];
    //
    Case cState of
     csCmd : Begin
              cState := csLen;
              Pkt.Frame.Opts.DB[Pkt.Frame.Opts.Cnt].Cmd := Dat;
             End;
     csLen : Begin
              cState := csDat;
              Pkt.Frame.Opts.DB[Pkt.Frame.Opts.Cnt].Len := Dat;
              Inx    := 0;
              Case Pkt.Frame.Opts.DB[Pkt.Frame.Opts.Cnt].Len <= 2 of
               True  : Begin
                        cState := csCmd;
                        Inc(Pkt.Frame.Opts.Cnt);
                       End;
               False :  cState := csDat;
              End;
             End;
     csDat : Begin
              //
              Pkt.Frame.Opts.DB[Pkt.Frame.Opts.Cnt].Dat[Inx] := Dat;
              Inc(Inx);
              //
              If Inx >= Pkt.Frame.Opts.DB[Pkt.Frame.Opts.Cnt].Len-2 then
               Begin
                cState := csCmd;
                Inc(Pkt.Frame.Opts.Cnt);
               End;
             End;
    End;
   end;
 end;

// Opts값 -> Env변수 Update
Procedure IPCP_Opts2Env (ForceEdit  : Boolean; Var Pkt : TPkt);
 Var
  Lp : Integer;
 begin
  For Lp := 0 to Pkt.Frame.Opts.Cnt-1 do
   Case Pkt.Frame.Opts.DB[Lp].Cmd of
    _cIPCP_IPComp    : If (ForceEdit)or(Not(IsSet(Pkt.Env.IPComp))) then
                        Pkt.Env.IPComp := Pkt.Frame.Opts.DB[Lp].Dat;
    _cIPCP_IPAddr    : Case ForceEdit of
                        True : Pkt.Env.IPClient := Pkt.Frame.Opts.DB[Lp].Dat;
                        False: Pkt.Env.IPServer := Pkt.Frame.Opts.DB[Lp].Dat;
                       End;
    _cIPCP_1DNSAddr  : If (ForceEdit)or(Not(IsSet(Pkt.Env.DNS1  ))) then
                        Pkt.Env.DNS1   := Pkt.Frame.Opts.DB[Lp].Dat;
    _cIPCP_2DNSAddr  : If (ForceEdit)or(Not(IsSet(Pkt.Env.DNS2  ))) then
                        Pkt.Env.DNS2   := Pkt.Frame.Opts.DB[Lp].Dat;
    _cIPCP_1NBNSAddr : ;
    _cIPCP_2NBNSAddr : ;
   end;
 end;

//
Function  IPCP_OptsExist(Var Pkt : TPkt; Cmd : Byte) : Boolean;
 Var
  Lp : Integer;
 begin
  // 초기화
  Result := False;
  //
  For Lp := 0 to Pkt.Frame.Opts.Cnt-1 do
   If Pkt.Frame.Opts.DB[Lp].Cmd = Cmd then
    begin
     Result := True;
     Exit;
    end;
 end;

//
Function  IPCP_OptsComp (Var Pkt : TPkt; Cmd : Byte; Buf4 : TBuf4) : Boolean;
 Var
  Lp : Integer;
  Lp2: Integer;
 begin
  // 초기화
  Result := False;
  //
  For Lp := 0 to Pkt.Frame.Opts.Cnt-1 do
   If Pkt.Frame.Opts.DB[Lp].Cmd = Cmd then
    begin
     For Lp2 := 0 to 3 do
      If Buf4[Lp2] <> Pkt.Frame.Opts.DB[Lp].Dat[Lp2] then
       Exit;
     //
     Result := True;
     Exit;
    end;
 end;

// Env 변수 -> Pkt.Data로 이전
Procedure IPCP_Env2Data (Var Pkt : TPkt);
 Var
  Ofs : Integer;
 begin
  //
  Ofs := 0;
  Pkt.Data.Data[Ofs+0] := _cIPCP_IPAddr;
  Pkt.Data.Data[Ofs+1] := 6;
  Move(Pkt.Env.IpServer,Pkt.Data.Data[Ofs+2],4);
  //
  Inc(Ofs,6);
  Pkt.Data.Len := Ofs;
 end;

//
Procedure IPCP_Env2DataReject(Var Pkt : TPkt);
 Var
  Ofs : Integer;
 begin
  //
  Ofs := 0;
  //
  Pkt.Data.Data[Ofs+0] := _cIPCP_IPComp;
  Pkt.Data.Data[Ofs+1] := 6;
  Move(Pkt.Env.IpComp,Pkt.Data.Data[Ofs+2],4);
  //
  Inc(Ofs,6);
  Pkt.Data.Data[Ofs+0] := _cIPCP_1DNSAddr;
  Pkt.Data.Data[Ofs+1] := 6;
  Move(Pkt.Env.DNS1,Pkt.Data.Data[Ofs+2],4);
  //
  Inc(Ofs,6);
  Pkt.Data.Data[Ofs+0] := _cIPCP_2DNSAddr;
  Pkt.Data.Data[Ofs+1] := 6;
  Move(Pkt.Env.DNS2,Pkt.Data.Data[Ofs+2],4);
  //
  Inc(Ofs,6);
  Pkt.Data.Len := Ofs;
 end;

//
Procedure Reply_LCP(Var Step : TStepState; Var Pkt : TPkt);
 Var
  FCS : Word;
  Lp  : Integer;
 begin
  _gDStr := '';
  hwSnd   (_cPPPFlag); // 7E
  hwSndEsc($FF   );  CRC_PPP(fwStart,$FF,FCS); // Protocol
  hwSndEsc($03   );  CRC_PPP(fwWork ,$03,FCS);
  hwSndEsc($C0   );  CRC_PPP(fwWork ,$C0,FCS);
  hwSndEsc($21   );  CRC_PPP(fwWork ,$21,FCS);
  Case Pkt.Frame.Code of  // Code
   _cConf_Req : begin
                 Pkt.Frame.Code := _cConf_Ack;
                 hwSndEsc  (Pkt.Frame.Code);
                 CRC_PPP(fwWork,Pkt.Frame.Code,FCS);
                end;
  End;
  hwSndEsc     (Pkt.Frame.ID);      CRC_PPP(fwWork ,Pkt.Frame.ID     ,FCS);
  hwSndEsc     (Hi(Pkt.Frame.Len)); CRC_PPP(fwWork ,Hi(Pkt.Frame.Len),FCS);
  hwSndEsc     (Lo(Pkt.Frame.Len)); CRC_PPP(fwWork ,Lo(Pkt.Frame.Len),FCS);
  // Cmd:Len:Data ...
  For Lp := 0 to Pkt.Data.Len-1 do
   Begin
    hwSndEsc   (Pkt.Data.Data[Lp]);
    CRC_PPP(fwWork ,Pkt.Data.Data[Lp],FCS);
   End;

  CRC_PPP(fwEnd ,0,FCS);
  // FCS
  hwSndEsc(Hi(FCS)  );
  hwSndEsc(Lo(FCS)  );
  hwSnd   (_cPPPFlag);
  // Help...
  // Dbg('Snd:'+_gDStr);
  Help_LCP('Snd:',Pkt );
 end;

//
Procedure Reply_IPCP(Var Step : TStepState; Var Pkt : TPkt);
 Var
  FCS : Word;
  Lp  : Integer;
 begin
  // Raw Data 값을 Opts Record로 이동후, 환경 변수에 저장
  IPCP_Data2Opts(Pkt);
  Case Pkt.Frame.Code of
   _cConf_Req  : IPCP_Opts2Env(False,Pkt);
   _cConf_Nak  : IPCP_Opts2Env(True ,Pkt);
   _cConf_Ack  : Exit;
  End;
  // Help_Env (Pkt);

  _gDStr := '';
  hwSnd   (_cPPPFlag); // 7E
  hwSndEsc($FF      );  CRC_PPP(fwStart,$FF,FCS); // Protocol
  hwSndEsc($03      );  CRC_PPP(fwWork ,$03,FCS);
  hwSndEsc($80      );  CRC_PPP(fwWork ,$80,FCS);
  hwSndEsc($21      );  CRC_PPP(fwWork ,$21,FCS);
  Case Pkt.Frame.Code of  // Code
   _cConf_Req : Begin
                 Dbg('IPCP : Req->Req');
                 If IPCP_OptsExist(Pkt,_cIPCP_1DNSAddr) or
                    IPCP_OptsExist(Pkt,_cIPCP_2DNSAddr) then
                  Begin
                   IPCP_Env2DataReject(Pkt);
                   Pkt.Frame.Len  := Pkt.Data.Len + 4;
                   Pkt.Frame.Code := _cConf_Rej;
                  End
                 else
                  Pkt.Frame.Code := _cConf_Ack;
                 //
                 hwSndEsc  (Pkt.Frame.Code);
                 CRC_PPP(fwWork,Pkt.Frame.Code,FCS);
                End;
   _cConf_Nak : Begin
                 Dbg('IPCP : Nak->Req');
                 Pkt.Frame.Code := _cConf_Req;
                 Inc(Pkt.Env.ID);
                 Pkt.Frame.ID := Pkt.Env.ID;
                 hwSndEsc(Pkt.Frame.Code);
                 CRC_PPP (fwWork,Pkt.Frame.Code,FCS);
                End;
   _cConf_Ack : Begin
                 Pkt.Frame.Code := _cConf_Req;
                 Inc(Pkt.Env.ID);
                 Pkt.Frame.ID := Pkt.Env.ID;

                 hwSndEsc(Pkt.Frame.Code);
                 CRC_PPP (fwWork,Pkt.Frame.Code,FCS);
                end;
  End;
  //
  hwSndEsc     (Pkt.Frame.ID);      CRC_PPP(fwWork ,Pkt.Frame.ID     ,FCS);
  hwSndEsc     (Hi(Pkt.Frame.Len)); CRC_PPP(fwWork ,Hi(Pkt.Frame.Len),FCS);
  hwSndEsc     (Lo(Pkt.Frame.Len)); CRC_PPP(fwWork ,Lo(Pkt.Frame.Len),FCS);
  // Cmd:Len:Data ...
  For Lp := 0 to Pkt.Data.Len-1 do
   Begin
    hwSndEsc   (Pkt.Data.Data[Lp]);
    CRC_PPP(fwWork ,Pkt.Data.Data[Lp],FCS);
   End;

  CRC_PPP(fwEnd ,0,FCS);
  // FCS
  hwSndEsc(Hi(FCS)  );
  hwSndEsc(Lo(FCS)  );
  hwSnd   (_cPPPFlag);
  // Help...
  // Dbg('Snd:'+_gDStr);
  Help_LCP('Snd:', Pkt );
 end;

// Pkt.iFCS : Loop
// Pkt.iInx : 갯수
// Pkt.iBuf : '.' 위치
// 중요한점은 7E는 반드시, Escape 시켜야 함
Function  DNS_Query      (Var Pkt : TPkt; Host : TStr) : Boolean;
 Var
  Lp  : Integer;
  FCS : Word;
 begin
  //
  _gDStr := '';
  Result := False;
  If Host = '' then Exit;
  // DNS 관련 -------------------- 12 + 4 +
  Pkt.DNS.ID            := $01EF;
  Pkt.DNS.Flags         := $0100;
  Pkt.DNS.QuestionRR    := $0001;
  Pkt.DNS.AnswerRR      := $0000;
  Pkt.DNS.AuthorityRR   := $0000;
  Pkt.DNS.AdditionRR    := $0000;
  Pkt.DNS.QueryType     := $0001;
  Pkt.DNS.QueryClass    := $0001;

  // UDP DNS 데이터 설정
  Pkt.Data.Len := 0;
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.ID         ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.ID         ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.Flags      ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.Flags      ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.QuestionRR ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.QuestionRR ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.AnswerRR   ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.AnswerRR   ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.AuthorityRR); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.AuthorityRR); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.AdditionRR ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.AdditionRR ); Inc(Pkt.Data.Len);
  // DNS Name 설정 (
www.maxpaper.com )
  Pkt.iInx := Pkt.Data.Len;
  Pkt.iFCS := 0;
  For Lp := 1 to Length(Host) do
   Case host[Lp] = '.' of
    False : Begin
             Pkt.Data.Data[Pkt.Data.Len+Lp] := Ord(Host[Lp]);
             Inc(Pkt.iFCS);
            End;
    True  : Begin
             Pkt.Data.Data[Pkt.iInx] := Pkt.iFCS;
             Pkt.iInx := Pkt.Data.Len+Lp;
             Pkt.iFCS :=  0;
            End;
   End;
  //
  Pkt.Data.Data[Pkt.iInx] := Pkt.iFCS;  Inc(Pkt.Data.Len,Length(host)+1);
  Pkt.Data.Data[Pkt.Data.Len] := $00;    ;  Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.QueryType  ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.QueryType  ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Hi(Pkt.DNS.QueryClass ); Inc(Pkt.Data.Len);
  Pkt.Data.Data[Pkt.Data.Len] := Lo(Pkt.DNS.QueryClass ); Inc(Pkt.Data.Len);

  // IP 관련
  Pkt.TCPIP.VerLen      := $45;
  Pkt.TCPIP.TOS         := $00;
  Pkt.TCPIP.Length      := 20 + (8 + Pkt.Data.Len); // 62 ( 20 + 8 + 34 )
  Pkt.TCPIP.ID          := $1BA3;
  Pkt.TCPIP.FlagIP      := $0000;
  Pkt.TCPIP.TTL         := $80;
  Pkt.TCPIP.Protocol    := _cIP_UDP;
  Pkt.TCPIP.SrcIp       := Pkt.Env.IPClient; // B2Buf4($0A,$17,$06,$04);
  Pkt.TCPIP.DstIP       := Pkt.Env.DNS1;     // B2Buf4($96,$02,$7E,$66);
  // UDP 관련
  Pkt.TCPIP.SrcPort     := $04EC; // DE6;
  Pkt.TCPIP.DstPort     := $0035; // 53
  Pkt.TCPIP.Win         := 8 + Pkt.Data.Len; // 8 + Data[34]

  // Send ----
  Pkt.TCPIP.ChkSumIP  := CRC_TCPUDP(Pkt,ctIP );
  Pkt.TCPIP.ChkSumTCP := CRC_TCPUDP(Pkt,ctUDP);
  //
  hwSnd (_cPPPFlag); // 7E
  // hwSndEsc(rU,Snd);
  hwSndCRC($FF,fwStart,FCS); // Protocol
  hwSndCRC($03,fwWork ,FCS); // Control
  hwSndCRC($00,fwWork ,FCS); // TCP/IP
  hwSndCRC($21,fwWork ,FCS); //
  // IP -----------------------------------------------------------------------
  hwSndCRC($45                    ,fwWork,FCS); // VerLen
  hwSndCRC($00                    ,fwWork,FCS); // TOS
  hwSndCRC(Hi(Pkt.TCPIP.Length)   ,fwWork,FCS); // Len ( IP + TCP + Data.Len )
  hwSndCRC(Lo(Pkt.TCPIP.Length)   ,fwWork,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.ID    )   ,fwWork,FCS); // ID
  hwSndCRC(Lo(Pkt.TCPIP.ID    )   ,fwWork,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.FlagIP)   ,fwWork,FCS); // FlagIP (3:13)
  hwSndCRC(Lo(Pkt.TCPIP.FlagIP)   ,fwWork,FCS); //
  hwSndCRC(   Pkt.TCPIP.TTL       ,fwWork,FCS); // TTL
  hwSndCRC(   Pkt.TCPIP.Protocol  ,fwWork,FCS); // Protocol
  hwSndCRC(Hi(Pkt.TCPIP.ChkSumIP) ,fwWork,FCS); // IP Check Sum
  hwSndCRC(Lo(Pkt.TCPIP.ChkSumIP) ,fwWork,FCS); // IP Check Sum
  hwSndCRC(   Pkt.TCPIP.SrcIP[0]  ,fwWork,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.SrcIP[1]  ,fwWork,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.SrcIP[2]  ,fwWork,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.SrcIP[3]  ,fwWork,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[0]  ,fwWork,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[1]  ,fwWork,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[2]  ,fwWork,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[3]  ,fwWork,FCS); // SrcIP
  // UDP ----------------------------------------------------------------------
  hwSndCRC(Hi(Pkt.TCPIP.SrcPort  ),fwWork,FCS); // Src Port
  hwSndCRC(Lo(Pkt.TCPIP.SrcPort  ),fwWork,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.DstPort  ),fwWork,FCS); // Dst Port
  hwSndCRC(Lo(Pkt.TCPIP.DstPort  ),fwWork,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.Win      ),fwWork,FCS); // UDP Len
  hwSndCRC(Lo(Pkt.TCPIP.Win      ),fwWork,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.ChkSumTCP),fwWork,FCS); // ChkSum
  hwSndCRC(Lo(Pkt.TCPIP.ChkSumTCP),fwWork,FCS); //
  // TCP Data
  If Pkt.Data.Len > 0 then
   For Lp := 0 to Pkt.Data.Len-1 do
    hwSndCRC(Pkt.Data.Data[Lp],fwWork,FCS);
  //
  CRC_PPP(fwEnd ,0,FCS);
  // FCS
  hwSnd(Hi(FCS)  );
  hwSnd(Lo(FCS)  );
  hwSnd(_cPPPFlag);
  // Help...
  // Dbg('Snd:'+_gDStr);
  Help_TCP('Snd:',Pkt);
 end;

//
Function  DNS_IpPos (Const Buf : TPktData) : Word;
 Var
  Lp    : Integer;
  Cnt   : Integer;
  Inx   : integer;
  DType : Word;
  DLen  : Word;

begin
 //
 Result := 0;
 If Buf.Len <= 12 then Exit;
 If Not( ( (Buf.Data[2] and $80) = $80 ) and        // Answer
         ( (Buf.Data[5] and $01) = $01 ) and        // Question
         (  Buf.Data[7]          > $01 ) ) then
  Exit;
 //
 Cnt := Buf.Data[7];
 Inx := 0;
 For Lp := 12 to Buf.Len-1 do
  If Buf.Data[Lp] = 0 then
   begin
    Inx := Lp + 5 ; // Name Position
    Break;
   end;
 //
 For Lp := 1 to Cnt do
  begin
   Case Buf.Data[Inx] = $C0 of
    True : Begin // Compress
            Inc(Inx,2);
            Move(Buf.Data[Inx],DType,2); // Read Type
           End;
    False: For DType := Inx to Buf.Len-1 do
            If Buf.Data[DType] = 0 then
             begin
              Inx := DType+1;
              Move(Buf.Data[Inx],DType,2); // Read Type
              Break;
             end;
   End;
   DType := Swap(DType);
   //
   Case DType <> 1 of
    True : begin
            Inc(Inx,8); // Class,TLL,Data
            Move(Buf.Data[Inx],DLen,2); // Read Data Len
            DLen := Swap(DLen);
            Inc(Inx,2+DLen);            // Len + Data
           end;
    False: begin
            Inc(Inx,8); // Class,TLL,Data
            Move(Buf.Data[Inx],DLen,2);
            DLen := Swap(DLen);
            Case DLen of
             4 : begin
                  Inc(Inx,2);
                  Result := Inx;
                  Exit;
                 end;
             else Inc(Inx,2+DLen);      // Len + Data
            End;
           end;
   End;
  end;
end;

//
Procedure TCP_Send       (Var Pkt : TPkt);
 Var
  FCS : Word;
  Lp  : Word;
 begin
  //
  hwSnd (_cPPPFlag); // 7E
  hwSndCRC($FF                    ,fwStart,FCS); // Protocol
  hwSndCRC($03                    ,fwWork ,FCS); // Control
  hwSndCRC($00                    ,fwWork ,FCS); // TCP/IP
  hwSndCRC($21                    ,fwWork ,FCS); //
  // IP ------------------------------------------------------------
  hwSndCRC($45                    ,fwWork ,FCS); // VerLen
  hwSndCRC($00                    ,fwWork ,FCS); // TOS
  hwSndCRC(Hi(Pkt.TCPIP.Length   ),fwWork ,FCS); // Len ( IP + TCP + Data.Len )
  hwSndCRC(Lo(Pkt.TCPIP.Length   ),fwWork ,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.ID       ),fwWork ,FCS); // ID
  hwSndCRC(Lo(Pkt.TCPIP.ID       ),fwWork ,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.FlagIP   ),fwWork ,FCS); // FlagIP (3:13)
  hwSndCRC(Lo(Pkt.TCPIP.FlagIP   ),fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.TTL       ,fwWork ,FCS); // TTL
  hwSndCRC(   Pkt.TCPIP.Protocol  ,fwWork ,FCS); // Protocol
  hwSndCRC(Hi(Pkt.TCPIP.ChkSumIP ),fwWork ,FCS); // IP Check Sum
  hwSndCRC(Lo(Pkt.TCPIP.ChkSumIP ),fwWork ,FCS); // IP Check Sum
  hwSndCRC(   Pkt.TCPIP.SrcIP[0]  ,fwWork ,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.SrcIP[1]  ,fwWork ,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.SrcIP[2]  ,fwWork ,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.SrcIP[3]  ,fwWork ,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[0]  ,fwWork ,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[1]  ,fwWork ,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[2]  ,fwWork ,FCS); // SrcIP
  hwSndCRC(   Pkt.TCPIP.DstIP[3]  ,fwWork ,FCS); // SrcIP
  // TCP --------------------------------------------------------
  hwSndCRC(Hi(Pkt.TCPIP.SrcPort)  ,fwWork ,FCS); // Src Port
  hwSndCRC(Lo(Pkt.TCPIP.SrcPort)  ,fwWork ,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.DstPort)  ,fwWork ,FCS); // Dst Port
  hwSndCRC(Lo(Pkt.TCPIP.DstPort)  ,fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.SegNum[0] ,fwWork ,FCS); // Seg Num.
  hwSndCRC(   Pkt.TCPIP.SegNum[1] ,fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.SegNum[2] ,fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.SegNum[3] ,fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.Ack   [0] ,fwWork ,FCS); // Ack
  hwSndCRC(   Pkt.TCPIP.Ack   [1] ,fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.Ack   [2] ,fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.Ack   [3] ,fwWork ,FCS); //
  hwSndCRC(   Pkt.TCPIP.HLen      ,fwWork ,FCS); // Header Len (4*X)
  hwSndCRC(   Pkt.TCPIP.FlagTCP   ,fwWork ,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.Win      ),fwWork ,FCS); // Win
  hwSndCRC(Lo(Pkt.TCPIP.Win      ),fwWork ,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.ChkSumTCP),fwWork ,FCS); // TCP Check Sum
  hwSndCRC(Lo(Pkt.TCPIP.ChkSumTCP),fwWork ,FCS); //
  hwSndCRC(Hi(Pkt.TCPIP.Urgent   ),fwWork ,FCS); // Urgent
  hwSndCRC(Lo(Pkt.TCPIP.Urgent   ),fwWork ,FCS); //
  // TCP Data
  If Pkt.Data.Len > 0 then
   For Lp := 0 to Pkt.Data.Len-1 do
    hwSndCRC(Pkt.Data.Data[Lp],fwWork,FCS);
  //
  CRC_PPP(fwEnd ,0,FCS);
  // FCS
  hwSnd(Hi(FCS)  );
  hwSnd(Lo(FCS)  );
  hwSnd(_cPPPFlag);
  // Help...
  // Dbg('Snd:'+_gDStr);
  Help_TCP('Snd:',Pkt);
 end;

//
Procedure TCP_Open (Var Pkt : TPkt; Ip : TBuf4; Port : Word; Flag : Byte);
 Var
  Sav4 : TBuf4;
  Len  : Word;
 begin
  //
  Pkt.Env.TCPState   := tsOpen;
  // IP 설정 ------------------------------------------------------------------
  Pkt.TCPIP.VerLen   := $45;
  Pkt.TCPIP.TOS      := $00;
  Pkt.TCPIP.Length   := $2C;
  Pkt.TCPIP.ID       := $4040; // 3D31;
  Pkt.TCPIP.FlagIP   := $4000;
  Pkt.TCPIP.TTL      := $40;
  Pkt.TCPIP.Protocol := _cIP_TCP;
  Pkt.TCPIP.SrcIp    := Pkt.Env.IPClient; // B2Buf4($0A,$17,$06,$04); //
  Pkt.TCPIP.DstIP    := IP;               // B2Buf4($76,$21,$72,$E8);
  // TCP 설정 -----------------------------------------------------------------
  Pkt.TCPIP.SrcPort  := $764A;
  Pkt.TCPIP.DstPort  := Port;
  Case (Flag and _cSyn) = _cSyn of
   True : begin
           Pkt.TCPIP.SegNum   := B2Buf4($00,$42,$24,$5C);
           Pkt.TCPIP.Ack      := B2Buf4($00,$00,$00,$00);
          end;
   False: begin
           Sav4               := Pkt.TCPIP.SegNum;     // Ack,Seq Swap
           Pkt.TCPIP.SegNum   := Pkt.TCPIP.Ack;
           Pkt.TCPIP.Ack      := Sav4;
           //
           Len := Pkt.TCPIP.HLen shr 4;
            Case Len > 5 of
             True  : Len := (Len-5)*4;
             False : Len := 0;
            End;
           Pkt.TCPIP.Ack := DWToB4(B4ToDW(Pkt.TCPIP.ACk)+
                                  Pkt.Data.Len - Len);
          

          end;
  End;
  Pkt.TCPIP.FlagTCP  := Flag;
  Pkt.TCPIP.Win      := $01FF; // Buffer 사이즈
  Pkt.TCPIP.Urgent   := $0000;
  //         ------------------------------------------------------------------
  Case (Flag and _cSyn) = _cSyn of
   True : begin
           Pkt.TCPIP.HLen     := $60;
           Pkt.Data.Len       := 4;
           Pkt.Data.Data[0]   := $02;
           Pkt.Data.Data[1]   := $04;
           Pkt.Data.Data[2]   := $00;
           Pkt.Data.Data[3]   := $D2;
          end;
   False: begin
           Pkt.TCPIP.HLen     := $50;
           Pkt.Data.Len       := 0;
          end;
  End;
  // Check Sum ----------------------------------------------------------------
  Pkt.TCPIP.ChkSumIP  := CRC_TCPUDP(Pkt,ctIP );
  Pkt.TCPIP.ChkSumTCP := CRC_TCPUDP(Pkt,ctTCP);
  //
  TCP_Send(Pkt);
 end;

//
Procedure TCP_Reply(Var Pkt : TPkt);
 Var
  Lp    : Byte;
  Sav4  : TBuf4;
  Sav2  : Word;
  Len   : Integer;
 begin
  _gDStr := '';
  //
  If Pkt.TCPIP.Protocol = _cIP_UDP then
   begin
    Dbg('### Rcv UDP , Pass... ###');
    Exit;
   end;
  // ---------------------------------------------------------------
  Case Pkt.Env.TCPState of
   tsOpen : Begin
             // IP 관련 설정 ---------------------------------------------------
             Pkt.TCPIP.ID       := $3D32;
             Pkt.TCPIP.FlagIP   := $4000;
             Pkt.TCPIP.TTL      := $40;
             Pkt.TCPIP.Protocol := _cIP_TCP;
             Sav4               := Pkt.TCPIP.SrcIP;   // IP Swap
             Pkt.TCPIP.SrcIp    := Pkt.TCPIP.DstIP;
             Pkt.TCPIP.DstIP    := Sav4;
             // TCP 관련 설정 --------------------------------------------------
             Sav2               := Pkt.TCPIP.SrcPort; // Port Swap
             Pkt.TCPIP.SrcPort  := Pkt.TCPIP.DstPort;
             Pkt.TCPIP.DstPort  := Sav2;
             Sav4               := Pkt.TCPIP.SegNum;     // Ack,Seq Swap
             Pkt.TCPIP.SegNum   := Pkt.TCPIP.Ack;
             Pkt.TCPIP.Ack      := Sav4;

             Pkt.TCPIP.HLen     := $50;
             Pkt.TCPIP.Win      := $01FF; // Buffer 사이즈
             //
             Pkt.Data.Len       := 0;
             Pkt.TCPIP.Length   := 20 + 20 + Pkt.Data.Len;
             //
             Case (Pkt.TCPIP.FlagTCP and _cSyn) = _cSyn of
              True : Begin
                      Pkt.TCPIP.Ack := DWToB4(B4ToDW(Pkt.TCPIP.Ack)+1);
                      Pkt.Env.TCPState  := tsWork;
                      Pkt.TcpIp.FlagTCP := _cAck;
                      Dbg('### TCP/IP : Open / ');
                     End;
              False: Begin
                      Dbg('### TCP/IP : Open / Exit #### 문제 발생 #### ');
                      Pkt.TCPIP.Ack := DWToB4(B4ToDW(Pkt.TCPIP.Ack)+1);
                      Pkt.Env.TCPState  := tsWork;
                      Pkt.TcpIp.FlagTCP := _cAck;
                     End;
             End;
            End;
   tsWork : Begin
             Exit;
             Len := Pkt.TCPIP.HLen shr 4;
             Case Len > 5 of
              True  : Len := (Len-5)*4;
              False : Len := 0;
             End;
             Pkt.TCPIP.Ack := DWToB4(B4ToDW(Pkt.TCPIP.ACk)+
                                     Pkt.Data.Len - Len);
             Pkt.TcpIp.FlagTCP := _cAck;
             Dbg('### TCP/IP : Work ' +
                 IntToStr(Pkt.Data.Len));
             //
             Pkt.Data.Len       := 0;
             Pkt.TCPIP.Length   := 20 + 20 + Pkt.Data.Len;
            End;
  End;
  //
  Pkt.TCPIP.ChkSumIP  := CRC_TCPUDP(Pkt,ctIP );
  Pkt.TCPIP.ChkSumTCP := CRC_TCPUDP(Pkt,ctTCP);
  //
  TCP_Send(Pkt);
 end;

//
Procedure ppp_Init   (Var Pkt    : TPkt);
 begin
  Pkt.iEscaped    := False;
  Pkt.iInx        := 0;
  //FillChar(Pkt.Env,SizeOf(Pkt.Env),#0);
  Pkt.State       := psStart;
  Pkt.Frame.State := sfCode;
  Pkt.TcpIp.State := stVerLen;
  //
  Pkt.Type_       := ptLCP;
 end;

//
Procedure Frame_Receive (Var Pkt : TPkt;InData : Byte);
 begin
  //
  Case Pkt.Frame.State of
   sfCode : Begin
             Pkt.Frame.Code  := InData;
             Pkt.Frame.State := sfID;
            End;
   sfID   : Begin
             Pkt.Frame.ID    := InData;
             Pkt.Frame.State := sfLen;
             Pkt.iInx        := 0;
            End;
   sfLen  : Begin
             Case Pkt.iInx of
              0 : Pkt.Frame.Len := InData;
              1 : Pkt.Frame.Len := (Pkt.Frame.Len shl 8) or InData;
             End;
             Inc(Pkt.iInx);
             If Pkt.iInx >= 2 then
              begin
               Pkt.Frame.State := sfData;
               Pkt.Data.Len    := 0;
              end;
            End;
   sfData : Begin
             Pkt.Data.Data[Pkt.Data.Len] := InData;
             Inc(Pkt.Data.Len);
             // 4 = Code[1] + ID[1] + Len[2]
             If Pkt.Data.Len >= (Pkt.Frame.Len - 4)  then
              begin
               Pkt.State := psFCS;
               Pkt.iInx  := 0;
              end;
            End;
  End;
 end;

Function Hdr_Len(Protocol : Byte ) : Byte;
 begin
  //
  Result := 40;
  If Protocol = _cIP_UDP then
   Result := 28;
 end;

//
Procedure TCP_Receive(Var Pkt : TPkt;InData : Byte);
 Var
  ChkSum : Word;
 begin
  //
  Case Pkt.TcpIp.State of
                // IP -----------------------------------------------------
   stVerLen   : Begin
                 Pkt.TcpIp.VerLen := InData;
                 Pkt.TcpIp.State  := stTOS;
                End;
   stTOS      : Begin
                 Pkt.TcpIp.TOS    := InData;
                 Pkt.TcpIp.State  := stLen;
                 Pkt.iInx      := 0;
                End;
   stLen      : Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.Length := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.Length := (Pkt.TcpIp.Length shl 8) or InData;
                      Pkt.TcpIp.State  := stID;
                      Pkt.iInx      := 0;
                     End;
                End;
   stID       : Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.ID      := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.ID     := (Pkt.TcpIp.ID shl 8) or InData;
                      Pkt.TcpIp.State  := stFlagIP;
                      Pkt.iInx      := 0;
                     End;
                End;
   stFlagIP   : Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.FlagIP := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.FlagIP := (Pkt.TcpIp.FlagIP shl 8) or InData;
                      Pkt.TcpIp.State  := stTTL;
                      Pkt.iInx      := 0;
                     End;
                End;
   stTTL      : Begin
                 Pkt.TcpIp.TTL      := InData;
                 Pkt.TcpIp.State    := stProtocol;
                End;
   stProtocol : Begin
                 Pkt.TcpIp.Protocol := InData;
                 Pkt.TcpIp.State    := stChkSumIP;
                 Pkt.iInx        := 0;
                End;
   stChkSumIP : Case Pkt.iInx of
                 0 : begin
                      Pkt.TcpIp.ChkSumIP := InData;
                      Inc(Pkt.iInx);
                     end;
                 1 : begin
                      Pkt.TcpIp.ChkSumIP := (Pkt.TcpIp.ChkSumIP shl 8) or InData;
                      Pkt.TcpIp.State    := stSrcIP;
                      Pkt.iInx           := 0;
                     end;
                End;
   stSrcIP    : Begin
                 Pkt.TcpIp.SrcIP[Pkt.iInx] := InData;
                 Inc(Pkt.iInx);
                 If Pkt.iInx >= 4 then
                  begin
                   Pkt.TcpIp.State := stDstIP;
                   Pkt.iInx     := 0;
                  end;
                End;
   stDstIP    : Begin
                 Pkt.TcpIp.DstIP[Pkt.iInx] := InData;
                 Inc(Pkt.iInx);
                 If Pkt.iInx >= 4 then
                  begin
                   Pkt.TcpIp.State := stSrcPort;
                   Pkt.iInx     := 0;
                  end;
                End;
                // TCP ---------------------------------------------------------
   stSrcPort  : Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.SrcPort := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.SrcPort := (Pkt.TcpIp.SrcPort shl 8) or InData;
                      Pkt.TcpIp.State   := stDstPort;
                      Pkt.iInx          := 0;
                     End;
                End;
   stDstPort  : Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.DstPort := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.DstPort := (Pkt.TcpIp.DstPort shl 8) or InData;
                      Pkt.iInx          := 0;
                      //
                      Case Pkt.TcpIp.Protocol of
                       _cIP_TCP : Pkt.TcpIp.State := stSeqNum;
                       _cIP_UDP : Pkt.TcpIp.State := stWin;
                      End;
                     End;
                End;
   stSeqNum   : Begin
                 Pkt.TcpIp.SegNum[Pkt.iInx] := InData;
                 Inc(Pkt.iInx);
                 If Pkt.iInx >= 4 then
                  begin
                   Pkt.TcpIp.State := stAck;
                   Pkt.iInx     := 0;
                  end;
                End;
   stAck      : Begin
                 Pkt.TcpIp.Ack[Pkt.iInx] := InData;
                 Inc(Pkt.iInx);
                 If Pkt.iInx >= 4 then
                  begin
                   Pkt.TcpIp.State := stHLen;
                   Pkt.iInx     := 0;
                  end;
                End;
   stHLen     : Begin
                 Pkt.TcpIp.HLen    := InData;
                 Pkt.TcpIp.State   := stFlagTCP;
                End;
   stFlagTCP  : Begin
                 Pkt.TcpIp.FlagTCP := InData;
                 Pkt.TcpIp.State   := stWin;
                 Pkt.iInx          := 0;
                End;
   stWin      : Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.Win := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.Win := (Pkt.TcpIp.Win shl 8) or InData;
                      Pkt.TcpIp.State   := stChkSumTCP;
                      Pkt.iInx          := 0;
                     End;
                End;
   stChkSumTCP: Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.ChkSumTCP := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.ChkSumTCP := (Pkt.TcpIp.ChkSumTCP shl 8) or InData;
                      Pkt.iInx          := 0;
                      Pkt.Data.Len      := 0;
                      //
                      Case Pkt.TcpIp.Protocol of
                       _cIP_TCP : Pkt.TcpIp.State := stUrgent;
                       _cIP_UDP : Pkt.TcpIp.State := stData;
                      End;
                     End;
                End;
   stUrgent   : Case Pkt.iInx of
                 0 : Begin
                      Pkt.TcpIp.Urgent  := InData;
                      Inc(Pkt.iInx);
                     End;
                 1 : Begin
                      Pkt.TcpIp.Urgent  := (Pkt.TcpIp.Urgent shl 8) or InData;
                      Pkt.TcpIp.State   := stData;
                      Pkt.iInx          := 0;
                      Pkt.Data.Len      := 0;
                      If Pkt.TcpIp.Length = Hdr_Len(Pkt.TcpIp.Protocol) then
                       begin
                        Pkt.State := psFCS;
                        Pkt.iInx  := 0;
                       end;
                     End;
                End;
   stData     : Begin
                 Pkt.Data.Data[Pkt.Data.Len] := InData;
                 Inc(Pkt.Data.Len);
                 If Pkt.Data.Len >= (Pkt.TCPIP.Length - Hdr_Len(Pkt.TcpIp.Protocol)) then
                  begin
                   Pkt.State := psFCS;
                   Pkt.iInx  := 0;
                   //
                   ChkSum := CRC_TcpUDP(Pkt,ctIP);
                   If Pkt.TCPIP.ChkSumIP <> ChkSum then
                    Dbg('#### Err IP CRC : Pkt:' + W2H(Pkt.TCPIP.ChkSumIP) +
                                        '/Calc:' + W2H(ChkSum));
                   //
                   Case Pkt.TCPIP.Protocol of
                    _cIP_TCP : ChkSum := CRC_TcpUDP(Pkt,ctTCP);
                    _cIP_UDP : ChkSum := CRC_TcpUDP(Pkt,ctUDP);
                   End;
                   If Pkt.TCPIP.ChkSumTCP <> ChkSum then
                    Dbg('#### Err TCP/UDP CRC : Pkt:' + W2H(Pkt.TCPIP.ChkSumTCP) +
                                             '/Calc:' + W2H(ChkSum));
                  end;
                End;
  End;
 end;

//
Function  ppp_Receive(Var Pkt : TPkt; InData : Byte) : Boolean;
 begin
  //
  Result := False;
  // Process Escape Sequence --------------------------------------------------
  If InData = _cEscape then begin
                             Pkt.iEscaped := True;
                             Exit;
                            end;
  If Pkt.iEscaped      then begin
                             InData := InData xor $20;
                             Pkt.iEscaped := False;
                            end;
  // State --------------------------------------------------------------------
  Case Pkt.State of
   psStart   : If InData = _cPPPFlag then
                begin
                 ppp_Init(_gPkt);
                 Pkt.State := psAddr;
                end;
   psAddr    : // $7E $FF $03 $C0 $21 : LCP
               // $7E         $80 $21 : IPCP
               // $7E             $21 : TCP,IP
               // $7E $FF $03 $00 $2F : Uncomp TCP/IP
               // $7E             $2F : Uncomp TCP/IP
               // $7E $FF $03 $00 $2D : Comp   TCP/IP
               // $7E             $2D : Comp   TCP/IP
               Case InData of
                $21,  // UnCompressed
                $2F,  // UnCompressed
                $2D : // Compressed
                      begin
                       Pkt.Type_ := ptTCP;
                       Pkt.State := psData;
                       CRC_PPP(fwStart,InData,Pkt.iFCS);
                      end;
                $7E : ;
                $80 : begin
                       Pkt.iInx           := 0;
                       Pkt.iBuf[Pkt.iInx] := InData;
                       Inc(Pkt.iInx);
                       Pkt.State          := psProtocol;
                       CRC_PPP(fwStart,InData,Pkt.iFCS);
                      end;
                $FF : begin
                       Pkt.Type_ := ptNone;
                       Pkt.State := psControl;
                       CRC_PPP(fwStart,InData,Pkt.iFCS);
                      end
                else  Pkt.State := psStart;
               End;
   psControl : Begin
                Pkt.State := psProtocol;
                Pkt.iInx  := 0;
                CRC_PPP(fwWork,InData,Pkt.iFCS);
               End;
   psProtocol: Begin
                Pkt.iBuf[Pkt.iInx] := InData;
                //
                CRC_PPP(fwWork ,InData,Pkt.iFCS);
                //
                Inc(Pkt.iInx);
                If Pkt.iInx >= 2 then
                 Begin
                  //
                  Case (Pkt.iBuf[0] shl 8) or
                       (Pkt.iBuf[1]      ) of
                   _cPktLCP  : Pkt.Type_ := ptLCP;   // LCP
                   _cPktCHAP : Pkt.Type_ := ptChap;  // Chap
                   _cPktIPCP : Pkt.Type_ := ptIPCP;  // IPCP
                   $0021,      // UnComp
                   $002F,      // UnComp
                   _cPktCTCP : // Comp
                               Pkt.Type_ := ptTCP;   // TCP,UDP
                   else        Pkt.State := psStart;
                  end;
                  //
                  If Pkt.State <> psStart then
                   Pkt.State := psData;
                 End;
               End;
   psData    : // 타입별로 Parsing
               Begin
                Case Pkt.Type_ of
                 ptLCP,
                 ptChap,
                 ptIPCP : Frame_Receive(Pkt,InData);
                 ptTCP  : TCP_Receive  (Pkt,InData);
                 else     Pkt.State := psStart;
                End;
                CRC_PPP(fwWork,InData,Pkt.iFCS);
               End;
   psFCS     : Begin
                Pkt.iBuf[Pkt.iInx] := InData;
                Inc(Pkt.iInx);
                If Pkt.iInx >= 2 then
                 begin
                  CRC_PPP(fwEnd,InData,Pkt.iFCS);
                  Pkt.rFCS := (Pkt.iBuf[0] shl 8) or
                              (Pkt.iBuf[1]      );
                  Pkt.State := psStop;
                  If Pkt.iFCS <> Pkt.rFCS then
                   Dbg('#### Err FCS : Pkt:'+W2H(Pkt.iFCS)+
                                    '/Calc:'+W2H(Pkt.rFCS));
                 end;
               End;
   psStop    : //
               Begin
                Pkt.State       := psStart;
                If InData = _cPPPFlag then
                 Result := True;
               End;
  End;
 end;

Function ppp_process    (Var Pkt : TPkt; InData : Byte) : Boolean;
 Var
  Lp : Integer;
 begin
  Result := PPP_Receive(Pkt,InData);
  If Result then
   Begin
    // 받은 패킷 보여주고...
    Help_Pkt('Rcv:',_gPkt);
    //
    Case _gPkt.Type_ of
     ptLCP  : Case _gPkt.Frame.Code of
               _cConf_Req : begin
                             Case Pkt.iStep of
                              ns0_Init : begin
                                          Dbg('Snd  LCP Request / 신규 채널 ##');
                                          hwSndBuf(@_cLCP_Req,SizeOf(_cLCP_Req));
                                         end;
                             End;
                             // 처음 패킷 응답
                             Reply_LCP(Pkt.iStep,_gPkt);
                             Pkt.iStep := ns1_LCP_Req;
                            end;
               _cConf_Ack : Begin
                             Dbg('####### Chap Send XXXXXXXXX');
                             hwSndBuf(@_cChap_Res,SizeOf(_cChap_Res));
                             //For Lp := 0 to 10 do
                             // begin
                             //  Sleep(20);
                             //  Application.ProcessMessages;
                             // end;
                             //Dbg('####### LCP 종료/ IPCP Request 보냄 #1  ###');
                             //hwSndBuf(@_cIPCP_Req,SizeOf(_cIPCP_Req));
                            End;
              End;
     ptChap : Case _gPkt.Frame.Code of
               _cConf_Req : Dbg('Rcv Chap Req ');
               _cConf_Ack : Dbg('Rcv Chap Ack ');
              End;
     ptIPCP : Reply_IPCP(Pkt.iStep,_gPkt);
     ptTCP  : TCP_Reply (_gPkt);
    End;
   End;
 end;

Procedure Send_IPCP_Req;
 begin
  Dbg('####### 수동  IPCP Request 보냄 #1  ###');
  hwSndBuf(      @_cIPCP_Req2,
           SizeOf(_cIPCP_Req2));
 end;

Initialization
  FillChar(_gPkt.Env,SizeOf(_gPkt.Env),#0);
  ppp_Init(_gPkt);
end.
 

2010년 3월 17일 수요일

maxpaper scrapbook software

maxpaper scrapbook software

온라인 인화사이트인 맥스페이퍼 ( http://www.maxpaper.com )에서 공개한증명사진및 압축앨범 편집 소프트웨어인 맥스페이퍼(Maxpaper)의 개발 일기입니다.2007년부터 2010년까지 지난 4년간의 개발 일정을 중간 정리합니다.

- 편집프로그램은 맥스페이퍼(www.maxpaper.com) 에서 다운가능합니다.



2010년 2월 21일 일요일

Maxpaper for Multi touch based on win7





윈도우7의 멀티터치 기능을 활용한 앨범 편집

한손으로 iphone들고 찍으니, 눈의 초점이 어긋나서 제대로 안됨.
쪼그만 삼각대라고 하나 사던지....
멀티터치 제스추어의 가능성을 보여주는 시연으로 ...

- UI 튜닝이 필요한 베타 단계


// ----------------------------------------------------------------------------
//
// Multi touch Implementation
//
// 크레딕스 최원식 (simonsayz@naver.com)
// - www.kredix.com
// - www.maxpaper.com
//
// History ------------------------------------------------------------------
// 2010.02.18 : 개발 시작 ( Based on Delphi7 ) ver 0.1
// 2010.02.18 : Rotate 버그 있음 (WM_touch에서도 동일하게 발생)
// (삼성 매직스테이션 DM-U200 문제로 판단됨)
// ----------------------------------------------------------------------------

Unit VCl_ObjViewer_Base_Touch;

Interface

Uses
Windows,Types,SysUtils;

Const
WM_GESTURENOTIFY = $011A;
WM_GESTURE = $0119;
WM_TOUCH = $0240;
//
WM_TABLET_DEFBASE = $02C0;
WM_TABLET_FLICK = WM_TABLET_DEFBASE + 11;
TOUCHEVENTF_UP = $0004;
//
TWF_FINETOUCH = $00000001;
TWF_WANTPALM = $00000002;

Type
HGESTUREINFO = type LongInt;// LongWord

HTouchInput = THandle;
UInt = DWord;
ULONGLONG = Int64;
ULONG_PTR = LongWord;
//
TGestureType = (gtNone,
gtBegin,
gtEnd,
gtZoom,
gtPan,
gtRotate,
gtTwoFingerTap,
gtPressAndTap);
TGestureState = (gsNone,
gsBegin,
gsWork,
gsEnd);
TGesture = Record
Type_ : TGestureType; // Gesture 형태
State : TGestureState; // Gesture 상태
XY : TPoint; // 위치
Value : Single; // 각도,확대
End;

// For window ----------------------------------------------------------------
TGestureNotifyStruct = Record
cbSize : UINT; // size, in bytes, of this structure
dwFlags : DWORD; // unused
hwndTarget : HWND; // handle to window targeted by the gesture
ptsLocation : TSmallPoint; // starting location
dwInstanceID : DWORD; // internally used
end;
PGestureNotifyStruct = ^TGestureNotifyStruct;
TWMGestureNotify = Packed record
Msg : Cardinal;
Unused : WPARAM;
NotifyStruct : PGestureNotifyStruct;
Result : Integer;
end;
TTouchInput = Record
x : Integer;
y : Integer;
hSource : THandle;
dwID : DWORD;
dwFlags : DWORD;
dwMask : DWORD;
dwTime : DWORD;
dwExtraInfo : ULONG_PTR;
cxContact : DWORD;
cyContact : DWORD;
End;
PTouchInput = ^TTouchInput;

// For Internal Operation & Dbg ----------------------------------------------
TGestureSet = (gsZoom,
gsZoomRotate,
gsAll);
TGestureSav = Record
Cnt : Integer;
State : TGestureState;
ullArguments : ULongLong;
//
ZoomPtPrev : TPoint;
ZoomFac : Single;
//
AngleSnap : Integer; // 화면 Snap Angle 임시저장
AnglePrev : Single; // Touch에서 받은 Angle
//
DbgAngle : Single;
DbgAngleSum : Single;
End;

Var
GestureSav : TGestureSav;

//
Function Gesture_Set (gsHandle : THandle;gsSet : TGestureSet) : Boolean;
Function Gesture_Get (_wParam : wParam; _lParam :lParam) : TGesture;
Function Gesture_Str (Gstr : TGesture) : String;
//
Function RegisterTouchWindow ( Handle : HWND;
ulFlags : Cardinal ): BOOL;
Function UnRegisterTouchWindow( Handle : HWND ): BOOL;
//
Function CloseTouchInputHandle( hTouchInput_ : HTOUCHINPUT ): BOOL;
Function GetTouchInputInfo ( hTouchInput : HTOUCHINPUT;
cInputs : UINT;
pInputs : PTOUCHINPUT;
cbSize : Integer ): BOOL;

Implementation

// http://wiki.helpmvp.com/home/notes/touch
Const
//
GF_Begin = $00000001;
GF_Inertia = $00000002;
GF_End = $00000004;
//
GC_ALLGESTURES = $00000001;
GC_ZOOM = $00000001;
GC_PAN = $00000001;
GC_PAN_WITH_SINGLE_FINGER_VERTICALLY = $00000002;
GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY = $00000004;
GC_PAN_WITH_GUTTER = $00000008;
GC_PAN_WITH_INERTIA = $00000010;
GC_ROTATE = $00000001;
GC_TWOFINGERTAP = $00000001;
GC_PRESSANDTAP = $00000001;
GC_ROLLOVER = GC_PRESSANDTAP;
//
GID_BEGIN = 1; // a generic gesture is beginning.
GID_END = 2; // a generic gesture end.
GID_ZOOM = 3; // zoom start, zoom move, or zoom stop.
GID_PAN = 4; // pan move or pan start.
GID_ROTATE = 5; // rotate move or rotate start.
GID_TWOFINGERTAP = 6; // two-finger tap gesture.
GID_PRESSANDTAP = 7; //
GID_RollOver = GID_PressAndTap;

Type
//
TGestureConfig = Record
dwID : DWORD; // gesture ID
dwWant : DWORD; // settings related to gesture ID that are to be turned on
dwBlock : DWORD; // settings related to gesture ID that are to be turned off
end;
PGestureConfig = ^TGestureConfig;
TConfigs = Array of TGestureConfig;
//
TGestureInfo = Record
cbSize : Longword;
dwFlags : DWord;
dwID : DWord;
hwndTarget : Hwnd;
ptsLocation : TSmallPoint;
dwInstanceID : DWord;
dwSequenceID : DWord;
ullArguments : ULongLong;
cbExtraArgs : UInt;
end;
PGestureInfo = ^TGestureInfo;

Var
_User32Handle : THandle;
_GetGestureInfo : Function ( hGestureInfo : HGESTUREINFO;
Var pGestureInfo : TGestureInfo): BOOL; stdcall;
_CloseGestureInfoHandle : Function ( hGestureInfo : HGESTUREINFO): BOOL; stdcall;
_SetGestureConfig : Function ( hwnd : HWND;
dwReserved : DWORD;
cIDs : UINT;
pGestureConfig: PGESTURECONFIG;
cbSize : UINT ): BOOL; stdcall;
_RegisterTouchWindow : Function ( hwnd : HWND;
ulFlags : Cardinal ): BOOL; stdcall;
_UnRegisterTouchWindow : Function ( hwnd : HWND ): BOOL; stdcall;
_CloseTouchInputHandle : Function ( hTouchInput_ : HTOUCHINPUT ): BOOL; stdcall;
_GetTouchInputInfo : Function ( hTouchInput : HTOUCHINPUT;
cInputs : UINT;
pInputs : PTOUCHINPUT;
cbSize : Integer ): BOOL; stdcall;
//
_GestureSav : TGestureSav;

//
Function GetGestureInfo ( hGestureInfo : HGESTUREINFO;
Var pGestureInfo : TGestureInfo): BOOL;
begin
Case Assigned(_GetGestureInfo) of
True : Result := _GetGestureInfo(hGestureInfo,pGestureInfo);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_GetGestureInfo := GetProcAddress(_User32Handle, 'GetGestureInfo');
If Assigned(_GetGestureInfo) then
Result := _GetGestureInfo(hGestureInfo,pGestureInfo);
end;
end;
end;
end;

//
Function CloseGestureInfoHandle (hGestureInfo: HGESTUREINFO): BOOL;
begin
Case Assigned(_CloseGestureInfoHandle) of
True : Result := _CloseGestureInfoHandle(hGestureInfo);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_CloseGestureInfoHandle := GetProcAddress(_User32Handle, 'CloseGestureInfoHandle');
If Assigned(_CloseGestureInfoHandle) then
Result := _CloseGestureInfoHandle(hGestureInfo);
end;
end;
end;
end;

//
Function SetGestureConfig ( hwnd : HWND;
dwReserved : DWORD;
cIDs : UINT;
pGestureConfig: PGESTURECONFIG;
cbSize : UINT ): BOOL;
begin
Case Assigned(_SetGestureConfig) of
True : Result := _SetGestureConfig(hwnd,dwReserved,cIDs,pGestureConfig,cbSize);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_SetGestureConfig := GetProcAddress(_User32Handle, 'SetGestureConfig');
If Assigned(_SetGestureConfig) then
Result := _SetGestureConfig(hwnd,dwReserved,cIDs,pGestureConfig,cbSize);
end;
end;
end;
end;

//
Function RegisterTouchWindow ( Handle : HWND;
ulFlags : Cardinal ): BOOL;
begin
Case Assigned(_RegisterTouchWindow) of
True : Result := _RegisterTouchWindow(Handle,ulFlags);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_RegisterTouchWindow := GetProcAddress(_User32Handle, 'RegisterTouchWindow');
If Assigned(_RegisterTouchWindow) then
Result := _RegisterTouchWindow(Handle,ulFlags);
end;
end;
end;
end;

//
Function UnRegisterTouchWindow ( Handle : HWND ): BOOL;
begin
Case Assigned(_UnRegisterTouchWindow) of
True : Result := _UnRegisterTouchWindow(Handle);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_UnRegisterTouchWindow := GetProcAddress(_User32Handle, 'UnregisterTouchWindow');
If Assigned(_UnRegisterTouchWindow) then
Result := _UnRegisterTouchWindow(Handle);
end;
end;
end;
end;

//
Function CloseTouchInputHandle ( hTouchInput_ : HTOUCHINPUT ): BOOL;
begin
Case Assigned(_CloseTouchInputHandle) of
True : Result := _CloseTouchInputHandle(hTouchInput_);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_CloseTouchInputHandle := GetProcAddress(_User32Handle, 'CloseTouchInputHandle');
If Assigned(_CloseTouchInputHandle) then
Result := _CloseTouchInputHandle(hTouchInput_);
end;
end;
end;
end;

//
Function GetTouchInputInfo ( hTouchInput : HTOUCHINPUT;
cInputs : UINT;
pInputs : PTOUCHINPUT;
cbSize : Integer ): BOOL;
begin
Case Assigned(_GetTouchInputInfo) of
True : Result := _GetTouchInputInfo(hTouchInput,cInputs,pInputs,cbSize);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_GetTouchInputInfo := GetProcAddress(_User32Handle, 'GetTouchInputInfo');
If Assigned(_GetTouchInputInfo) then
Result := _GetTouchInputInfo(hTouchInput,cInputs,pInputs,cbSize);
end;
end;
end;
end;

//
Function GID_ROTATE_ANGLE_FROM_ARGUMENT( Arg: ULONGLONG): Double;
begin
Result := (((Arg / 65535.0) * 4.0 * 3.14159265) - 2.0 * 3.14159265);
end;

//
Function GID_GestureType(GID : Cardinal ) : TGestureType;
begin
Case GID of
GID_BEGIN : Result := gtBegin;
GID_END : Result := gtEnd;
GID_ZOOM : Result := gtZoom;
GID_PAN : Result := gtPan;
GID_ROTATE : Result := gtRotate;
GID_TWOFINGERTAP : Result := gtTwoFingerTap;
GID_PRESSANDTAP : Result := gtPressAndTap;
else Result := gtNone;
end;
end;

//
Function Get_Angle(gaArg : ULongLong) : Double;
begin
Result := gID_Rotate_Angle_From_Argument(gaArg) * 180 / pi;
end;

//
Function Flag_Check(fcValue,fcFlag : DWord) : Boolean;
begin
Result := (fcValue and fcFlag) = fcFlag;
end;

//
Function Flag_State(fcValue : DWord) : TGestureState;
begin
// 초기화
Result := gsNone;
//
If Flag_Check(fcValue,GF_Begin ) then Result := gsBegin;
If Flag_Check(fcValue,GF_End ) then Result := gsEnd;
If Result = gsNone then Result := gsWork;
end;

// ----------------------------------------------------------------------------
//
//
//
//
//
// ----------------------------------------------------------------------------

//
Function Gesture_Set (gsHandle : THandle;gsSet : TGestureSet) : Boolean;
Var
GestureConfig : TGestureConfig;
Configs : Array [0..1] of TGestureConfig;
ConfigCnt : Integer;
begin
Case gsSet of
gsAll : // Gesture 전체 사용
begin
FillChar(GestureConfig,SizeOf(GestureConfig),#0);
GestureConfig.dwWant := GC_AllGestures;
Result := Integer(SetGestureConfig(gsHandle,0,1,@GestureConfig,
SizeOf(GestureConfig))) <> 0;
end;
gsZoom,
gsZoomRotate
: //
begin
FillChar(Configs,SizeOf(Configs),#0);
//
Configs[0].dwID := GID_Zoom;
Configs[0].dwWant := GC_Zoom;
Configs[0].dwBlock := 0;

Configs[1].dwID := GID_ROTATE;
Configs[1].dwWant := GC_ROTATE;
Configs[1].dwBlock := 0;
//
Case gsSet of
gsZoom : ConfigCnt := 1;
gsZoomRotate : ConfigCnt := 2;
End;
Result := Integer(SetGestureConfig(gsHandle,0,ConfigCnt,@Configs[0],
Sizeof(TGestureConfig))) <> 0;
end;
end;
end;

// http://msdn.microsoft.com/ko-kr/magazine/ee336016.aspx
Function Gesture_Get(_wParam :wParam; _lParam :lParam) : TGesture;
Var
GI : TGestureInfo;
Str : String;
begin
// Step #1. 초기화 ----------------------------------------------------------
FillChar(Result,SizeOf(TGesture),#0);
FillChar(Gi,SizeOf(Gi),#0);
ZeroMemory(@gi, sizeof(TGestureInfo));
gi.cbSize := Sizeof(gi);

// Step #2. 멀티터치 정보 얻기 ----------------------------------------------
GetGestureInfo(_lParam, gi);
//
Result.Type_ := GID_GestureType(gi.dwID);
Result.XY := Point(gi.ptsLocation.x,gi.ptsLocation.y);

Case gi.dwID of
// Event Style [Simple] ----------------------------------------------------
GID_Pan : Result.State := Flag_State(gi.dwFlags);
GID_TWOFINGERTAP : Result.State := Flag_State(gi.dwFlags);
GID_PRESSANDTAP : Result.State := Flag_State(gi.dwFlags);
// Event Style [Complex] ---------------------------------------------------
GID_Zoom : Begin
Result.State := Flag_State(gi.dwFlags);
// Zoom 계산을 위하여, 초기값 저장
If Result.State = gsBegin then
_GestureSav.ullArguments := gi.ullArguments;
Result.Value := gi.ullArguments / _GestureSav.ullArguments;
End;
GID_Rotate : Begin
Case Flag_State(gi.dwFlags) of
gsNone : Result.State := gsNone;
gsBegin : begin
_GestureSav.Cnt := 0;
_GestureSav.State := gsNone;
Result.State := gsNone;
end;
gsWork,
gsEnd : begin
Inc(_GestureSav.Cnt);
Result.State := gsNone;
If _Gesturesav.Cnt > 2 then
begin
Case _GestureSav.State of
gsNone : begin
Result.State := gsBegin;
_GestureSav.State := gsWork;
_GestureSav.AnglePrev := Get_Angle(gi.ullArguments);
If Flag_State(gi.dwFlags) = gsEnd then
Result.State := gsNone;
end;
gsWork : Case Flag_State(gi.dwFlags) = gsWork of
True : Result.State := gsWork;
False : Result.State := gsEnd;
end;
End;
end;
Result.Value := Get_Angle(gi.ullArguments);

GestureSav.AnglePrev := Result.Value;
{
Case Result.Value > 0 of
True : Result.Value := 2;
False: Result.Value := -2;
End;
}
end;
End;
End;
End;
//
CloseGestureInfoHandle(_lParam);
end;

//
Function Gesture_Str (Gstr : TGesture) : String;

Function State2Str(fsFlag : TGestureState) : String;
begin
Case fsFlag of
gsNone : Result := '... ';
gsBegin : Result := 'Begin ';
gsWork : Result := 'Work ';
gsEnd : Result := 'End ';
End;
end;

Function XY2Str(xy : TPoint) : String;
begin
Result := IntToStr(xy.x)+','+ IntToStr(xy.Y) + ' ';
end;

begin
Case Gstr.Type_ of
gtBegin : Result := 'Begin ';
gtEnd : Result := 'End ';
gtZoom : Result := 'Zoom ' + State2Str(Gstr.State) + XY2Str(Gstr.XY) + Format('%3.1f',[Gstr.Value]);
gtPan : Result := 'Pan ' + State2Str(Gstr.State) + XY2Str(Gstr.XY);
gtRotate : Result := 'Rotate ' + State2Str(Gstr.State) + XY2Str(Gstr.XY) + Format('%3.1f',[Gstr.Value]);
gtTwoFingerTap : Result := '2FngrTap' + State2Str(Gstr.State) + XY2Str(Gstr.XY);
gtPressAndTap : Result := 'Prs &Tap' + State2Str(Gstr.State) + XY2Str(Gstr.XY);
End;
end;

Initialization
//
_User32Handle := 0;
_GetGestureInfo := nil;
_CloseGestureInfoHandle := nil;
_SetGestureConfig := nil;
_RegisterTouchWindow := nil;
_UnRegisterTouchWIndow := nil;
_CloseTouchInputHandle := nil;
//
FillChar(GestureSav,SizeOf(GestureSav),#0);
end.

2009년 1월 25일 일요일

About Photoshop File Format Internal

This contents has the article how to generate psd file in your application.
simonsayz@naver.com


포토앨범 맥스페이퍼를 위하여, 수작업으로 분석한 포토샵 파일 구조 분석입니다.
맥스페이퍼 다음버전부터는 포토샵 파일 출력 기능이 추가됩니다.



맥스페이퍼 다운로드 3MB ( http://www.maxpaper.com/ )



주제어 :
맥스페이퍼,maxpaper,포토앨범,포토샵,포토샵 파일구조,RLE,RAW,Packbits,TIFF Standard,
델파이,PSD,PSB,PSD CS,RLE Compressed,압축앨범,성장앨범,자동보정,증명사진,사진인화,
Noritsu,Fujifilm,프론티어 7500,프론티어 7700,Frontier 7500,Panda,Simon,Qss HD



문서 참조를 위하여, 영어로 작성되었습니다.


This is analysis report of the 5x5 pixel psd file (Blue & Red) for maxpaper.

Remarks
Maxpaper is photo album software. (
http://www.maxpaper.com/ )


Last modified : Jan,26,2009
Revision 1.6 by simon,choi
(simonsayz@naver.com)


Preset Variable

Calculated Varitable






Common Header of PSD (RLE Compressed Version)


/- File Header ----------------------------------------------------------------/
38 42 50 53 ; PhotoShop Header / 8BPS
00 01 ; Version
00 00 00 00 00 00 ; Reserved
00 04 ; Channel
00 00 00 05 ; Row (5pixel)
00 00 00 05 ; Column (5pixel)
00 08 ; Depth (8bit)
00 03 ; Mode (RGB )

/- Color Mode Data ------------------------------------------------------------/
00 00 00 00 ; Color Map Data Size

/- Image Resources ------------------------------------------------------------/
00 00 00 44 ; Length (68 Bytes)
38 42 49 4D ; '8BIM'
03 EE ; Alpha Channel Name
00 00 ; Name Length
00 00 00 0D ; Resource Size
0C 54 72 61 6E 73 70 61 72 65 6E 63 79 00 ; Transparency
38 42 49 4D ; '8BIM'
03 ED ; Resolution Info
00 00 ; Name Length
00 00 00 10 ; Resource Size
01 2C 00 00 ; hRes [300]
00 01 ; hResUnit [Pixel per Inch]
00 01 ; WidthUnit [inch]
01 2C 00 00 ; vRes [300]
00 01 ; vResUnit [Pixel per Inch]
00 01 ; HeightUnit [inch]
38 42 49 4D ; '8BIM'
04 00 ; Layer State Information [Target Layer]
00 00 ; Name Length
00 00 00 02 ; Resource Size
00 00 ; [Bottom Layer]


/- Layer and Mask ---------------------------------------------------------/
00 00 01 76 ; Layer Length (374 ) Offset x1
00 00 01 72 ; Layer Info Len (370 = 2 + 106*2 + 88 + 68 ) Offset x1 + 4d
FF FE ; No of Layers, If < 0 -> 1st alpha have transparency area





00 00 00 00 ; Top Offset x2 Layer #1 (106bytes)
00 00 00 01 ; Left
00 00 00 05 ; Bottom
00 00 00 04 ; Right
00 04 ; No Chans
FF FF ; Alpha
00 00 00 16 ;
Length of Alpha Offset x2 + 20d
00 00 ; Red
00 00 00 16 ;
Length of Red Offset x2 + 26d
00 01 ; Green
00 00 00 16 ;
Length of Green Offset x2 + 32d
00 02 ; Blue
00 00 00 16 ;
Length of Blue Offset x2 + 38d
38 42 49 4D ; '8BIM'
6E 6F 72 6D ; 'norm' [normal,darken... ]
FF ; Opacity [0:Transparent..255:Opaque]
00 ; Clip [0:Base, 1:non-base ]
00 ; Flag [0:trans protected, 1 : visible]
00 ; Filler [zero]
00 00 00 30 ; Extra Len
00 00 00 00 ; Mask Len
00 00 00 00 ; Blend Langes
07 4C 61 79 65 72 20 31 ; 'Layer 1'; Layer Name( x 4bytes based,pascal string)
38 42 49 4D ; '8BIM';
6C 75 6E 69 ; luni (Unicode name)
00 00 00 14 ; Length
00 00 00 07 00 4C 00 61 00 79 00 65 00 72 00 20 00 31 00 00 ; 'Layer 1'







00 00 00 01 ; Top Offset x3 Layer #n (106bytes)
00 00 00 00 ; Left
00 00 00 04 ; Bottom
00 00 00 05 ; Right
00 04 ; Chs DB
FF FF ; Alpha
00 00 00 12 ;
Length of Alpha Offset x3 + 20d
00 00 ; Red
00 00 00 12 ;
Length of Red Offset x3 + 26d
00 01 ; Green
00 00 00 12 ;
Length of Green Offset x3 + 32d
00 02 ; Blue
00 00 00 0E ;
Length of Blue Offset x3 + 38d
38 42 49 4D ; '8BIM'
6E 6F 72 6D ; Layer Blend
FF ; Opacity
00 ; Clip
00 ; Flag
00 ; Filler [zero]
00 00 00 30 ; Extra Len
00 00 00 00 ; Mask Len
00 00 00 00 ; Blend Len
07 4C 61 79 65 72 20 31 ; 'Layer 2'; Layer Name( x 4bytes based,pascal string)
38 42 49 4D ; '8BIM'
6C 75 6E 69 ; luni (Unicode name)
00 00 00 14 ; Length
00 00 00 07 00 4C 00 61 00 79 00 65 00 72 00 20 00 32 00 00 ; 'Layer 2'


Layer 1( Transparency,Red,Green,Blue )-------------------------------------








*00 01 ; Alpha / RLE
00 02/00 02/00 02/00 02/00 02 ; ColSize * Height (2x5)
FE FF FE FF FE FF FE FF FE FF ;


16h (88bytes)
Length of Alpha







*00 01 ; Red / RLE
00 02/00 02/00 02/00 02/00 02 ; ColSize * Height (2x5)
FE FF FE FF FE FF FE FF FE FF

16h
Length of Red





*00 01 ; Green / RLE
00 02/00 02/00 02/00 02/00 02 ; ColSize * Height (2x5)
FE 00 FE 00 FE 00 FE 00 FE 00

16h
Length of Green






*00 01 ; Blue / RLE
00 02/00 02/00 02/00 02/00 02 ; ColSize * Height (2x5)
FE 00 FE 00 FE 00 FE 00 FE 00

16h
Length of Blue

FF FF FF FF FF FF 00 00 00 00 00 00
FF FF FF FF FF FF 00 00 00 00 00 00
FF FF FF FF FF FF 00 00 00 00 00 00
FF FF FF FF FF FF 00 00 00 00 00 00
FF FF FF FF FF FF 00 00 00 00 00 00

Layer 2( Transparency,Red,Green,Blue )-------------------------------------








*00 01 ; Alpha / RLE
00 02/00 06/00 02 ; ColSize * Height (2x3)
FC FF/00 FF FE 00 00 FF/FC FF


12h (68bytes)
Length of Alpha







*00 01 ; Red / RLE
00 02/00 06/00 02 ; ColSize * Height (2x3)
FC 00/00 00 FE FF 00 00/FC 00

12h
Length of Red






*00 01 ; Green / RLE
00 02/00 06/00 02 ; ColSize * Height (2x3)
FC 00/00 00 FE FF 00 00/FC 00

12h
Length of Green






*00 01 ; Blue / RLE
00 02/00 02/00 02 ; ColSize * Height (2x3)

FC FF FC FF FC FF

0Eh
Length of Blue


FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF
FF 00 00 00 FF 00 FF FF FF 00 00 FF FF FF 00 FF FF FF FF FF
FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF

/- Image Data -----------------------------------------------------------------/
*00 01 ; RLE
00 02/00 02/00 06/00 02/00 02/ ; Alpha ColSize * Height (2x5)
00 06/00 02/00 02/00 02/00 06/ ; Red ColSize * Height (2x5)
00 06/00 02/00 06/00 02/00 06/ ; Green ColSize * Height (2x5)
00 06/00 02/00 02/00 02/00 06/ ; Blue ColSize * Height (2x5)
FC FF /FC 00/00 00 FE FF 00 00/FC 00/
FC FF
00 FF FE 00 00 FF/FC 00/FC 00 /FC 00/
00 FF FE 00 00 FF
00 FF FE 00 00 FF/FC FF/00 FF FE 00 00 FF/FC FF/
00 FF FE 00 00 FF
00 00 FE FF 00 00/FC FF/FC FF /FC FF/
00 00 FE FF 00 00

FF FF FF FF FF FF 00 00 00 FF FF 00 00 00 FF 00 FF FF FF 00

00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF
00 FF FF FF 00 00 00 00 00 00 FF 00 00 00 FF FF FF FF FF FF
00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF 00 00 00 FF FF 00 00 00 FF
00 FF FF FF 00



This is analysis report of the 2x2 pixel psd file (RGBA) for maxpaper.









Common Header of PSD (Uncompressed Version)


/- File Header ----------------------------------------------------------------/
38 42 50 53 ; PhotoShop Header / 8BPS
00 01 ; Version
00 00 00 00 00 00 ; Reserved
00 04 ; Channel
00 00 00 02 ; Row (2 pixel)
00 00 00 02 ; Column (2 pixel)
00 08 ; Depth (8bit)
00 03 ; Mode (RGB )

/- Color Mode Data ------------------------------------------------------------/
00 00 00 00 ; Color Map Data Size

/- Image Resources ------------------------------------------------------------/
00 00 00 44 ; Length (68 Bytes)
38 42 49 4D ; '8BIM'
03 EE ; Alpha Channel Name
00 00 ; Name Length
00 00 00 0D ; Resource Size
0C 54 72 61 6E 73 70 61 72 65 6E 63 79 00 ; Transparency
38 42 49 4D ; '8BIM'
03 ED ; Resolution Info
00 00 ; Name Length
00 00 00 10 ; Resource Size
01 2C 00 00 ; hRes [300]
00 01 ; hResUnit [Pixel per Inch]
00 01 ; WidthUnit [inch]
01 2C 00 00 ; vRes [300]
00 01 ; vResUnit [Pixel per Inch]
00 01 ; HeightUnit [inch]
38 42 49 4D ; '8BIM'
04 00 ; Layer State Information [Target Layer]
00 00 ; Name Length
00 00 00 02 ; Resource Size
00 00 ; [Bottom Layer]


/- Layer and Mask ---------------------------------------------------------/
00 00 00 88 ; Layer Length ( 136 ) Offset x1
00 00 00 84 ; Layer Info Len ( 132 = 106+24+2 ) Offset x1 + 4d
FF FF ; No of Layers, If < 0 -> 1st alpha have transparency area





00 00 00 00 ; Top Offset x2 Layer #1 (106bytes)
00 00 00 00 ; Left
00 00 00 02 ; Bottom
00 00 00 02 ; Right
00 04 ; No Chans
FF FF ; Alpha
00 00 00 06 ;
Length of Alpha Offset x2 + 20d
00 00 ; Red
00 00 00 06 ;
Length of Red Offset x2 + 26d
00 01 ; Green
00 00 00 06 ;
Length of Green Offset x2 + 32d
00 02 ; Blue
00 00 00 06 ;
Length of Blue Offset x2 + 38d
38 42 49 4D ; '8BIM'
6E 6F 72 6D ; 'norm' [normal,darken... ]
FF ; Opacity [0:Transparent..255:Opaque]
00 ; Clip [0:Base, 1:non-base ]
00 ; Flag [0:trans protected, 1 : visible]
00 ; Filler [zero]
00 00 00 30 ; Extra Len
00 00 00 00 ; Mask Len
00 00 00 00 ; Blend Langes
07 4C 61 79 65 72 20 31 ; 'Layer 1'; Layer Name( x 4bytes based,pascal string)
38 42 49 4D ; '8BIM';
6C 75 6E 69 ; luni (Unicode name)
00 00 00 14 ; Length
00 00 00 07 00 4C 00 61 00 79 00 65 00 72 00 20 00 31 00 00 ; 'Layer 1'


Layer 1( Transparency,Red,Green,Blue )-------------------------------------






*00 00 FF FF/FF 00 ; Alpha / Raw


06h (24bytes)







*00 01 FF 00/00 FF ; Red / Raw

06h






*00 01 00 FF/00 FF ; Green / Raw

06h






*00 01 FF 00/FF FF ; Blue / Raw

06h

FF FF FF 00 00 FF 00 00
FF 00 00 FF 00 FF FF FF


/- Image Data -----------------------------------------------------------------/
*00 00 ; Raw Data
FF 00/00 FF ; Alpha
00 FF/00 FF ; Red
00 00/FF FF ; Green
FF FF/FF 00 ; Blue ColSize * Height (2x5)

FF 00 00 FF 00 00 FF FF
00 FF 00 FF FF FF FF 00


2009년 1월 8일 목요일

scrapbook software maxpaper b2182



Scrapbook software maxpaper b.2182

freeware for personal usages. but not allowed for commercial usages.
It's very useful to compose the photos within a minute.

Download(3MB) : http://www.maxpaper.com/provider/system/maxpaper_b2782me.zip

----------------------------------------------
Software Requirements
OS : Windows xp,vista
RAM : over 1GB
Video : over 1024x768 (32bit)