source: ISPProgrammer/Dallas/UDallasProgrammer.pas

Last change on this file was 438, checked in by chronos, 12 years ago
  • Modified: Faster write in TPrestoProgrammer using delayed response check of sent commands.
File size: 11.8 KB
Line 
1unit UDallasProgrammer;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, USerialPort, UCommSerialPort, UCommPin, UCommMark,
9 UJobProgressView, SyncObjs, DateUtils, Dialogs, URegistry,
10 Forms, UISPProgrammer, Registry, UBinarySerializer, SpecializedList,
11 UCommTelnet, UCommTelnetComPortOption, UCommConnector;
12
13const
14 Mark = #13#10;
15
16type
17 ETimeout = class(Exception);
18
19 { TDallasProgrammer }
20
21 TDallasProgrammer = class(TISPProgrammer)
22 private
23 FOnLogData: TOnLogDataEvent;
24 Pin: TCommPin;
25 CommMark: TCommMark;
26 ResponseQueue: TListObject;
27 ResponseLock: TCriticalSection;
28 ResponseTemp: TBinarySerializer;
29 ConnectorBackup: TDeviceConnector;
30 ConnectorBackupPin: TCommPin;
31 HexData: TStringList;
32 Request: TBinarySerializer;
33 Mark: TListByte;
34 procedure ReceiveData(Sender: TCommPin; Stream: TListByte);
35 function ReadResponse(Count: Integer = 0): string;
36 function ResponseCount: Integer;
37 procedure ResponseClear;
38 procedure CheckWriteErrorCode(Value: string);
39 procedure CheckResponseErrorCode(Value: string);
40 protected
41 procedure SetActive(AValue: Boolean); override;
42 public
43 Timeout: TDateTime;
44 Identification: string;
45 BaudRate: Integer;
46 Connector: TDeviceConnector;
47 procedure LoadFromRegistry(Root: HKEY; Key: string); override;
48 procedure SaveToRegistry(Root: HKEY; Key: string); override;
49 procedure Read(Job: TJob); override;
50 procedure Write(Job: TJob); override;
51 procedure Erase; override;
52 procedure Verify(Job: TJob); override;
53 procedure Reset; override;
54 function ReadIdentification: string; override;
55 constructor Create; override;
56 destructor Destroy; override;
57 property OnLogData: TOnLogDataEvent read FOnLogData write FOnLogData;
58 end;
59
60implementation
61
62resourcestring
63 STimeout = 'Timeout';
64 //SEmptyBuffer = 'Empty buffer';
65 SInvalidHexFormat = 'Invalid Intel Hex record format';
66 SFlashControllerError = 'Flash controller error';
67 SInvalidRecordAddress = 'Invalid address in Intel Hex record';
68 SInvalidRecordLength = 'Invalid Intel Hex record length';
69 SWriteFailure = 'Failure to write 1s to 0s during programming';
70 SInvalidRecordType = 'Invalid Intel Hex record type';
71 SInvalidRecordChecksum = 'Invalid checksum in Intel Hex record';
72 SVerifyError = 'Verify Error';
73 SInvalidResponse = 'Invalid response';
74 SUnknownProgrammerResponse = 'Unknown flash programmer response "%s"';
75 SIdentification = 'Device identification';
76
77{ TDallasProgrammer }
78
79procedure TDallasProgrammer.ReceiveData(Sender: TCommPin; Stream: TListByte);
80var
81 NewList: TListByte;
82begin
83 try
84 ResponseLock.Acquire;
85 NewList := TListByte.Create;
86 NewList.Assign(Stream);
87 ResponseQueue.Add(NewList);
88 finally
89 ResponseLock.Release;
90 end;
91end;
92
93function TDallasProgrammer.ReadResponse(Count: Integer = 0): string;
94var
95 Serializer: TBinarySerializer;
96 StartTime: TDateTime;
97 ElapsedTime: TDateTime;
98begin
99 StartTime := Now;
100 repeat
101 if Count = 0 then begin
102 if ResponseCount > 0 then Break;
103 end else begin
104 if ResponseCount >= Count then Break;
105 end;
106 Sleep(1);
107 ElapsedTime := Now - StartTime;
108 until (ElapsedTime > Timeout);
109 if ElapsedTime > Timeout then
110 raise Exception.Create(STimeout);
111 try
112 ResponseLock.Acquire;
113 Serializer := TBinarySerializer.Create;
114 Serializer.List := TListByte(ResponseQueue.First);
115 if Count = 0 then
116 Result := Serializer.ReadString(Serializer.List.Count)
117 else Result := Serializer.ReadString(Count);
118 ResponseQueue.Delete(0);
119 finally
120 Serializer.Free;
121 ResponseLock.Release;
122 end;
123end;
124
125function TDallasProgrammer.ResponseCount: Integer;
126begin
127 try
128 ResponseLock.Acquire;
129 Result := ResponseQueue.Count;
130 finally
131 ResponseLock.Release;
132 end;
133end;
134
135procedure TDallasProgrammer.ResponseClear;
136begin
137 try
138 ResponseLock.Acquire;
139 ResponseQueue.Clear;
140 finally
141 ResponseLock.Release;
142 end;
143end;
144
145procedure TDallasProgrammer.SetActive(AValue: Boolean);
146var
147 SerialPort: TCommSerialPort;
148 TelnetOption: TTelnetOptionComPort;
149begin
150 if Active = AValue then Exit;
151 inherited;
152 if AValue then begin
153 Request := TBinarySerializer.Create;
154 Request.List := TListByte.Create;
155 Request.OwnsList := True;
156 HexData := TStringList.Create;
157
158 Connector.Active := False;
159 ConnectorBackup.Assign(Connector);
160 ConnectorBackupPin := Connector.Pin.RemotePin;
161 Connector.Pin.Disconnect;
162 if Connector.ConnectionType = ctSerialPort then begin
163 //SerialPort.Name := SerialPort.Name;
164 Connector.CommSerial.SerialPort.FlowControl := fcNone;
165 Connector.CommSerial.SerialPort.BaudRate := BaudRate;
166 Connector.CommSerial.SerialPort.DTR := True;
167 Connector.CommSerial.SerialPort.Flush;
168 end else
169 if Connector.ConnectionType = ctNetworkClient then begin
170 TelnetOption := TTelnetOptionComPort(Connector.CommTelnet.SearchOption(tmComPortControlOption));
171 TelnetOption.FlowControl := fcNone;
172 TelnetOption.BaudRate := BaudRate;
173 TelnetOption.DTR := True;
174 end;
175 Connector.CommSerial.SerialPort.Purge;
176 Connector.CommTelnet.Purge;
177 Connector.Pin.Connect(CommMark.PinRaw);
178 if Assigned(FOnLogData) then
179 Pin.OnLogData := FOnLogData;
180 CommMark.Active := True;
181 Connector.Active := True;
182 ResponseClear;
183 Sleep(1000);
184 ReadIdentification;
185 end else begin
186 CommMark.Active := False;
187 Connector.Active := False;
188 Connector.Assign(ConnectorBackup);
189 Connector.Pin.Connect(ConnectorBackupPin);
190 Connector.Active := True;
191 HexData.Free;
192 Request.Free;
193 end;
194end;
195
196procedure TDallasProgrammer.CheckWriteErrorCode(Value: string);
197begin
198 if Value = 'H' then raise Exception.Create(SInvalidHexFormat)
199 else if Value = 'F' then raise Exception.Create(SFlashControllerError)
200 else if Value = 'A' then raise Exception.Create(SInvalidRecordAddress)
201 else if Value = 'L' then raise Exception.Create(SInvalidRecordLength)
202 else if Value = 'P' then raise Exception.Create(SWriteFailure)
203 else if Value = 'R' then raise Exception.Create(SInvalidRecordType)
204 else if Value = 'S' then raise Exception.Create(SInvalidRecordChecksum)
205 else if Value = 'V' then raise Exception.Create(SVerifyError)
206 else if Value = '' then raise Exception.Create(SInvalidResponse)
207 else if Value <> 'G' then raise Exception.Create(Format(SUnknownProgrammerResponse, [Value]));
208end;
209
210procedure TDallasProgrammer.CheckResponseErrorCode(Value: string);
211begin
212 if Value <> '' then begin
213 if Value[1] = 'E' then
214 raise Exception.Create('Dallas error: ' + Value);
215 end;
216end;
217
218procedure TDallasProgrammer.LoadFromRegistry(Root: HKEY; Key: string);
219begin
220 with TRegistryEx.Create do
221 try
222 RootKey := Root;
223 OpenKey(Key + '\ISPProgrammer\Dallas', True);
224 BaudRate := ReadIntegerWithDefault('FirmwareBaudRateNumeric', 57600);
225 finally
226 Free;
227 end;
228end;
229
230procedure TDallasProgrammer.SaveToRegistry(Root: HKEY; Key: string);
231begin
232 with TRegistryEx.Create do
233 try
234 RootKey := Root;
235 OpenKey(Key + '\ISPProgrammer\Dallas', True);
236 WriteInteger('FirmwareBaudRateNumeric', Integer(BaudRate));
237 finally
238 Free;
239 end;
240end;
241
242procedure TDallasProgrammer.Read(Job: TJob);
243var
244 Value: string;
245 I: Integer;
246begin
247 Active := True;
248
249 Request.List.Count := 0;
250 ResponseClear;
251 Request.WriteByte(Ord('D'));
252 Pin.Send(Request.List);
253 Value := ReadResponse;
254 Value := ReadResponse; // Empty line
255 CheckResponseErrorCode(Value);
256
257 //HexFile.SaveToStringList(HexData);
258 Job.Progress.Max := 65535 div 32;
259 //Request.Size := 0;
260 //ResponseClear;
261 I := 0;
262 repeat
263 Value := ReadResponse;
264 if Value <> '' then begin
265 //Log(Value);
266 HexData.Add(Value);
267 if Value = ':00000001FF' then Break;
268 Inc(I);
269 end;
270 Job.Progress.Value := I;
271 if Job.Terminate then Break;
272 until False;
273 //for I := 0 to 10 do //HexData.Count - 1 do
274 // Log(HexData[I]);
275 if not Job.Terminate then
276 HexFile.LoadFromStringList(HexData);
277end;
278
279procedure TDallasProgrammer.Verify(Job: TJob);
280var
281 Value: string;
282 I: Integer;
283begin
284 Active := True;
285
286 Request.List.Count := 0;
287 ResponseClear;
288 Request.WriteByte(Ord('V'));
289 Pin.Send(Request.List);
290 ReadResponse;
291
292 try
293 CommMark.Mark.Clear;
294 HexFile.SaveToStringList(HexData);
295 Job.Progress.Max := HexData.Count;
296 for I := 0 to HexData.Count - 1 do begin
297 Request.Clear;
298 ResponseClear;
299 Request.WriteString(HexData[I]);
300 Request.WriteList(Mark, 0, Mark.Count);
301 Pin.Send(Request.List);
302 Value := ReadResponse;
303 CheckWriteErrorCode(Value);
304 Job.Progress.Value := I;
305 if Job.Terminate then Break;
306 end;
307 finally
308 CommMark.Mark.Assign(Mark);
309 end;
310end;
311
312procedure TDallasProgrammer.Write(Job: TJob);
313var
314 Value: string;
315 I: Integer;
316begin
317 Active := True;
318 Request.Clear;
319 ResponseClear;
320 Request.WriteByte(Ord('L'));
321 Pin.Send(Request.List);
322 Value := ReadResponse;
323
324 try
325 CommMark.Mark.Clear;
326 HexFile.SaveToStringList(HexData);
327 Job.Progress.Max := HexData.Count;
328 // Delayed response check mechanism,
329 // to avoid thread sleep(1) to context switch after 16 ms
330 // During 16 ms delay: 57600 / 10 * 0.016 = 97 bytes can be transfered
331 // One line of hex file is 74 bytes long
332 // Then two during context switching next line should be written to output buffer
333 // On I = 0 do not check response
334 // On I = HexData.Count do not send data, only check response
335 ResponseClear;
336 for I := 0 to HexData.Count do begin
337 if I < HexData.Count then begin
338 Request.Clear;
339 Request.WriteString(HexData[I]);
340 Request.WriteList(Mark, 0, Mark.Count);
341 Pin.Send(Request.List);
342 end;
343 if I > 0 then begin
344 Value := ReadResponse;
345 CheckWriteErrorCode(Value);
346 end;
347 Job.Progress.Value := I;
348 if Job.Terminate then Break;
349 end;
350 finally
351 CommMark.Mark.Assign(Mark);
352 end;
353end;
354
355procedure TDallasProgrammer.Erase;
356begin
357 Active := True;
358 Request.Clear;
359 ResponseClear;
360 Request.WriteByte(Ord('K'));
361 Pin.Send(Request.List);
362 CheckResponseErrorCode(ReadResponse);
363end;
364
365procedure TDallasProgrammer.Reset;
366begin
367end;
368
369function TDallasProgrammer.ReadIdentification: string;
370var
371 Value: string;
372begin
373 Result := '';
374 Active := True;
375
376 ResponseClear;
377 Request.Clear;
378 Pin.Send(Request.List);
379 Value := ReadResponse; // Empty line
380 Identification := ReadResponse;
381
382 // Make one empty command to clear possible previous data
383 ResponseClear;
384 Request.Clear;
385 Pin.Send(Request.List);
386 Value := ReadResponse; // Empty line
387
388 Log(SIdentification + ': ' + Identification);
389end;
390
391constructor TDallasProgrammer.Create;
392begin
393 inherited;
394 Capabilities := [ipcErase, ipcRead, ipcWrite, ipcReset];
395 Timeout := 3000 * OneMillisecond;
396 ResponseQueue := TListObject.Create;
397 ResponseLock := TCriticalSection.Create;
398 ResponseTemp := TBinarySerializer.Create;
399 ResponseTemp.List := TListByte.Create;
400 ResponseTemp.OwnsList := True;
401 Pin := TCommPin.Create;
402 Pin.OnReceive := ReceiveData;
403 Mark := TListByte.Create;
404 Mark.SetArray([13, 10]);
405 CommMark := TCommMark.Create(nil);
406 CommMark.Mark.Assign(Mark);
407 CommMark.PinFrame.Connect(Pin);
408 BaudRate := 9600;
409 ConnectorBackup := TDeviceConnector.Create;
410end;
411
412destructor TDallasProgrammer.Destroy;
413begin
414 Active := False;
415 FreeAndNil(Mark);
416 FreeAndNil(CommMark);
417 FreeAndNil(ConnectorBackup);
418 FreeAndNil(Pin);
419 FreeAndNil(ResponseQueue);
420 FreeAndNil(ResponseLock);
421 FreeAndNil(ResponseTemp);
422 inherited;
423end;
424
425end.
426
Note: See TracBrowser for help on using the repository browser.