Forum > General
failed Memory update of a class object
(1/1)
mas steindorff:
I solved the following issue in my main code with workaround but I was wondering what I did wrong or if someone else has see this error?
I created a class object that basically reads a binary data from a "config file" and decodes it. Within this class, I have a packed record that describes the memory layout of the various binary variables. I then created a ReadFromFile method that works just fine except I need to call it twice in order to make the new values "stick". Otherwise the various object properties returns the previous values. The object's properties read and write using procedures and functions that translate directly from the packed record memory and there is only one of these records. There is only one instance of this config file reader object accessibly to the form but there are other instances on other forms within the program.
When I place a breakpoint in the ReadFromFile code, I see the binary variables update but after the code returns to the form, the calls to the properties fetch old values!
Now the weird part: a second call to ReadFromFile right after the first one has no affect. if I call a function that gets the value from all of the properties and then call the ReadFromFile, the next call to the get values get the correct values! (that is my fix) All of my other code to set values, SaveToFile, work just fine.
Ideas?
Marc:
Please provide some (compilable) sample code
mas steindorff:
OK, first the form code. I've included just my modifications to the automatically generated code. this code expects the form to have a read button and 3 Tedit boxes not included in an attempt to keep this post for getting too big.
--- Code: ---...
Public { Public declarations }
ConfigObj:TConfigObj; // as part of the form
end;
Procedure TFrmConfig.FormCreate(Sender: TObject);
Begin
...
ConfigObj := TConfigObj.Create;
end;
Procedure TFrmConfig.FormDestroy(Sender: TObject);
Begin
ConfigObj.Free;
end;
Procedure TFrmConfig.BtnReadSDClick(Sender: TObject);
var filename:string;
Begin
filename := GetConfigFileName(SD_Device); // "F:Config.dat
// .. more file testing code removed
StatusMessage2('reading...'+filename);
if ConfigObj.ReadFromFile(filename) then
begin
PramToEdit();
ConfigObj.ReadFromFile(filename); // for some reason I need to do a display thing before the read takes hold
PramToEdit(); // this one works
end;
end;
procedure GetParam(var box:TEdit; AValue:double);
begin
box.Text := format(%.2f',[Avalue]);
end;
procedure TFrmconfig.PramToEdit();
begin
GetParam(ed_AcqTime, ConfigObj.uiAcqTime);
GetParam(ed_ProcTime, ConfigObj.uiProcTime);
GetParam(ed_AmpExcReg, ConfigObj.uiAmpDiffExReg);
end;
--- End code ---
========= The configobj is in another unit. I'v reduced the number of parameters down to 3 (1 float and 2 words) but the others follow the same format
--- Code: ---type
F32 = single;
U16 = word;
U8 = byte;
TConfigParmTable = packed record // entree def
prarmCode :U8;
byteoffset :U16; // 0 to 511 (where to find parameters)
size :U16;
end;
TConfigFilePrams = packed record
bidsmode :U8;
PrarmCount:U8;
// first table starts after these bytes
PrarmTable:TConfigParmTable; end;
TConfigFile = record case integer of
0:(Pram:TConfigFilePrams);
1:(raw:array[1..(8*1024)] of U8);
end;
TConfigDAQType = packed record // def DAQ parameters
AcqPts :U16; // rng=[10..500]
ProcPts :U16; // rng=[10..500]
AmpDiffExReg :F32; // rng=[0.0 .. 1.0]
end;
TConfigObj = class
my : record
Tag :integer;
CardType :U8;
DaqParam :TConfigDAQType; // Raw vars live here
fileOK :Boolean;
ConfigFile :TConfigFile;
FileName :string;
end; // of record
private { private declarations }
procedure DecodeConfigTable(Index: Integer);
Procedure SetU16Pts(value: double; Var saveto: U16; min,max:U16);
procedure Showstr(Str: String);
public { public declarations }
Constructor Create;
property Tag :integer read my.tag Write my.tag;
Procedure SetAmpDiffExReg (Const AValue: F32);
Function UIGet_ProcTime : double;
Procedure UISet_ProcTime (Const AValue: double);
Function UIGet_AcqTime : double;
Procedure UISet_AcqTime (Const AValue: double);
...
property uiAcqTime :double Read UIGet_AcqTime Write UISet_AcqTime;
property uiProcTime:double Read UIGet_ProcTime Write UISet_ProcTime;
property uiAmpDiffExReg :F32 Read my.DaqParam.AmpDiffExReg Write SetAmpDiffExReg;
function ReadFromFile(filename:string):Boolean;
End;
implementation
const
sampfreq = 50000.0;
Constructor TConfigObj.Create;
Begin
Inherited Create;
with my do begin
DaqParam.AcqPts := 500;
DaqParam.ProcPts := 500;
DaqParam.AmpDiffExReg := 0.00;
end;
end;
Procedure TConfigObj.SetU16Pts(value:double; var saveto:U16; min,max:U16);
begin
if (value < min) then saveto := min
else if (value > max) then saveto := max
else saveto := round(value);
End;
Function TConfigObj.UIGet_AcqTime: double; // checked
Begin
result := my.DaqParam.AcqPts *1000.0/sampfreq;
End;
Procedure TConfigObj.UISet_AcqTime(Const AValue: double); // checked
var f:double;
Begin
f := trunc(round(AValue*sampfreq/1000.0));
SetU16Pts(f, my.DaqParam.AcqPts, 10, 500);
end;
Function TConfigObj.UIGet_ProcTime: double; // checked
Begin
result := my.DaqParam.ProcPts *1000/sampfreq;
End;
Procedure TConfigObj.UISet_ProcTime(Const AValue: double); // checked
var f:double;
Begin
f := AValue * sampfreq/1000;
SetU16Pts(f, my.DaqParam.ProcPts , 10, 500);
End;
Procedure TConfigObj.SetAmpDiffExReg(Const AValue: F32);
Begin
if (Avalue < 0.0) then my.DaqParam.AmpDiffExReg:=0.0
else if (Avalue > 1.0) then my.DaqParam.AmpDiffExReg:=1.0
else my.DaqParam.AmpDiffExReg:=Avalue;
end;
function Tconfigobj.Readfromfile(filename: String): Boolean;
var fhandle:THandle;
i:integer;
begin
result := FALSE;
my.fileOK:=FALSE;
try
fhandle:=FileOpen(fileName, fmOpenRead+ fmShareDenyNone);
i := FileRead( Fhandle, my.ConfigFile, sizeof(TConfigFile));
if (i < sizeof(my.ConfigFile)) then
exit;
my.fileOK :=TRUE;
my.FileName :=filename; // save just incase I need it
my.CardType := my.ConfigFile.Pram.mode;
for i:=1 to my.ConfigFile.Pram.PrarmCount do begin
DecodeConfigTable(i);
end;
result := TRUE; // good read !! A breakpoint here shows my.DaqParam are equal to the file contents
finally
FileClose(fhandle);
end;
end;
procedure Tconfigobj.BinGetDAQ_params(tbl:TConfigParmTable);
var p:^TConfigDAQType;
begin
p := @my.ConfigFile.raw[tbl.byteoffset+1];
// move(p^, my.DaqParam, sizeof(my.DaqParam));
self.my.DaqParam := p^; // and that all that it takes to read all 32 bytes
end;
procedure Tconfigobj.DecodeConfigTable(index:integer);
var tbl:^TConfigParmTable;
begin
tbl := @my.ConfigFile.Pram.PrarmTable;
inc(tbl, index-1);
case tbl^.prarmCode of
DAQ_param : BinGetDAQ_params(tbl^); // TConfigDAQType
....
else ShowStr(' *** unknown type, no decoder yet ***');
end;
end;
--- End code ---
thank you for looking.
mas
Navigation
[0] Message Index