📄 awkermit.pas
字号:
end;
function kpPrevSeq(P : PProtocolData; I : Integer) : Integer;
{-Decrement I to previous slot, accounting for current table size}
begin
with P^ do begin
Dec(I);
if I = 0 then
I := kTableSize;
kpPrevSeq := I;
end;
end;
function kpTableFull(P : PProtocolData) : Bool;
{-Returns True if the send table is full}
begin
with P^ do
kpTableFull := kInfoTable[kpNextSeq(P, kTableHead)].InUse;
end;
function kpPacketsOutstanding(P : PProtocolData) : Bool;
{-True if there are unacked packets in the table}
var
I : Integer;
begin
with P^ do begin
kpPacketsOutstanding := True;
for I := 1 to kTableSize do
if kInfoTable[I].InUse then
Exit;
kpPacketsOutstanding := False;
end;
end;
function kpGetOldestSequence(P : PProtocolData) : Integer;
var
I, Oldest : Integer;
begin
Oldest := MaxInt;
with P^ do begin
for I := 1 to kTableSize do begin
if kInfoTable[I].InUse and (kInfoTable[I].Seq < Oldest) then
Oldest := I;
end;
if Oldest = MaxInt then
Result := -1
else
Result := kInfoTable[Oldest].Seq;
end;
end;
function kpSeqInTable(P : PProtocolData; CurSeq : Integer) : Integer;
{-Return the position in the table of CurSeq, or -1 of not found}
var
I : Integer;
begin
with P^ do begin
kpSeqInTable := -1;
for I := 1 to kTableSize do
if kInfoTable[I].Seq = CurSeq then begin
kpSeqInTable := I;
Exit;
end;
end;
end;
procedure kpGotAck(P : PProtocolData; CurSeq : Cardinal);
{-Note ACK for block number CurSeq}
var
I : Integer;
begin
with P^ do begin
I := kpSeqInTable(P, CurSeq);
if I <> - 1 then
kInfoTable[I].InUse := False;
end;
end;
function kpWindowsUsed(P : PProtocolData) : Byte;
{-Return number of window slots in use}
var
I : Integer;
Cnt : Cardinal;
begin
with P^ do begin
if not kpPacketsOutstanding(P) then begin
kpWindowsUsed := 0;
Exit;
end;
Cnt := 0;
for I := 1 to kTableSize do
if kInfoTable[I].InUse then
Inc(Cnt);
kpWindowsUsed := Cnt;
end;
end;
procedure kpWritePacket(P : PProtocolData; Index : Byte);
{-Expand and write the packet from table slot Index}
var
TIndex : Cardinal;
WIndex : Cardinal;
LastIndex : Cardinal;
RepeatCnt : Cardinal;
Free : Cardinal;
Left : Cardinal;
C : Char;
Failed : Bool;
procedure WriteBlock;
begin
with P^ do begin
Failed := apWriteProtocolBlock(P, kWorkBlock^, SizeOf(kWorkBlock^));
Inc(aFileOfs, SizeOf(kWorkBlock^));
WIndex := 1;
Free := SizeOf(kWorkBlock^);
end;
end;
begin
with P^ do begin
{Set starting indexes}
TIndex := Cardinal(Index-1)*aBlockLen;
LastIndex := Integer(TIndex)+kInfoTable[Index].Len;
WIndex := 1;
{Loop through this block in kDataTable...}
Failed := False;
repeat
{Get a character with escaping already translated}
kpGetDataChar(P, C, TIndex, RepeatCnt);
if RepeatCnt = 1 then begin
{Single char, just add it to WorkBlock}
kWorkBlock^[WIndex] := C;
Inc(WIndex);
end else begin
{Repeating char, start filling aDataBlock(s)}
Free := SizeOf(kWorkBlock^)-(WIndex-1);
Left := RepeatCnt;
repeat
if Free >= Left then begin
FillChar(kWorkBlock^[WIndex], Left, C);
Inc(WIndex, Left);
Left := 0;
end else begin
FillChar(kWorkBlock^[WIndex], Free, C);
Inc(WIndex, Free);
Dec(Left, Free);
end;
{Flush WorkBlock if it fills}
if WIndex = SizeOf(kWorkBlock^)+1 then
WriteBlock;
until (Left = 0) or Failed;
end;
{Flush WorkBlock if it fills}
if WIndex = SizeOf(kWorkBlock^)+1 then
WriteBlock;
until (TIndex = LastIndex) or Failed;
{Commit last, or only, block}
if WIndex <> 1 then begin
Failed := apWriteProtocolBlock(P, kWorkBlock^, WIndex-1);
Inc(aFileOfs, WIndex-1);
end;
end;
end;
function kpSeqGreater(P : PProtocolData; Seq1, Seq2 : Byte) : Bool;
{-Return True if Seq is greater than Seq2, accounting for wrap at 64}
var
I : Integer;
begin
with P^ do begin
I := Seq1 - Seq2;
if I > 0 then
kpSeqGreater := (I < 32)
else
kpSeqGreater := (Abs(I) > 32);
end;
end;
function kpLoSeq(P : PProtocolData) : Byte;
{-Return sequence number of oldest possible sequence number}
{-Current Seq - (kTableSize)}
begin
with P^ do begin
{Handle case of no windows}
if kTableSize = 1 then begin
kpLoSeq := kRecBlockNum;
Exit;
end;
kpLoSeq := kInfoTable[kTableTail].Seq;
end;
end;
function kpHiSeq(P : PProtocolData) : Byte;
{-Return sequence number of highest acceptable sequence number}
var
I : Byte;
Count : Byte;
begin
with P^ do begin
{Handle case of no windows}
if kTableSize = 1 then begin
kpHiSeq := kRecBlockNum;
Exit;
end;
{Search backwards counting free (acked) slots}
I := kpPrevSeq(P, kTableHead);
Count := 0;
repeat
with kInfoTable[I] do
if Acked or not InUse then
Inc(Count);
I := kpPrevSeq(P, I);
until (I = kTableHead);
{HiSeq is current sequence number + Count}
Inc(Count, kRecBlockNum);
if Count > 64 then
Dec(Count, 64);
kpHiSeq := Count;
end;
end;
function kpSeqDiff(P : PProtocolData; Seq1, Seq2 : Byte) : Byte;
{-Assuming Seq1 > Seq2, return the difference}
begin
with P^ do begin
if Seq1 > Seq2 then
kpSeqDiff := Seq1-Seq2
else
kpSeqDiff := (Seq1+64)-Seq2;
end;
end;
procedure kpAddToTable(P : PProtocolData; Seq : Byte);
{-Add Seq to proper location in table}
var
CurSeq : Byte;
HeadSeq : Byte;
I : Cardinal;
Diff : Cardinal;
begin
with P^ do begin
{Calculate kTableHead value for Seq (range known to be OK)}
HeadSeq := kInfoTable[kTableHead].Seq;
if kpSeqGreater(P, Seq, HeadSeq) then begin
{Incoming packet is new, rotate table, writing old slots as required}
Diff := kpSeqDiff(P, Seq, HeadSeq);
for I := 1 to Diff do begin
kTableHead := kpNextSeq(P, kTableHead);
if kTableHead = kTableTail then begin
if kInfoTable[kTableTail].InUse then begin
kpWritePacket(P, kTableTail);
kInfoTable[kTableTail].InUse := False;
kInfoTable[kTableTail].Acked := False;
end;
kTableTail := kpNextSeq(P, kTableTail);
end;
end;
I := kTableHead;
end else begin
{Incoming packet is a retransmitted packet, find associated table index}
CurSeq := HeadSeq;
I := kTableHead;
while CurSeq <> Seq do begin
CurSeq := Dec64(CurSeq);
I := kpPrevSeq(P, I);
end;
end;
{Stuff info table}
kInfoTable[I].Seq := Seq;
kInfoTable[I].Acked := True;
kInfoTable[I].Len := kRecDataLen;
kInfoTable[I].InUse := True;
{Stuff data table}
Move(aDataBlock^, kDataTable^[(I-1)*aBlockLen], kRecDataLen);
end;
end;
procedure kpSendNak(P : PProtocolData);
{-Send an nak packet for packet Seq}
const
NakLen = 3;
begin
with P^ do begin
kpPutHeader(P, KNak, NakLen);
{Put checksum}
kpSendBlockCheck(P);
{Put terminator}
kpSendTerminator(P);
end;
end;
procedure kpSendAck(P : PProtocolData; Seq : Byte);
{-Send an acknowledge packet for packet Seq}
const
AckLen : array[1..3] of Byte = (3, 4, 5);
var
B : Byte;
Save : Byte;
begin
with P^ do begin
B := AckLen[Byte(kKermitOptions.Check)-$30];
{kpPutHeader uses aBlockNum so we'll need to change it temporarily}
Save := aBlockNum;
aBlockNum := Seq;
kpPutHeader(P, KAck, B);
{Put checksum}
kpSendBlockCheck(P);
{Put terminator}
kpSendTerminator(P);
aBlockNum := Save;
end;
end;
function kpDataCount(P : PProtocolData; Index : Byte) : Cardinal;
{-Count actual data characters in slot Index}
var
TIndex : Cardinal;
DIndex : Cardinal;
LastIndex : Cardinal;
RepeatCnt : Cardinal;
C : Char;
begin
with P^ do begin
{Set starting indexes}
TIndex := Cardinal(Index-1)*aBlockLen;
LastIndex := Integer(TIndex)+kInfoTable[Index].Len;
DIndex := 1;
{Loop through this block in kDataTable...}
repeat
{Get a character with escaping already translated}
kpGetDataChar(P, C, TIndex, RepeatCnt);
Inc(DIndex, RepeatCnt);
until (TIndex = LastIndex);
{Commit last, or only, block}
kpDataCount := DIndex-1;
end;
end;
procedure kpProcessDataPacket(P : PProtocolData);
{-Process received data packet}
var
I : Cardinal;
Count : Cardinal;
begin
with P^ do begin
aProtocolError := ecOK;
if (kpSeqGreater(P, kRecBlockNum, kpLoSeq(P)) or (kRecBlockNum = kpLoSeq(P))) and
(kpSeqGreater(P, kpHiSeq(P), kRecBlockNum) or (kRecBlockNum = kpHiSeq(P))) then begin
{Acceptable data packet}
kpAddToTable(P, kRecBlockNum);
{Exit on errors, will be handled by state machine}
if aProtocolError <> ecOK then
Exit;
{Nak missing packets}
if kpSeqGreater(P, kRecBlockNum, aBlockNum) then begin
I := aBlockNum;
repeat
kpSendNak(P);
I := Inc64(I);
until I = kRecBlockNum;
end else if kRecBlockNum = aBlockNum then begin
{Adjust status variables}
Count := kpDataCount(P, kTableHead);
Inc(aBytesTransferred, Count);
Dec(aBytesRemaining, Count);
aElapsedTicks := ElapsedTime(aTimer);
end;
{Ack the packet we got}
kpSendAck(P, kRecBlockNum);
{Expect next highest sequence beyond highest table entry}
aBlockNum := Inc64(kInfoTable[kTableHead].Seq);
end else begin
{Unacceptable block number, ignore it}
aBlockNum := aBlockNum;
end;
end;
end;
function kpIncTableIndex(P : PProtocolData; Index, Increment : Byte) : Byte;
{-Increment table index, wrap at table size}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -