Author Topic: Using Modbus Register Bits in Controls  (Read 15002 times)

DougLyons

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Using Modbus Register Bits in Controls
« on: November 15, 2014, 10:36:02 AM »
Hi Archie,

It would be really great if you could accommodate some of the Modbus community on this.
The ability to address a Modbus Register Bit where you need a Boolean in the controls would be nice.
It was actually fairly easy to do in version 3.70, but now in 3.80 the PLCAddress has moved inside the driver.
This means that it is not as easy to handle the PLCAddress to set up polling and then decode the bits of the data.

For Example on the BasicIndicator if the PLCAddressSelectColor2 could contain "40001.1" to use Bit 1.
This could be extended to all of the 16 bits with the highest being accessed using "40001.16".
I have been able to make this work by modifying the PolledDataReturned and adding a BitTest.
Unfortunately it fails when the bit number goes beyond one digit, so 10, 11, ..16 do not work.

Here is my code to show you want I was trying to do:

Code: [Select]
    Private Sub PolledDataReturned(ByVal sender As Object, ByVal e As SubscriptionHandlerEventArgs)
        If e.PLCComEventArgs.ErrorId = 0 Then
            Try
                Dim TempValue As Boolean
                '* Write the value to the property that came from the end of the PLCAddress... property name
                If e.SubscriptionDetail.PLCAddress.IndexOf(".") = 5 And _
                    Val(Mid(e.SubscriptionDetail.PLCAddress, 6)) > 0 And _
                    sender.ToString.ToUpper.IndexOf("MODBUS") >= 0 Then
                    TempValue = BitTest(e.PLCComEventArgs.Values(0), _
                    Val("&H" & Mid(e.PLCComEventArgs.PlcAddress, 7)))
                    Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet). _
                        SetValue(Me, Convert.ChangeType(TempValue, _
                        Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet).PropertyType), Nothing)
                Else
                    Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet). _
                                SetValue(Me, Convert.ChangeType(e.PLCComEventArgs.Values(0), _
                                Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet).PropertyType), _
                                Nothing)
                End If
            Catch ex As Exception
            DisplayError("INVALID VALUE RETURNED!" & e.PLCComEventArgs.Values(0))
        End Try
        Else
        DisplayError("Com Error. " & e.PLCComEventArgs.ErrorMessage)
        End If
    End Sub
    Private Function BitTest(Number As Long, bit As Integer) As Boolean
        If bit = 16 Then
            BitTest = ((Number < 0) * -1.0)             ' Bit 16 (High Bit)
        Else
            BitTest = ((Number And 2 ^ (bit - 1)) <> 0) * -1
        End If
    End Function

I know that my code is not the best, but you should be able to make any necessary changes easily.

It appears that if you changed the internals of the driver to accept Modbus addresses from 5-8 characters this would work.
I have attached a copy of the output showing the error when using the high bit.

Is it possible that you could change the driver to allow this syntax?
If that were the case, then it would be easy to start adding the additional code to handle this one control at a time.
The code above actually works fine for bits 1 through 9 on the BasicIndicator and seems to prove the concept.

Also, I attempted to use Hex values such as "40001.A", but this caused errors as well.
I have attached a screen capture showing this.

Thanks for all of your work on this project. It is always impressive to me to see it grow.

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5262
    • View Profile
    • AdvancedHMI
Re: Using Modbus Register Bits in Controls
« Reply #1 on: November 15, 2014, 11:08:28 AM »
There are plans to eventually incorporate bit level addressing in the driver, but in the mean time try something like the code below. Note though the bit numbering is from 0 to 15

Code: [Select]
        Dim TempValue As Boolean
        Dim PeriodPos As Integer = e.SubscriptionDetail.PLCAddress.LastIndexOf(".")
        If PeriodPos > 3 Then
            Dim BitNumber As Integer = e.SubscriptionDetail.PLCAddress.substring(PeriodPos+1)
            TempValue = CBool(e.PLCComEventArgs.Values(0) And (2 ^ BitNumber))
        Else
            TempValue = e.PLCComEventArgs.Values(0)
        End If

        Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet). _
                SetValue(Me, Convert.ChangeType(TempValue, _
                Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet).PropertyType), Nothing)

