home *** CD-ROM | disk | FTP | other *** search
- {$A+,F+,R-,S-,V-}
- {$M 8192,0,$A0000}
-
- {***********************************************}
- {* TERMBP.PAS 1.02 *}
- {* Copyright (c) TurboPower Software 1991 *}
- {* All Rights Reserved *}
- {***********************************************}
-
- program TermBP;
- {Example prog for BPlus protocols, including online GIF display}
-
- {$I APDEFINE.INC}
-
- {$IFNDEF UseOPro}
- !!! The included defines are not compatible with this program !!!
- {$ENDIF}
-
- {$IFNDEF UseOOP}
- !!! The included defines are not compatible with this program !!!
- {$ENDIF}
-
- {The following two defines must match the state of the same defines in}
- {OOBPLUS.PAS and GIFVIDEO.PAS}
-
- {$DEFINE SupportGIF}
- {$DEFINE UseSVGA}
-
- uses
- DOS,
- OpRoot,
- OpDos,
- OpCrt,
- OpString,
- OpKey,
- ApMisc,
- ApPort,
- ApUart,
- ApTimer,
- ApAnsi,
- OOCom,
- OOAbsPcl,
- OOBPlus,
- GIFVideo,
- OLGIF;
-
- type
- BufPtr = ^BufferArray;
- BufferArray = array[0..MaxInt] of Char;
-
- const
- WAttr : Byte = $1B; {Window attribute}
- FAttr : Byte = $1E; {Frame attribute}
- DAttr : Byte = $1F; {Data attribute}
- StatusDelay = 2000; {Delay 2 seconds for status messages}
-
- var
- UP : UartPortPtr; {our port ptr}
- BP : BPProtoFTP; {B+ proto object}
-
- W : Word;
- C : Char absolute W;
- GotIt,
- Finished : Boolean;
- S : String;
- BytesRead : Word;
- B : array[1..1000] of Char;
- OTMode : Byte;
-
- procedure Abort(Msg : String; Code : Integer);
- {-Close port and halt}
- begin
- WriteLn(Msg, Code);
- Halt(1);
- end;
-
- procedure RingBell;
- {-make a noise}
- begin
- Sound(440);
- Delay(100);
- NoSound;
- end;
-
- {--------------------------------------------------------------------------}
-
- function Long2StrBlank(L : LongInt) : string;
- {-Convert a long/word/integer/byte/shortint to a string}
- begin
- if L <= 0 then
- Long2StrBlank := ''
- else
- Long2StrBlank := Long2Str(L);
- end;
-
- function BuildWindow(XLow, YLow, XHigh, YHigh : Byte; Header : String) : Pointer;
- {-Saves the underlying screen, frames and clears a window}
- type
- FrameCharType = (ULeft, LLeft, URight, LRight, Horiz, Vert);
- FrameArray = array[FrameCharType] of Char;
- const
- FrameChars : FrameArray = '╒╘╕╛═│';
- var
- CoversP : BufPtr;
- WordsPerRow : Word;
- BufBytes : Word;
- SrcPos : Word;
- DestPos : Word;
- Row : Word;
- HeaderLen : Byte absolute Header;
- Width, HeaderPos : Byte;
- Span : string[132];
- SpanLen : Byte absolute Span;
-
- begin
- BuildWindow := nil;
-
- {Compute number of words to move per row}
- WordsPerRow := Succ(XHigh-XLow);
-
- {Compute bytes needed for screen buffer}
- BufBytes := (WordsPerRow*Succ(YHigh-YLow)) shl 1;
-
- {Make sure enough memory is available}
- if not GetMemCheck(CoversP, BufBytes) then
- Exit;
-
- {Save current contents to the screen buffer}
- DestPos := 0;
- SrcPos := (Pred(YLow)*ScreenWidth+Pred(XLow)) shl 1;
- for Row := YLow to YHigh do begin
- MoveScreen(Mem[VideoSegment:SrcPos], CoversP^[DestPos], WordsPerRow);
- Inc(SrcPos, ScreenWidth shl 1);
- Inc(DestPos, WordsPerRow shl 1);
- end;
-
- {Calculate width of window and position of header}
- SpanLen := Succ(XHigh - XLow);
- Width := SpanLen-2;
-
- {construct the upper border and draw it}
- FillChar(Span[2], Width, FrameChars[Horiz]);
- Span[1] := FrameChars[ULeft];
- Span[SpanLen] := FrameChars[URight];
- FastWrite(Span, YLow, XLow, FAttr);
-
- {Draw the vertical bars}
- for Row := Succ(YLow) to Pred(YHigh) do begin
- FastWrite(FrameChars[Vert], Row, XLow, FAttr);
- FastWrite(FrameChars[Vert], Row, XHigh, FAttr);
- end;
-
- {Draw the bottom border}
- Span[1] := FrameChars[LLeft];
- Span[SpanLen] := FrameChars[LRight];
- FastWrite(Span, YHigh, XLow, FAttr);
-
- {Draw the header}
- if HeaderLen > 0 then begin
- if HeaderLen > Width then
- HeaderLen := Width;
- HeaderPos := (SpanLen-HeaderLen) shr 1;
- FastWrite(Header, YLow, XLow + HeaderPos, FAttr);
- end;
-
- {Fill in the window}
- for Row := Ylow+1 to YHigh-1 do
- FastWrite(CharStr(' ', Pred(XHigh-XLow)), Row, XLow+1, FAttr);
-
- BuildWindow := CoversP;
- end;
-
- procedure RemoveWindow(P : Pointer; XLow, YLow, XHigh, YHigh : Byte);
- {-Restore screen contents and deallocate buffer space if requested}
- var
- CoversP : BufPtr absolute P;
- WordsPerRow : Word;
- SrcPos : Word;
- DestPos : Word;
- Row : Word;
- begin
- {Compute number of words to move per row}
- WordsPerRow := Succ(XHigh-XLow);
-
- {Restore current contents to the screen buffer}
- DestPos := 0;
- SrcPos := (Pred(YLow)*ScreenWidth+Pred(XLow)) shl 1;
- for Row := YLow to YHigh do begin
- MoveScreen(CoversP^[DestPos], Mem[VideoSegment:SrcPos], WordsPerRow);
- Inc(SrcPos, ScreenWidth shl 1);
- Inc(DestPos, WordsPerRow shl 1);
- end;
-
- {Deallocate buffer space}
- FreeMem(CoversP, (WordsPerRow*Succ(YHigh-YLow)) shl 1);
- end;
-
- function ReadStrWin(Pr : String; var S : String) : Boolean;
- {-prompt for a string in a window}
- var
- P : Pointer;
- OX,OL : Word;
- OA,B : Byte;
- begin
- ReadStrWin := False;
- OA := TextAttr;
- GetCursorState(OX,OL);
- S := '';
- P := BuildWindow(1,10,ScreenWidth,12,'');
- if P = NIL then exit;
-
- FastWrite(Pr,11,3,WAttr);
- GoToXYAbs(Length(Pr)+4,11);
- TextAttr := DAttr;
- S := '';
- ReadLn(S);
-
- TextAttr := OA;
- RestoreCursorState(OX,OL);
- RemoveWindow(P,1,10,ScreenWidth,12);
- ReadStrWin := (S <> '');
- end;
-
- function FormatMinSec(TotalSecs : LongInt) : String;
- {-Format TotalSecs as minutes:seconds}
- var
- Min, Sec : LongInt;
- S : String;
- begin
- Min := TotalSecs div 60;
- Sec := TotalSecs mod 60;
- Str(Sec:2, S);
- if S[1] = ' ' then
- S[1] := '0';
- FormatMinSec := Pad(Long2Str(Min) + ':' + S,8);
- end;
-
- function FormatMinTenths(TotalSecs : LongInt) : String;
- {-Format TotalSecs as minutes.tenths}
- var
- Min : Real;
- S : String;
- begin
- Min := TotalSecs / 60;
- Str(Min:6:1, S);
- FormatMinTenths := Pad(S,8);
- end;
-
- procedure UpdateProgressBar(Row, Col, Len : Byte; Percent : Real);
- {-Fills in a progress bar with Percent complete}
- const
- CompleteChar = '▓';
- var
- CharPercent : Real;
- CharCount : Byte;
- BarStr : String;
- begin
- if Len = 0 then exit;
- {Calculate "percent value" of each character space}
- CharPercent := 100.0 / Len;
-
- {Calculate how many chars we need to approach (but not exceed) Percent}
- CharCount := Trunc((Percent * 100) / CharPercent);
-
- {Make sure we don't go past Len}
- if CharCount > Len then
- CharCount := Len;
-
- {Write out the complete bar}
- FillChar(BarStr[1], CharCount, CompleteChar);
- BarStr[0] := Char(CharCount);
- if CharCount <> 0 then
- FastWrite(BarStr, Row, Col, DAttr);
- end;
-
- procedure UpdateStatusMsg(Row, Col, Len : Byte);
- {-Translate the current AsyncStatus into a status message}
- const
- LastStatus : Word = 65535;
- MaxMsgLen = 40;
- var
- Msg : String;
- begin
- if AsyncStatus <> LastStatus then begin
- FillChar(Msg[1], MaxMsgLen, ' ');
- Msg[0] := Char(MaxMsgLen);
- FastWrite(Msg, Row, Col, DAttr);
- Msg := bpStatusStr(AsyncStatus);
- FastWrite(Msg, Row, Col, DAttr);
- if AsyncStatus <> 0 then Delay(2000);
- end;
- end;
-
-
- {$F+}
- function WindowResume(BP : BPProtocolPtr) : ResumeResultType;
- var
- Res : ResumeResultType;
- C : Char;
- E : EventTimer;
- begin
- FastWrite(Pad('File Exists. (R)esume, (O)verwrite, re(N)ame, (A)bort?',57),18,12,DAttr);
- RingBell;
- NewTimerSecs(E,10);
- repeat
- while NOT KeyPressed do
- if TimerExpired(E) then begin {send WACK to host}
- BP^.APort^.PutString(cDLE+';');
- NewTimerSecs(E,10);
- end;
- C := Upcase(ReadKey);
- until (C in ['A','N','O','R']);
- FastWrite(Pad(' ',57),18,12,DAttr);
- case C of
- 'A': WindowResume := xfrAbort;
- 'N': WindowResume := xfrRename;
- 'O': WindowResume := xfrOverwrite;
- 'R': WindowResume := xfrResume;
- end;
- end;
-
- procedure WindowStatus(AP : AbstractProtocolPtr;
- Starting, Ending : Boolean);
- {-Default show status procedure}
-
- (*
- ┌───────────────────── Protocol Upload ────────────────────┐
- 1 │ Protocol: xxxxxxxxxx Bytes sent: xxxxxxx │
- 2 │ File name: xxxxxxxxxx Bytes recd: xxxxxxx │
- 3 │ File size: xxxxxx Packets sent: xxxxxxx │
- 4 │ Block check: xxx Packets recd: xxxxxxx │
- 5 │ Block size: xxxxx Data bytes: xxxxxxx │
- 6 │ Blocks to go: xxxxx Remaining: xxxxxxx │
- 7 │ │
- 8 │ Est. time: xx.x Total errors: xxxxxxx │
- 9 │ Elapsed time: Throughput: xxxxxxx │
- 10 │ Remaining time: xx.x Efficiency: xxxxxxx │
- 11 │ │
- 12 │ Progress: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
- 13 │ Last Message: Ok │
- 14 │ │
- └──────────────────────────────────────────────────────────┘
- *)
-
- const
- XLow = 10;
- YLow = 4;
- XHigh = 69;
- YHigh = 19;
- P : Pointer = nil;
- NewProgBar = '░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░';
- var
- Blocks : Integer;
- Efficiency, MaxCPS, ActualCPS, R : Real;
- CurBlockSize : Word;
- CurElapsedTics : LongInt;
- CurElapsedSecs : LongInt;
- CurBlock : Word;
- S : String;
- I : Word;
- B : Boolean;
- begin
- if Starting then with BPProtoFTPPtr(AP)^ do begin
- {Build and frame the window}
- P := BuildWindow(XLow, YLow, XHigh, YHigh,' BPlus Protocol ');
- if P = nil then
- Abort('Insufficient memory ', 1);
-
- {Write out the fixed text strings}
- FastWrite('Protocol:', YLow+1, XLow+2, WAttr);
- FastWrite('Check type:', YLow+2, XLow+2, WAttr);
- FastWrite('File name:', YLow+3, XLow+2, WAttr);
- FastWrite('File size:', YLow+4, XLow+2, WAttr);
- FastWrite('Block size:', YLow+5, XLow+2, WAttr);
- FastWrite('Blocks to go:', YLow+6, XLow+2, WAttr);
-
- FastWrite('Est. time:', YLow+8, XLow+2, WAttr);
- FastWrite('Elapsed time:', YLow+9, XLow+2, WAttr);
- FastWrite('Remaining time:', YLow+10, XLow+2, WAttr);
-
- FastWrite('Bytes sent:', YLow+1, XLow+33, WAttr);
- FastWrite('Bytes recd:', YLow+2, XLow+33, WAttr);
- FastWrite('Packets sent:', YLow+3, XLow+33, WAttr);
- FastWrite('Packets recd:', YLow+4, XLow+33, WAttr);
- FastWrite('Data bytes:', YLow+5, XLow+33, WAttr);
- FastWrite('Remaining:', YLow+6, XLow+33, WAttr);
-
- FastWrite('Total errors:', YLow+8, XLow+33, WAttr);
- FastWrite('Throughput:', YLow+9, XLow+33, WAttr);
- FastWrite('Efficiency:', YLow+10, XLow+33, WAttr);
-
- FastWrite('Progress:', YLow+12, XLow+2, WAttr);
- FastWrite('Status:', YLow+13, XLow+2, WAttr);
- FastWrite(NewProgBar, YLow+12, XLow+18, DAttr);
- end;
-
- {Update the data areas}
- with BPProtoFTPPtr(AP)^ do begin
- {Store common status info in local variables}
- CurBlockSize := OurParams.BlkSize * 128;
- BlockLen := CurBlockSize;
- CurElapsedTics := ElapsedTime(Timer);
- CurElapsedSecs := Tics2Secs(CurElapsedTics);
-
- {Protocol and file name}
- FastWrite(ProtocolTypeString[ProtType], YLow+1, XLow+18, DAttr);
- case GetCheckType of
- bcChecksum1 : S := bcsChecksum1;
- else S := bcsCrc16;
- end;
- FastWrite(S, YLow+2, XLow+18, DAttr);
- FastWrite(Pad(StUpcase(GetFileName), 12), YLow+3, XLow+18, DAttr);
-
- {File size, packet size, check type and packets remaining}
- FastWrite(LeftPad(Long2StrBlank(SrcFileLen),8), YLow+4, XLow+18, DAttr);
- FastWrite(LeftPad(Long2Str(CurBlockSize),8), YLow+5, XLow+18, DAttr);
- Blocks := Trunc((BytesRemaining+Pred(CurBlockSize)) div CurBlockSize);
- FastWrite(LeftPad(Long2StrBlank(Blocks),8), YLow+6, XLow+18, DAttr);
-
- {Estimated time, elapsed time and time remaining}
- if SrcFileLen > 0 then
- FastWrite(Pad(FormatMinSec(EstimateTransferSecs(SrcFileLen)),8),
- YLow+8, XLow+18, DAttr);
- FastWrite(Pad(FormatMinSec(CurElapsedSecs),8), YLow+9, XLow+18, DAttr);
- if BytesRemaining > 0 then
- FastWrite(Pad(FormatMinSec(EstimateTransferSecs(BytesRemaining)),8),
- YLow+10, XLow+18, DAttr);
-
- {Raw bytes sent and recd}
- FastWrite(LeftPad(Long2StrBlank(S_Raw),8), YLow+1, XLow+50, DAttr);
- FastWrite(LeftPad(Long2StrBlank(R_Raw),8), YLow+2, XLow+50, DAttr);
-
- {Blocks sent and recd}
- FastWrite(LeftPad(Long2StrBlank(S_Packets),8), YLow+3, XLow+50, DAttr);
- FastWrite(LeftPad(Long2StrBlank(R_Packets),8), YLow+4, XLow+50, DAttr);
-
- {Data counts}
- FastWrite(LeftPad(Long2StrBlank(BytesTransferred),8), YLow+5, XLow+50, DAttr);
- FastWrite(LeftPad(Long2StrBlank(BytesRemaining),8), YLow+6, XLow+50, DAttr);
-
- {Errors}
- FastWrite(LeftPad(Long2Str(GetTotalErrors),8), YLow+8, XLow+50, DAttr);
-
- {Display an empty progress bar on startup}
- if BytesTransferred = 0 then
- FastWrite(NewProgBar, YLow+12, XLow+18, DAttr);
-
- {Update the progress bar (if the file size is known}
- if SrcFileLen > 0 then
- R := BytesRemaining / SrcFileLen
- else
- R := 1.0;
- UpdateProgressBar(YLow+12, XLow+18, Length(NewProgBar), 1.0 - R);
-
- {Update status message}
- UpdateStatusMsg(YLow+13, XLow+18, 35);
-
- {Calculate and display throughput}
- if CurElapsedSecs > 0 then
- ActualCPS := BytesTransferred / CurElapsedSecs
- else
- ActualCPS := 0.0;
- FastWrite(LeftPad(Long2Str(Trunc(ActualCPS))+' CPS',8),
- YLow+9, XLow+50, DAttr);
-
- {Calculate and display efficiency}
- MaxCPS := APort^.PR^.CurBaud div 10;
- if MaxCPS > 0 then
- Efficiency := (ActualCPS / MaxCPS) * 100.0
- else
- Efficiency := 0.0;
- FastWrite(Real2Str(Efficiency, 7, 0)+'%', YLow+10, XLow+50, DAttr);
- end;
-
- {Remove the window on the last status call}
- if Ending then
- RemoveWindow(P, XLow, YLow, XHigh, YHigh);
- end;
-
- {--------------------------------------------------------------------------}
-
- {$IFDEF SupportGIF}
-
- procedure ShowGIF;
- {-save screen, display GIF online}
- const
- TmpName = '$$TEMP$$.GIF';
- TmpBSize = 8192;
- var
- SP : Pointer;
- X,L : Word;
- B : Boolean;
- S : String;
-
- function SaveTempGIF(NewFN : PathStr) : Boolean;
- {-save temp GIF capture file to new name by fastest means}
- var P : Pointer;
- C : Char;
- W : Word;
- T : PathStr;
- F : File;
- begin
- SaveTempGIF := False;
- {see if new name is on same drive as current}
- C := DefaultDrive;
- T := FExpand(NewFN);
- if (C = T[1]) and (NOT(ExistFile(T))) then begin
- {if so, just rename file and we're done}
- Assign(F,TmpName);
- Rename(F,T);
- SaveTempGIF := (IOResult = 0);
- end
- else begin
- {slow way}
- if NOT GetMemCheck(P,TmpBSize) then exit;
- W := CopyFile(TmpName,T,P,TmpBSize);
- SaveTempGIF := (W = 0);
- FreeMemCheck(P,TmpBSize);
- end;
- end;
-
- procedure KillTemp;
- {-erase the temp file}
- var F : File;
- begin
- Assign(F,TmpName);
- Erase(F);
- if IOResult = 0 then ;
- end;
-
- begin
- {save the screen for later}
- if SaveWindow(1,1,ScreenWidth,ScreenHeight,True,SP) then begin
- GetCursorState(X,L);
-
- {display the thing}
- B := DisplayGIFOnline(UP, True);
-
- {restore the screen}
- RestoreWindow(1,1,ScreenWidth,ScreenHeight,True,SP);
- RestoreCursorState(X,L);
-
- {if the view/capture was OK, get a name and save the perm file}
- if B then
- if (ReadStrWin('GIF Name (<CR>=no save) ',S)) and (S <> '') then begin
- S := StUpcase(S);
- S := DefaultExtension(S,'GIF');
- if SaveTempGIF(S) then
- KillTemp
- else
- RingBell;
- end;
- UP^.PutChar(^M); {host always waits for a CR after a GIF view}
- end;
- end;
-
- {$ENDIF}
-
- procedure ProcessANSI(S : String);
- {-handle our special ANSI/VT52 sequences}
- var
- C : Char;
- begin
- C := S[Length(S)];
- case C of
- {$IFDEF SupportGIF}
- 'g':
- if S[3] = '>' then {GIF command: "[>dg" where d=0,1 or 2}
- case S[4] of
- '0': UP^.PutString(GIFReply + ^M); {send GIF support info}
- '1': ShowGIF; {GIF comming, show it}
- '2': WriteStringAnsi(S); {"2" is to print the GIF, we don't do it}
- else WriteStringAnsi(S); {I dunno!}
- end;
- {$ENDIF}
- 'I':
- if S[2] = 'I' then
- BP.bpHandleESCI {send host our Capabilities Response string}
- else
- WriteStringAnsi(S);
-
- else
- WriteStringAnsi(S);
- end;
- end;
-
-
- procedure Map(var C : Char);
- {-mask recd char to 7 bits}
- begin
- C := Char(Byte(C) and $7F);
- end;
-
- procedure HandleReceive;
- {-process possible received character}
- type
- RcvStates = (rsNormal, rsEscSeen);
- const
- RecvState : RcvStates = rsNormal;
- CapStr : String[40] = '';
- var
- C : Char;
- begin
- if UP^.CharReady then begin
- UP^.GetChar(C);
- Map(C);
-
- case RecvState of
- rsEscSeen:
- begin
- CapStr := CapStr + C;
- if C in ['A'..'Z','a'..'z'] then begin
- ProcessAnsi(CapStr);
- RecvState := rsNormal;
- end;
- end;
-
- rsNormal:
- case C of
- #5 : {<ENQ>, reply}
- BP.bpHandleENQ;
- #8 : {<BS>, make distructive}
- Write(#8#32#8);
- #12: {<FF>, clear the screen}
- ClrScr;
- #16: {<DLE>, start B+ session}
- if BP.bpDLESeen then ;
- #27: {<ESC>, start of a term command}
- begin
- CapStr := '' + #27;
- RecvState := rsEscSeen;
- end;
- else
- Write(C);
- end;
- end;
- end;
- end;
-
- function HandleKey : Boolean;
- {-process pressed keys}
- var W : Word;
- C : Char absolute W;
- begin
- HandleKey := False;
- if NOT KeyPressed then exit;
- W := ReadKeyWord;
- case W of
- AltX:
- HandleKey := True;
- else if C <> #0 then
- UP^.PutChar(C);
- end;
- end;
-
-
-
- begin
- ClrScr;
-
- {$IFDEF UseSVGA}
-
- if CurrentDisplay = VGA then begin
- {we have a VGA, see if it's a supported SVGA. We save & restore text
- mode around this as DetectSVGAType can leave the card somewhat twisted}
- OTMode := CurrentMode;
- DetectSVGAType(True);
- TextMode(OTMode);
- ReinitCrt;
- ClrScr;
- if SVGAType = vtVESA then
- WriteLn('Using detected VESA driver')
- else if SVGAType <> 0 then
- WriteLn('Found ',SVGANames[SVGAType],' chipset-based SVGA');
- end;
-
- {$ENDIF}
-
- {Open a port. B+ protocol should have *minimum* of 2K recv buffer!}
- UP := New(UartPortPtr, InitCustom(Com3, 2400, NoParity, 8, 1,
- 4096, 4096, DefPortOptions));
- if UP = nil then
- Abort('Failed to open port: ', AsyncStatus);
- WriteLn('Com1 opened at 2400 N81');
-
- {set up our B+ protocol object}
- if NOT BP.Init(UP,xfrRename) then begin
- WriteLn('Failed to init protocol object');
- Dispose(UP,Done);
- Halt;
- end;
- BP.SetShowStatusProc(WindowStatus);
- BP.bpSetResumeProc(WindowResume);
-
- WriteLn('Press <AltX> to quit');
-
- {Simple terminal}
- repeat
- {Process chars to send}
- Finished := HandleKey;
-
- {Process chars received}
- HandleReceive;
-
- until Finished;
-
- BP.Done;
- Dispose(UP, Done);
- end.
-