1 | unit UCommDelay;
|
---|
2 |
|
---|
3 | {$mode Delphi}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, UCommPin, UThreading, SyncObjs, SpecializedList, UStreamHelper;
|
---|
9 |
|
---|
10 | type
|
---|
11 | TCommDelay = class;
|
---|
12 |
|
---|
13 | { TDelayedPacket }
|
---|
14 |
|
---|
15 | TDelayedPacket = class
|
---|
16 | ReceiveTime: TDateTime;
|
---|
17 | Data: TStreamHelper;
|
---|
18 | constructor Create;
|
---|
19 | destructor Destroy; override;
|
---|
20 | end;
|
---|
21 |
|
---|
22 | { TCommDelayThread }
|
---|
23 |
|
---|
24 | TCommDelayThread = class(TTermThread)
|
---|
25 | Parent: TCommDelay;
|
---|
26 | procedure Execute; override;
|
---|
27 | end;
|
---|
28 |
|
---|
29 | { TCommDelay }
|
---|
30 |
|
---|
31 | TCommDelay = class
|
---|
32 | private
|
---|
33 | FActive: Boolean;
|
---|
34 | FDelay: TDateTime;
|
---|
35 | PacketQueue1: TListObject; // TListObject<TDelayedPacket>
|
---|
36 | PacketQueue2: TListObject; // TListObject<TDelayedPacket>
|
---|
37 | Thread: TCommDelayThread;
|
---|
38 | procedure ReceiveData1(Sender: TCommPin; AStream: TStream);
|
---|
39 | procedure ReceiveData2(Sender: TCommPin; AStream: TStream);
|
---|
40 | procedure SetActive(AValue: Boolean);
|
---|
41 | public
|
---|
42 | Lock: TCriticalSection;
|
---|
43 | Pin1: TCommPin;
|
---|
44 | Pin2: TCommPin;
|
---|
45 | constructor Create;
|
---|
46 | destructor Destroy; override;
|
---|
47 | property Delay: TDateTime read FDelay write FDelay;
|
---|
48 | property Active: Boolean read FActive write SetActive;
|
---|
49 | end;
|
---|
50 |
|
---|
51 | implementation
|
---|
52 |
|
---|
53 | { TCommDelayThread }
|
---|
54 |
|
---|
55 | procedure TCommDelayThread.Execute;
|
---|
56 | var
|
---|
57 | I: Integer;
|
---|
58 | CurrentTime: TDateTime;
|
---|
59 | SendData: TStreamHelper;
|
---|
60 | begin
|
---|
61 | try
|
---|
62 | SendData := TStreamHelper.Create;
|
---|
63 | repeat
|
---|
64 | with Parent do begin
|
---|
65 | try
|
---|
66 | Lock.Acquire;
|
---|
67 | CurrentTime := Now;
|
---|
68 | for I := PacketQueue1.Count - 1 downto 0 do
|
---|
69 | if TDelayedPacket(PacketQueue1[I]).ReceiveTime < (CurrentTime - Delay) then begin
|
---|
70 | SendData.Clear;
|
---|
71 | SendData.WriteStream(TDelayedPacket(PacketQueue1[I]).Data, TDelayedPacket(PacketQueue1[I]).Data.Size);
|
---|
72 | PacketQueue1.Delete(I);
|
---|
73 | try
|
---|
74 | Lock.Release;
|
---|
75 | Pin1.Send(SendData.Stream);
|
---|
76 | finally
|
---|
77 | Lock.Acquire;
|
---|
78 | end;
|
---|
79 | end;
|
---|
80 |
|
---|
81 | for I := PacketQueue2.Count - 1 downto 0 do
|
---|
82 | if TDelayedPacket(PacketQueue2[I]).ReceiveTime < (CurrentTime - Delay) then begin
|
---|
83 | SendData.Clear;
|
---|
84 | SendData.WriteStream(TDelayedPacket(PacketQueue2[I]).Data, TDelayedPacket(PacketQueue2[I]).Data.Size);
|
---|
85 | PacketQueue2.Delete(I);
|
---|
86 | try
|
---|
87 | Lock.Release;
|
---|
88 | Pin2.Send(SendData.Stream);
|
---|
89 | finally
|
---|
90 | Lock.Acquire;
|
---|
91 | end;
|
---|
92 | end;
|
---|
93 | finally
|
---|
94 | Lock.Release;
|
---|
95 | end;
|
---|
96 | end;
|
---|
97 | if not Terminated then Sleep(1);
|
---|
98 | until Terminated;
|
---|
99 | finally
|
---|
100 | SendData.Free;
|
---|
101 | end;
|
---|
102 | end;
|
---|
103 |
|
---|
104 | { TDelayedPacket }
|
---|
105 |
|
---|
106 | constructor TDelayedPacket.Create;
|
---|
107 | begin
|
---|
108 | Data := TStreamHelper.Create;
|
---|
109 | end;
|
---|
110 |
|
---|
111 | destructor TDelayedPacket.Destroy;
|
---|
112 | begin
|
---|
113 | Data.Free;
|
---|
114 | inherited Destroy;
|
---|
115 | end;
|
---|
116 |
|
---|
117 | { TCommDelay }
|
---|
118 |
|
---|
119 | procedure TCommDelay.ReceiveData1(Sender: TCommPin; AStream: TStream);
|
---|
120 | begin
|
---|
121 | try
|
---|
122 | Lock.Acquire;
|
---|
123 | if Delay = 0 then Pin2.Send(AStream)
|
---|
124 | else
|
---|
125 | with TDelayedPacket(PacketQueue2.AddNew(TDelayedPacket.Create)) do begin
|
---|
126 | ReceiveTime := Now;
|
---|
127 | Data.WriteStream(AStream, AStream.Size);
|
---|
128 | end;
|
---|
129 | finally
|
---|
130 | Lock.Release;
|
---|
131 | end;
|
---|
132 | end;
|
---|
133 |
|
---|
134 | procedure TCommDelay.ReceiveData2(Sender: TCommPin; AStream: TStream);
|
---|
135 | begin
|
---|
136 | try
|
---|
137 | Lock.Acquire;
|
---|
138 | if Delay = 0 then Pin1.Send(AStream)
|
---|
139 | else
|
---|
140 | with TDelayedPacket(PacketQueue1.AddNew(TDelayedPacket.Create)) do begin
|
---|
141 | ReceiveTime := Now;
|
---|
142 | Data.WriteStream(AStream, AStream.Size);
|
---|
143 | end;
|
---|
144 | finally
|
---|
145 | Lock.Release;
|
---|
146 | end;
|
---|
147 | end;
|
---|
148 |
|
---|
149 | procedure TCommDelay.SetActive(AValue: Boolean);
|
---|
150 | begin
|
---|
151 | if FActive = AValue then Exit;
|
---|
152 | FActive := AValue;
|
---|
153 | if AValue then begin
|
---|
154 | Thread := TCommDelayThread.Create(True);
|
---|
155 | Thread.FreeOnTerminate := False;
|
---|
156 | Thread.Parent := Self;
|
---|
157 | Thread.Name := 'CommDelay';
|
---|
158 | Thread.Start;
|
---|
159 | end else begin
|
---|
160 | FreeAndNil(Thread);
|
---|
161 | end;
|
---|
162 | end;
|
---|
163 |
|
---|
164 | constructor TCommDelay.Create;
|
---|
165 | begin
|
---|
166 | Lock := TCriticalSection.Create;
|
---|
167 | PacketQueue1 := TListObject.Create;
|
---|
168 | PacketQueue2 := TListObject.Create;
|
---|
169 | Pin1 := TCommPin.Create;
|
---|
170 | Pin1.OnReceive := ReceiveData1;
|
---|
171 | Pin2 := TCommPin.Create;
|
---|
172 | Pin2.OnReceive := ReceiveData2;
|
---|
173 | end;
|
---|
174 |
|
---|
175 | destructor TCommDelay.Destroy;
|
---|
176 | begin
|
---|
177 | Active := False;
|
---|
178 | Pin2.Free;
|
---|
179 | Pin1.Free;
|
---|
180 | PacketQueue1.Free;
|
---|
181 | PacketQueue2.Free;
|
---|
182 | Lock.Free;
|
---|
183 | inherited Destroy;
|
---|
184 | end;
|
---|
185 |
|
---|
186 | end.
|
---|
187 |
|
---|