DougLyons

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Using Modbus Register Bits in Controls
« Reply #2 on: November 15, 2014, 07:54:21 PM »
Archie,

This is very good. It does work if one is willing to make a few concessions with the Modbus address.
If the bit is 0 to 9 then everything works as expected (Ex: 40001.0 gets the LSB of the word).

A problem appears when using the standard 5 digit Modbus address with a two digit bit address.
Now you have more than 7 characters and you will see a message like that shown my first attachment above.
It says "Address must be 5-7 digits, xxxxx.xx" where the x's represent the address you tried to use.

The work-around is to shorten the Base Modbus address to 4 characters such as the following:

Example 40001.15 becomes 4001.15 and this works fine to get the actual Modbus address of 40001 and bit 15.

Thanks for the suggested code and the quick reply.
It seems that making the change all around would likely have minimum negative effects.
As a further clarification to anyone else who might want to test this code I have these comments.

This code needs to be put into the PolledDataReturned Subroutine for the modified control.
It needs to replace the existing code between the "Try" and the "Catch" statements.
Another important point is that the"0" bit is the least significant bit and the "15" bit is the most significant.

Thanks again for a new feature in the works and a preliminary peek at it.

andrew_pj

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
Re: Using Modbus Register Bits in Controls
« Reply #3 on: December 01, 2014, 01:29:58 AM »
Dear Archie,

I am currently using version 3.8.5, and trying to implement this feature in BasicIndicator.vb
Using the following code (similar as you suggested):

Code: [Select]
Private Sub PolledDataReturned(ByVal sender As Object, ByVal e As SubscriptionHandlerEventArgs)
        If e.PLCComEventArgs.ErrorId = 0 Then
            Try
                Dim TempValue As Boolean
                Dim Value As Integer = e.PLCComEventArgs.Values(0)
                Dim PeriodPos As Integer = e.SubscriptionDetail.PLCAddress.LastIndexOf(".")
                If PeriodPos > 3 Then
                    Dim BitNumber As Integer = e.SubscriptionDetail.PLCAddress.Substring(PeriodPos + 1)
                    TempValue = CBool(Value And (2 ^ BitNumber))
                Else
                    TempValue = e.PLCComEventArgs.Values(0)
                End If

                If e.PLCComEventArgs.Values IsNot Nothing AndAlso e.PLCComEventArgs.Values.Count > 0 Then
                    '* 13-NOV-14 Changed from Convert.ChangeType to CTypeDynamic because a 0/1 would not convert to boolean
                    '* Write the value to the property that came from the end of the PLCAddress... property name
                    Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet). _
                                SetValue(Me, CTypeDynamic(TempValue, _
                                Me.GetType().GetProperty(e.SubscriptionDetail.PropertyNameToSet).PropertyType), Nothing)
                End If
            Catch ex As Exception
                DisplayError("INVALID VALUE!" & ex.Message)
            End Try
        Else
            DisplayError("Com Error " & e.PLCComEventArgs.ErrorId & "." & e.PLCComEventArgs.ErrorMessage)
        End If
    End Sub

The problem:
1. It is always showing FALSE, when using bitNumber 5,6,7,8,9,15.
2. When entering value 32768 (bitNumber 15) or above, error message occurs:
"Failed to write value. Arithmetic operation resulted in an overflow"

After debugging, found out that Value variable is always showing zero (0) at certain bitNumber (5,6,7,8,9,15).
In other cases (bitNumber 0,1,2,3,4,10,11,12,13,14), Value is showing exact same value as entered.

Please advise solution regarding this issue.
Thank you.

(** NOTE: I try to upload attachment (64KB only). But error message occurs:
"The upload folder is full. Please try a smaller file and/or contact an administrator." )

Best regards,
Andrew
« Last Edit: December 01, 2014, 01:34:22 AM by andrew_pj »

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5262
    • View Profile
    • AdvancedHMI
Re: Using Modbus Register Bits in Controls
« Reply #4 on: December 01, 2014, 08:03:31 AM »
32768 cannot be written because the value is a signed integer and only the range -32768 through 32767 is accepted.

