AdvancedHMI Software
General Category => Feature Request => Topic started by: DougLyons 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:
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.
-
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
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)
-
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.
-
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):
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
-
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.
-
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 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,
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
-
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
-
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.
-
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
-
I found some straggling code that should have been deleted. Try this base driver patch to see if it corrects the problem
-
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
-
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.
-
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
-
andrew_pj,
Yes. I get this same error. You can enter "-1" and you will see "65535" displayed with all bits set.
This appears to be just the difference in whether the 16-bit number is considered signed or unsigned.
In version 3.85 and before both inputs and outputs were handled as signed integers.
Now with version 3.86 it appears that the outputs are handled as unsigned integers and the inputs as signed integers.
Visual Basic has always had problems because of the fact that it is not a strongly typed language.
In the past there was no way to make an integer be unsigned. It was defaulted to signed.
There was no unsigned 16-bit declaration character or way to DIM the variable to unsigned.
This may have improved lately, but I do not know. I am very new to VB.net with much experience in VB6.
As you can imagine you can use "-1" through "-32768" on the keypad to get the full range of numbers with the high bit set.
It would be great if we were allowed to decide whether to use signed or unsigned integers for inputs and outputs.
Maybe this would be a good feature request.
-
Modify ModbusUtilities.vb, in the AdvancedHMIDrivers project, at line 22 to be this code:
'* Loop through extracting each value AND avoid exceeding the number of bytes in the RawData
While (ResultingValuesIndex < address.NumberOfElements) AndAlso (startByte + (Math.Ceiling(ResultingValuesIndex * (address.BitsPerElement / 8))) + BytesPerElement - 1) <= (rawData.Count)
'* Bit or byte read?
If address.BitsPerElement > 1 Then
'Dim Result As Integer = 0
Dim ValueDataBytes(CInt(address.BitsPerElement / 8) - 1) As Byte
'* Ensure there is enought data to process
If rawData.Count >= (startByte + ResultingValuesIndex * BytesPerElement + BytesPerElement) Then
For i = 0 To BytesPerElement - 1
ValueDataBytes(i) = rawData(startByte + ResultingValuesIndex * BytesPerElement + i)
Next
If address.Address.IndexOf("F4", 0, System.StringComparison.InvariantCultureIgnoreCase) >= 0 Then
'* F4 address designates it is a floating point type
ModbusUtilities.SwapBytes(ValueDataBytes, 0)
ModbusUtilities.SwapBytes(ValueDataBytes, 2)
ResultingValues(ResultingValuesIndex) = CStr(BitConverter.ToSingle(ValueDataBytes, 0))
ElseIf address.Address.IndexOf("L4", 0, System.StringComparison.InvariantCultureIgnoreCase) >= 0 Then
'* Convert bytes to a long integer
ModbusUtilities.SwapBytes(ValueDataBytes, 0)
ModbusUtilities.SwapBytes(ValueDataBytes, 2)
ResultingValues(ResultingValuesIndex) = CStr(BitConverter.ToInt32(ValueDataBytes, 0))
Else
ModbusUtilities.SwapBytes(ValueDataBytes, 0)
ResultingValues(ResultingValuesIndex) = CStr(BitConverter.ToInt16(ValueDataBytes, 0))
End If
'* Is a bit number designated?
If address.BitNumber >= 0 Then
ResultingValues(ResultingValuesIndex) = CStr(CBool((CInt(2 ^ address.BitNumber) And CInt(ResultingValues(ResultingValuesIndex))) > 0))
End If
End If
Else
'* It is a bit read, so extract from the byte
'* Byte 0 Bit 0 is always the first bit specified in the address
Dim ByteNumber As Integer = CInt(Math.Floor((ResultingValuesIndex) / 8))
Dim BitNumber As Integer = CInt(((ResultingValuesIndex) / 8 - ByteNumber) * 8)
ResultingValues(ResultingValuesIndex) = CStr(((rawData(ByteNumber + startByte)) And CByte(2 ^ BitNumber)) > 0)
End If
ResultingValuesIndex += 1
End While
-
Archie,
This code does seem to fix the ranges.
I noticed that this is a bit shorter than the old code and leaves out some checks for "F4" and "L4".
Does that mean that you do not handle the Floats and Longs anymore?
Also since the multi-threading improvements I have been getting error messages in the IDE.
when I use the "X" in the upper right-hand window to shut down the running project I received errors such as these:
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
I am guessing that the main form is closing out before some of the threads have a chance to close.
I do not know what happens when the EXE file is run, but I suspect that it would be fine.
I just wanted to let you know about this in case you have a solution.
The result is that you wind up in a debugging mode and then you have to use the "Stop" button to shut the program down.
I think that the poll time is defaulting to a very minimal value because my mod_RSSim shows lots of polls.
Also, my hard disk drive light stays busy and I think that the system is buffering lots of poll data.
Thanks again so much.
Doug Lyons
-
This code does seem to fix the ranges.
I noticed that this is a bit shorter than the old code and leaves out some checks for "F4" and "L4".
Does that mean that you do not handle the Floats and Longs anymore?
The longs and floats are still handled the same. The code was just rearranged and simplified.
Version 3.87 is now posted that rolls up all of these recent drivers modifications.
-
Just download and tested in version 3.89, the attached error appears.
Test the same thing in version 3.87, it works fine.
Please advise, Thank you.
Best regards,
Andrew
-
Change the line of code to this:
DisplayError("INVALID VALUE RETURNED")
-
Just download and tested in version 3.89, the attached error appears.
Test the same thing in version 3.87, it works fine.
A version 3.90 has been posted that should catch and handle this error properly.
-
Thanks Archie, fixed the problem.
A minor issue here, everytime starts the program, there is error message occurs on all objects in the form:
"Com Error - 999. No values return"
This error holds about 5 seconds, then disappear and no longer appears.
But it comes everytime the program starts.
The MOD_RSsim software is running though.
Best regards,
Andrew
-
A minor issue here, everytime starts the program, there is error message occurs on all objects in the form:
"Com Error - 999. No values return"
This error holds about 5 seconds, then disappear and no longer appears.
But it comes everytime the program starts.
The MOD_RSsim software is running though.
I think this is the same problem here:
http://advancedhmi.com/forum/index.php?topic=527.0
Try that code change and let me know if it resolves it.
-
Unfortunately the error still appears.
Trying to debug and identifying the location from the Call Stack, in SubscriptionHandler.vb Line 134.
It seems the IF condition doesn't meet so it will directly point to ELSE which is assigning e.ErrorId = -999
It should be correct that e.Values is Nothing and e.Values.Count is 0 when program just started.
So, perhaps need some additional handler here.
Best regards,
Andrew
-
I'll get an updated posted in a few hours that may fix this
-
Archie, this problem still exists in version 3.91 and 3.92
Always during program starts, this error appears.
Best regards,
Andrew
-
Seems you're having the same issues as I am. Don't know if this helps but v3.87 does not show this error. There are other issues with 3.87 (3.92 has the same issues)but it seems to the most stable version so far.
-
Version 3.93 is now posted. Sorry for all the revisions this week. Implementing bit level access and read optimizing at the same time really opened a can of worms. But I do appreciate the testing and feedback from everyone.
-
Tested version 3.93, result is OK for BasicIndicator with address bit (e.g 40001.0, 40001.1, 40001.2, ...)
However, address 40001, 40002, 40003, etc for DigitalPanelMeter still indicates "Com Error -999" in the beginning.
I try tested with other indicators: Tank, Gauge. Result is same.
Best regards,
Andrew
-
Version 3.94 is posted now and has a couple more fixes to the Modbus drivers
-
Version 3.94 is posted now and has a couple more fixes to the Modbus drivers
Yes! Version 3.94 has no more "Com Error -999"
Thanks for updating.
Best regards,
Andrew
-
Yes! Version 3.94 has no more "Com Error -999"
That's good news to hear. Thanks for all the testing and patience.