Expressions on all properties of base tags

Hi!

I just improved the support for expressions in the properties of PascalSCADA tags. At first moment, this feature was only available for the TPLCBlockElement.Index and TPLCStructItem.Index tags/properties. From today, is possible to use expressions on the following tag classes:

  • TPLCTagNumber
  • TPLCStruct
  • TPLCBlock
  • TPLCString

On these tags, is possible use and include in the expression the following properties:

  • PLCRack
  • PLCSlot
  • PLCStation
  • MemFile_DB
  • MemAddress
  • MemSubElement
  • MemReadFunction
  • MemWriteFunction
  • Tag (you can only use this property on expressions in the properties mentioned above)

Below is a video that helps you understand the new feature:

Suggestions for improvements are always welcome!

23 thoughts on “Expressions on all properties of base tags”

    1. If you assign a scale processor in TPLCTagNumber.ScaleProcessor, the property TPLCTagNumber.Value will show the scaled value (engineering value) instead TPLCTagNumber.ValueRaw still showing the original value, read from your device.

    1. Insert a TLinearScaleProcessor on your application

      Configure it

      On your tags that will use the same scale, set the property ScalProcessor of your tags to the TLinearScaleProcessor created on the first step

      Note that a single Scale processor component (TLinearScaleProcessor, TUserScale) can be shared across multiples tags.

  1. Hi Fabio,

    What are different for any write method on:
    TPLCTagnumber, TPLCBlock, TPLCBloctElement since of all them use same parameters….
    procedure Write(Values:TArrayOfDouble; Count, Offset:Cardinal); override;
    Should we write from TPLCBlock or from Element ?

    Thank you

  2. Depends of what you want to do. But in summary, all synchronous writes will be redirected to the

    procedure Write(Values:TArrayOfDouble; Count, Offset:Cardinal); override;

    And the parameters will depend of your tag class and size (and offset or index, if you are doing that from a TPLCStructElement or a TPLCBlockElement).

    This way allows you to map only the first element of a big block using a TPLCTagNumber, to use it to write a big data block using the procedure write mentioned above.

    But as I wrote, depends of what you want to do…

    1. Hi Fabio,

      Thank you for your explanation.
      From your explanation, we able to write block of memories address just using TPLCTagNumber.Write, but also using TPLCBlock.Write with same parameters.

      For Offset parameter, please kindly explain clearly since we have already TArrayOfDouble and count.

      Thank you

  3. Hi Fabio,

    We have block of memories in Arduino (15 location, 4 byte: addr from 0 – 14), Slave ID of Arduino is 1.
    if we want write 1 location addr 2 only, should we configure:
    PLCStation : 1
    MemAddress : 2
    Size : 1
    TPLCTagNumber.Write(Value,1,offset);
    Is it correct except “offset – still not clear” ?

    Thank you

    1. Hi Fabio,

      We continue with block of memories in Arduino (15 location, 4 byte: addr from 0 – 14), Slave ID of Arduino is 1.
      if we want write 3 location addr from 10 – 12, should we configure:
      PLCStation : 1
      MemAddress : 10
      Size : 3
      We should use TPLCBlock.Write(Value-array,3,offset), instead of TPLCTagNumber…….
      Is it correct except “offset – still not clear” ?

      For moment time we have able to read and write from Autoread/AutoWrite set to true.

      Thank you

    1. Hi Fabio,

      Our Configuration:
      SerialPortDriverMB: TSerialPortDriver;
      BaudRate : br9600
      COMPort: COM5
      DataBits:db8
      Noparity
      Stopbits:sb2

      ModBusRTUDriverArdu: TModBusRTUDriver;
      CommunicationPort:SerialPortDriverMB

      ArduRlBlockOpr: TPLCBlock;
      ProtocolDriver:ModBusRTUDriverArdu
      PLCStation:1 (same as Arduino)
      MemAddress:2
      Size:2
      MemReadFuntion:3
      MemWriteFuntion:16

      In the Arduino side:
      Slave Addr:1
      Block of memories in Arduino (15 location, 4 byte: addr from 0 – 14)

      And we used following code that doesn’t work:

      procedure TfrmDiag.BtnSendModbusClick(Sender: TObject);
      var
      val: TArrayOfDouble;
      begin
      SetLength(val, 2);
      val[1] := dataToArdu.STATE;
      val[2] := dataToArdu.RESET;
      bankTag.ArduRlBlockOpr.Write(val,2,0);
      BtnSendModbus.Enabled:=false;
      end;

      But working as well if we configure AutoRead/AutoWrite to true

      Thank you

  4. Hi Fabio,

    We continue with our own experiment with “Write” method.
    The following code look doesn’t work.

    procedure TfrmDiag.BtnSendModbusClick(Sender: TObject);
    var
    val: TArrayOfDouble;
    begin
    SetLength(val, 2);
    val[1] := dataToArdu.STATE;
    val[2] := dataToArdu.RESET;
    bankTag.ArduRlBlockOpr.Write(val,2,0);
    BtnSendModbus.Enabled:=false;
    end;

    Any Idea for it ?

    Thank you

  5. Thanks by your feedback.

    Now that I know your config, is more easy to you explain how offset works.

    On Modbus (RTU/TCP) the TagType pttDefault have 16 bits of length on functions 3 and 16, and no type conversion are made when receiving or sending values.

    So, if the MemAddress of your tag (with TagType=pttDefault or tagType=pttSmallInt or TagType=pttWord, using modbus) is equal to 0, the offset=2 will simple start the write on modbus register 2 instead of 0, with Count registers of lenght.

    But assuming that you are using 32 bits of length tags (TagType=pttLongInt, TagType=pttDWord or TagType=pttFloat) the offset will calculated:

    RealMemAddress:=(SizeOfTag/SizeOfTargetArea)*Offset;

    Writing on modbus holding registers (MemWriteFunction=16):

    pttLongInt size = 32 bits;
    MemWriteFunction=16 on Modbus Size: 16 bits
    Offset = 2
    RealMemAddress := (32 / 16) * 2;

    So, the write of one LongInt tag will start at holding register 4;

    The size of datablock that will be written is:
    RealSize :=(SizeOfTag/SizeOfTargetArea)*Count;

    Writing the same example above, with Count=5, will result:
    RealSize :=(32/16)*5;

    So doing:
    MyTagLongInt.Write(ArrayWith5LongIntValues,5,2);

    Will write 10 words, at the holding register MyTagLongInt.MemAddress + 4.

    To help you, enable the log of the data exchanged between PascalSCADA and your Arduino by doing:

    SerialPortDriverMB.LogFile := ‘c:\some path\some log file name.txt’
    SerialPortDriverMB.LogIOActions := true;

    Ahhh, Do you have activated your SerialPort? To activate it do?

    SerialPortDriverMB.Active := true;

    on your Form.OnFormCreate event

  6. Another thing:

    You should use a TPLCBlock instead of TPLCTagNumber, because the Write of TPLCTagNumber, the count and offset are hardcoded to 1 and 0, respectively.

  7. Hi Fabio,

    How do we resolve “Error reading SerialPortDriver” when application (PasccalScada) if Modbus-RTU devices are not connected to Host (Master) ?

    Thank You.

    1. Is simple. First of all, leave the property SerialPort.COMPort empty at design time. On your Form Create event put the following code:

      try
      SerialPort.COMPort := ‘COM5’;
      SerialPort.Active := true;
      except
      //show some message telling about the missing serial port…
      end;

Leave a Reply

Your email address will not be published. Required fields are marked *