What do you get if you add a BasicLabel with the address and no bit designation, for example "40001"
Then add the BasicIndicator with the addresss 40001.5
Set the 40001 address to a value of 32 (bit 5)

I did a quick test and it is returning a True for me.

DougLyons

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Using Modbus Register Bits in Controls
« Reply #5 on: December 01, 2014, 08:08:00 AM »
andrew_pj,

I have had similar problems recently.

Unfortunately the ModbusTcpCom functionality will not even read a simple 40001 register into a DigitalPanelMeter since version 3.83. I tested 3.83 and it worked fine, but 3.84 and 3.85 both fail to even read a value. They give an error of "Illegal Modbus Address".

Hopefully Archie will be able to address these problems soon. I think it is likely that once this is fixed, the Bit reads will work again with the code modifications. If you can go back to a previous version that is 3.83 or before, you should be OK.

I tried to upload a picture of the error, but I received an error that the upload folder was full.
« Last Edit: December 01, 2014, 08:10:05 AM by DougLyons »

andrew_pj

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
Re: Using Modbus Register Bits in Controls
« Reply #6 on: December 01, 2014, 09:33:50 PM »
Dear Archie,

I just try out version 3.8.6, thanks for adding this feature.

However, got an error on reading bitNumber 2 and above (40001.2, 40001.3, ..., 40001.14)
BitNumber 0 and 1 works fine (40001.0, 40001.1)
The error is "Invalid Address 40001.X - Invalid bit number in address"
(** NOTE ** X = 2,3,4,5,6,7,8,9,10,11,12,13,14 )


Best regards,
Andrew

andrew_pj

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
Re: Using Modbus Register Bits in Controls
« Reply #7 on: December 01, 2014, 09:47:39 PM »
andrew_pj,

I have had similar problems recently.

Unfortunately the ModbusTcpCom functionality will not even read a simple 40001 register into a DigitalPanelMeter since version 3.83. I tested 3.83 and it worked fine, but 3.84 and 3.85 both fail to even read a value. They give an error of "Illegal Modbus Address".

Hopefully Archie will be able to address these problems soon. I think it is likely that once this is fixed, the Bit reads will work again with the code modifications. If you can go back to a previous version that is 3.83 or before, you should be OK.

I tried to upload a picture of the error, but I received an error that the upload folder was full.

Dear DougLyons,

In version 3.8.6, and there is no issue using ModbusTCPCom with any components, including DigitalPanelMeter.
I use MOD_RSSIM version 8.20, Modbus TCP/IP Address 127.0.0.1


Best regards,
Andrew


Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5262
    • View Profile
    • AdvancedHMI
Re: Using Modbus Register Bits in Controls
« Reply #8 on: December 02, 2014, 07:40:48 AM »
I just try out version 3.8.6, thanks for adding this feature.

However, got an error on reading bitNumber 2 and above (40001.2, 40001.3, ..., 40001.14)
BitNumber 0 and 1 works fine (40001.0, 40001.1)
The error is "Invalid Address 40001.X - Invalid bit number in address"
(** NOTE ** X = 2,3,4,5,6,7,8,9,10,11,12,13,14 )
This is what I get for trusting my code and not testing. Attached is a patch that should fix this.

Extract the attached file and replace the one found in AdvancedHMIDrivers\Support folder

DougLyons

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Using Modbus Register Bits in Controls
« Reply #9 on: December 02, 2014, 08:39:45 AM »
Archie,

My preliminary testing indicates that this has fixed the errors that I was seeing.
Do you think that it would be a good idea to post a new version on SourceForge?

Thanks for the quick response and great work.

andrew_pj

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
Re: Using Modbus Register Bits in Controls
« Reply #10 on: December 02, 2014, 08:35:00 PM »
I just try out version 3.8.6, thanks for adding this feature.

However, got an error on reading bitNumber 2 and above (40001.2, 40001.3, ..., 40001.14)
BitNumber 0 and 1 works fine (40001.0, 40001.1)
The error is "Invalid Address 40001.X - Invalid bit number in address"
(** NOTE ** X = 2,3,4,5,6,7,8,9,10,11,12,13,14 )
This is what I get for trusting my code and not testing. Attached is a patch that should fix this.

