views:

449

answers:

2

I'm testing DelphiModbus library on Delphi 2009 and don't get quite the results I want. I think the problem lies with the following line on IdModbusClient.pas:

Move(Buffer, ReceiveBuffer, iSize);

It looks like ReceiveBuffer is set to some garbage.

Buffer is defined as TIdBytes (from Indy components)

ReceiveBuffer is defined as TCommsBuffer:

  TModBusFunction = Byte;

  TModBusDataBuffer = array[0..256] of Byte;

  TCommsBuffer = packed record
    TransactionID: Word;
    ProtocolID: Word;
    RecLength: Word;
    UnitID: Byte;
    FunctionCode: TModBusFunction;
    MBPData: TModBusDataBuffer;
    Spare: Byte;
  end; { TCommsBuffer }

And iSize is of course the size of the Buffer in bytes.

I wonder if this has anything to do with unicode conversion?

A: 
Ken White
That doesn't compile, error message: [DCC Error] IdModBusClient.pas(296): E2017 Pointer type required
Harriv
You're absolutely right. Teach me to read slowly before posting; I look less foolish that way. :-(How are TModBufDataBuffer and TModBusFunction defined?
Ken White
Those are just bytes, single byte and array. I edited the original question.
Harriv
Hmm, try setting buffer to some initial value and only copying that to the ReceiveBuffer. I've a feeling that Move doesn't consider Buffer as a starting point for the actual data. I can't test this until Monday.
Harriv
+4  A: 

Indy's TIdBytes type is a dynamic array, defined in IdGlobal.pas:

type
  TIdBytes = array of Byte;

You can't pass a variable of that type directly to Move and expect it to work because it will only copy the four-byte reference stored in that variable. (And if you told it to copy more than four bytes, then it will proceed to copy whatever else resides in memory after that variable — who knows what.) Given these declarations:

var
  Buffer: TIdBytes;
  ReceiveBuffer: TCommsBuffer;

The way to call Move on those variables is like this:

if Length(Buffer) > 0 then
  Move(Buffer[0], ReceiveBuffer, iSize);

It works like that because Move's parameters are untyped, so you need to pass the value that you want to copy, not a pointer or reference to the value. The compiler handles the referencing by itself.

The code is a little weird because it looks like you're just copying one byte out of Buffer, but don't let it bother you too much. It's a Delphi idiom; it's just the way it works.

Also, this has nothing to do with Delphi 2009; it's worked this way ever since Delphi 4, when dynamic arrays were introduced. And Move has been this way forever.

Rob Kennedy
Thanks, that makes sense. I wonder if that library has ever worked with Indy 10, for which this code is specific. I'll have to test later.
Harriv