source: PinConnection/CommFrame.pas

Last change on this file was 575, checked in by chronos, 5 months ago
  • Modified: Remove U prefix from unit names of PinConnection package.
File size: 5.7 KB
Line 
1unit CommFrame;
2
3interface
4
5uses
6 Classes, Dialogs, SysUtils, SpecializedList, BinarySerializer,
7 CommPin;
8
9type
10 TFrameState = (fsOutside, fsStart, fsInside, fsEnd);
11
12 { TCommFrame }
13
14 TCommFrame = class(TCommNode)
15 private
16 LastCharIsSpecialChar: Boolean;
17 ReceiveBuffer: TBinarySerializer;
18 FrameState: TFrameState;
19 FFrameErrorCount: Integer;
20 FCRCErrorCount: Integer;
21 function GetStreamCRC8(Stream: TListByte): Byte;
22 procedure RawDataReceive(Sender: TCommPin; Stream: TListByte);
23 procedure RawSetStatus(Sender: TCommPin; Status: Integer);
24 procedure FrameDataReceive(Sender: TCommPin; Stream: TListByte);
25 procedure FrameSetStatus(Sender: TCommPin; Status: Integer);
26 public
27 RawDataPin: TCommPin;
28 FrameDataPin: TCommPin;
29 PacketLoss: Real;
30 SpecialChar: Byte;
31 ControlCodeFrameStart: Byte;
32 ControlCodeFrameEnd: Byte;
33 ControlCodeSpecialChar: Byte;
34 function ComputeRawSize(DataStream: TListByte): Integer;
35 constructor Create(AOwner: TComponent); override;
36 destructor Destroy; override;
37 property FrameErrorCount: Integer read FFrameErrorCount;
38 property CRCErrorCount: Integer read FCRCErrorCount;
39 end;
40
41
42implementation
43
44{ TCommFrame }
45
46constructor TCommFrame.Create(AOwner: TComponent);
47begin
48 inherited;
49 ReceiveBuffer := TBinarySerializer.Create;
50 ReceiveBuffer.List := TListByte.Create;
51 ReceiveBuffer.OwnsList := True;
52 RawDataPin := TCommPin.Create;
53 RawDataPin.OnReceive := RawDataReceive;
54 RawDataPin.Node := Self;
55 FrameDataPin := TCommPin.Create;
56 FrameDataPin.OnReceive := FrameDataReceive;
57 FrameDataPin.Node := Self;
58 PacketLoss := 0;
59 SpecialChar := $fe;
60 ControlCodeFrameStart := $fd;
61 ControlCodeFrameEnd := $fc;
62 ControlCodeSpecialChar := $fb;
63end;
64
65destructor TCommFrame.Destroy;
66begin
67 FreeAndNil(RawDataPin);
68 FreeAndNil(FrameDataPin);
69 FreeAndNil(ReceiveBuffer);
70 inherited;
71end;
72
73procedure TCommFrame.FrameDataReceive(Sender: TCommPin; Stream: TListByte);
74var
75 RawData: TBinarySerializer;
76 I: Integer;
77 Character: Byte;
78 CRC: Byte;
79begin
80 // Write CRC code to end of frame
81 CRC := GetStreamCRC8(Stream);
82
83 // Byte stuffing
84 try
85 RawData := TBinarySerializer.Create;
86 RawData.List := TListByte.Create;
87 RawData.OwnsList := True;
88 RawData.WriteByte(SpecialChar);
89 RawData.WriteByte(ControlCodeFrameStart);
90 for I := 0 to Stream.Count - 1 do begin
91 Character := Stream[I];
92 if Character = SpecialChar then begin
93 RawData.WriteByte(SpecialChar);
94 RawData.WriteByte(ControlCodeSpecialChar);
95 end else RawData.WriteByte(Character);
96 end;
97
98 Character := CRC;
99 if Character = SpecialChar then begin
100 RawData.WriteByte(SpecialChar);
101 RawData.WriteByte(ControlCodeSpecialChar);
102 end else RawData.WriteByte(Character);
103
104 RawData.WriteByte(SpecialChar);
105 RawData.WriteByte(ControlCodeFrameEnd);
106 if Random >= PacketLoss then
107 RawDataPin.Send(RawData.List);
108 finally
109 RawData.Free;
110 end;
111end;
112
113procedure TCommFrame.FrameSetStatus(Sender: TCommPin; Status: Integer);
114begin
115 RawDataPin.Status := Status;
116end;
117
118function TCommFrame.ComputeRawSize(DataStream: TListByte): Integer;
119var
120 I: Integer;
121begin
122 Result := 5; // FrameStart + CRC + FrameEnd
123 for I := 0 to DataStream.Count - 1 do
124 if DataStream[I] = SpecialChar then Inc(Result, 2)
125 else Inc(Result, 1);
126end;
127
128procedure TCommFrame.RawDataReceive(Sender: TCommPin; Stream: TListByte);
129var
130 Character: Byte;
131 CRC: Byte;
132 ExpectedCRC: Byte;
133 I: Integer;
134begin
135 for I := 0 to Stream.Count - 1 do begin
136 Character := Stream[I];
137 if LastCharIsSpecialChar then begin
138 if Character = ControlCodeSpecialChar then begin
139 ReceiveBuffer.WriteByte(SpecialChar)
140 end else
141 if Character = ControlCodeFrameStart then begin
142 if FrameState = fsInside then
143 Inc(FFrameErrorCount);
144 ReceiveBuffer.List.Count := 0;
145 ReceiveBuffer.Position := 0;
146 FrameState := fsInside;
147 end else
148 if Character = ControlCodeFrameEnd then begin
149 if FrameState = fsInside then begin
150 // Check CRC
151 if ReceiveBuffer.List.Count > 0 then begin
152 ReceiveBuffer.Position := ReceiveBuffer.List.Count - 1;
153 CRC := ReceiveBuffer.ReadByte;
154 ReceiveBuffer.List.Count := ReceiveBuffer.List.Count - 1;
155 ExpectedCRC := GetStreamCRC8(ReceiveBuffer.List);
156
157 if ExpectedCRC <> CRC then Inc(FCRCErrorCount)
158 else begin
159 //if Random >= PacketLoss then
160 FrameDataPin.Send(ReceiveBuffer.List);
161 end;
162 end else Inc(FCRCErrorCount);
163 end else Inc(FFrameErrorCount);
164 FrameState := fsOutside;
165 end;
166 LastCharIsSpecialChar := False;
167 end else begin
168 if Character = SpecialChar then LastCharIsSpecialChar := True
169 else ReceiveBuffer.WriteByte(Character);
170 end;
171 end;
172end;
173
174procedure TCommFrame.RawSetStatus(Sender: TCommPin; Status: Integer);
175begin
176 FrameDataPin.Status := Status;
177end;
178
179function TCommFrame.GetStreamCRC8(Stream: TListByte): Byte;
180var
181 I: Integer;
182 B: Integer;
183 Pom: Byte;
184const
185 Polynom: Byte = $18;
186begin
187 Pom := 0;
188 Result := 0;
189 for I := 0 to Stream.Count - 1 do begin
190 Pom := Stream[I];
191 for B := 0 to 7 do begin
192 if ((Result xor Pom) and 1) = 1 then
193 Result := ((Result xor Polynom) shr 1) or $80
194 else Result := Result shr 1;
195 Pom := (Pom shr 1) or ((Pom shl 7) and $80); // Rotace vpravo
196 end;
197 end;
198end;
199
200end.
Note: See TracBrowser for help on using the repository browser.