Extract the attached file and replace the one found in AdvancedHMIDrivers\Support folder


Thanks Archie, now the "Invalid bit number" error has gone.
However, I still get the same error that I mentioned previously (on version 3.8.5) about bitNumber 5,6,7,8,9.
When I change the value of address 40001 as 32767, all bits become TRUE, except 40001.5, 40001.6, 40001.7, 40001.8, 40001.9.

After doing some tests, these are my hypothesis:
1. For bitNumber 6,7,8,9, the address is assigned to previous address.
For example:
address 40002 = 64, then 40001.6 becomes TRUE
address 40003 = 128, then 40002.7 becomes TRUE
address 40004 = 256, then 40003.8 becomes TRUE
address 40005 = 512, then 40004.9 becomes TRUE
2. For bitNumber 5, only even number address is linked.
For example:
address 40001 = 32, nothing happen
address 40002 = 32, then 40001.5 becomes TRUE and 40002.5 becomes TRUE
address 40003 = 32, nothing happen
address 40004 = 32, then 40003.5 becomes TRUE and 40004.5 becomes TRUE
address 40005 = 32, nothing happen

Please advise the solution regarding this.
Thank you.


Best regards,
Andrew

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5262
    • View Profile
    • AdvancedHMI
Re: Using Modbus Register Bits in Controls
« Reply #11 on: December 02, 2014, 09:07:17 PM »
I found some straggling code that should have been deleted. Try this base driver patch to see if it corrects the problem

andrew_pj

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
Re: Using Modbus Register Bits in Controls
« Reply #12 on: December 02, 2014, 09:25:40 PM »
I found some straggling code that should have been deleted. Try this base driver patch to see if it corrects the problem

Yes, now everything works as it should be.
Thanks Archie, Great work!


Best regards,
Andrew

DougLyons

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Re: Using Modbus Register Bits in Controls
« Reply #13 on: December 04, 2014, 01:01:41 AM »
32768 cannot be written because the value is a signed integer and only the range -32768 through 32767 is accepted.

Archie,

From what I can see the above statement was true through version 3.85.
But with version 3.86 things seem to have changed.
Where before the Modbus registers were returning -32768 to 32767 now they return 0 to 65535.

I have attached a picture showing some examples. I copied a similar pattern to what andrew_pj used.
I noticed that his highest bit was 14, but I have included up to 15 to show all of the bits.

The HEX value is just a formula running in a DataSubscriber like the following:

Label1.Text = Mid("000" & (Hex(e.Values(0))), Len(Hex(e.Values(0))))

This is such a great program and allows a wonderful amount of flexibility since it is based on Visual Basic code.
Thanks for all of you work on this. I know that you must spend quite a bit of time on this.

andrew_pj

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
Re: Using Modbus Register Bits in Controls
« Reply #14 on: December 04, 2014, 03:29:22 AM »
32768 cannot be written because the value is a signed integer and only the range -32768 through 32767 is accepted.

Archie,

From what I can see the above statement was true through version 3.85.
But with version 3.86 things seem to have changed.
Where before the Modbus registers were returning -32768 to 32767 now they return 0 to 65535.

I have attached a picture showing some examples. I copied a similar pattern to what andrew_pj used.
I noticed that his highest bit was 14, but I have included up to 15 to show all of the bits.

The HEX value is just a formula running in a DataSubscriber like the following:

Label1.Text = Mid("000" & (Hex(e.Values(0))), Len(Hex(e.Values(0))))

This is such a great program and allows a wonderful amount of flexibility since it is based on Visual Basic code.
Thanks for all of you work on this. I know that you must spend quite a bit of time on this.

Dear DougLyons,

I used MOD_RSsim v8.20 to test this.
I modify 40001 value in MOD_RSsim into 32768, then bit 40001.15 becomes TRUE.
So, you are right, it seems now the range is 0 to 65535.
This is what I expected in the first place.

However, when I try modifying from AHMI by entering value of 32768 or above, using DigitalPanelMeter, I get the following error:
"Failed to write value. Arithmetic operation resulted in an overflow."
Do you get the same thing?


Best regards,
Andrew