Datman
Sep 16 2008, 08:50 PM
Hi Guys.
Ive got an application that uses VB6 to get data from a Micrologix1100 using DDE. Occasionally the system needs to write data down to the PLC, usually just 1 integer. Sometimes ( maybe once a day ) this gives a timeout or message que filled error. This is fine, i am using error traps in my vb6 code, and it will halt and try to handle the error. So if such error occurs, i close my DDE Link, and try to reconnect after 5 seconds. This is where the system completely falls over. In the code below, it will get to the linkmode = 2 , then halt with an error ( no foreign application responded to a ddeinitiate ). From here i can go nowhere, it seems that rslinx still has the ddetopic locked, and will not allow access. the only way to solve the issue is to shut down rslinx and run my application again. Is this a problem anyone has seen before? WHen looking at the Server Diagnostics in RSLinx, it says the number of conversations is 1 after an error, even though my application has close all its dde connections. how can i "kill" any dde connections in order to get this thing to reconnect without having to restart RSLinx. hope this makes sense, any help much appreciated.
FrmMain.DDETest.Text = data
FrmMain.DDETest.LinkTopic = "RSLinx|BOARD_GRADER"
'Define DDE application and Topic
FrmMain.DDETest.LinkItem = address
'Define DDE link item
FrmMain.DDETest.LinkMode = 2
'Open DDE link (manual)
FrmMain.DDETest.LinkPoke
'Write data to RSLinx
FrmMain.DDETest.LinkMode = 0
'Close DDE link
Exit Function
trn_psycho
Sep 17 2008, 08:21 AM
Not sure about this, but you may want to add a while loop to make sure the link is closed...
EX:
While FrmMain.DDETest.LinkMode <> 0
FrmMain.DDETest.LinkMode = 0
Wend
Datman
Sep 17 2008, 02:40 PM
QUOTE(trn_psycho @ Sep 18 2008, 01:21 AM) [snapback]73717[/snapback]
Not sure about this, but you may want to add a while loop to make sure the link is closed...
EX:
While FrmMain.DDETest.LinkMode <> 0
FrmMain.DDETest.LinkMode = 0
Wend
ok thanks ill try that. its really bugging me that rslinx will not let me connect again. sometimes i also get an error back after trying to write.. "message que filled". I guess this means RSLinx is struggling and i cant put any more data across. to be fair, my test code is very hard on the DDE, im performing a DDEwrite every loop (~300ms) in order to 'destructive test' this thing. the real application only does a write once every 0.5s at most, more like 1 every second under normal conditions.
BobLfoot
Sep 17 2008, 05:45 PM
QUOTE(Datman @ Sep 17 2008, 03:40 PM) [snapback]73726[/snapback]
ok thanks ill try that. its really bugging me that rslinx will not let me connect again. sometimes i also get an error back after trying to write.. "message que filled". I guess this means RSLinx is struggling and i cant put any more data across. to be fair, my test code is very hard on the DDE, im performing a DDEwrite every loop (~300ms) in order to 'destructive test' this thing. the real application only does a write once every 0.5s at most, more like 1 every second under normal conditions.
Datman - I have used Excel VBA for DDE connection to a processor. You'll find a couple of my samples in the Ab Download section. I've never stress tested them. I always use a DDETerminate.
I would wonder what is your ping time between your PC and MLGX. Use a 128 byte packet and at least 100 packets before you average.
By the way each open and close pass counts as a connection and msg request added to the queue.
You might be more stress friendly if you opened the dde link and left it connected until you had completed all writes then close.
Just MHO.
BTW - since this a test app can you post the vb6 project and forms.
Datman
Sep 17 2008, 06:00 PM
although its a test app on my bench i cant really post because the app im testing is the actual source code for the machine itself
how many conversations can i have open with rslinx? Let me explain fully, i am using two different methods of doing DDE within my vb code.
upon starting the application i create a topic called RSIchan. this topic is used though the code to perform reads, using the DDERequest (RSIchan, address) command. However with VB6 a write needs to be done from an object. Therefore whenever i need to write, i enter the data into a text box, and perform the following code:
Public sub DDEWrite(address as string, data as integer)
FrmMain.DDETest.Text = data
FrmMain.DDETest.LinkTopic = "RSLinx|BOARD_GRADER" 'Define DDE application and Topic
FrmMain.DDETest.LinkItem = address 'Define DDE link item
FrmMain.DDETest.LinkMode = 2 'Open DDE link (manual)
FrmMain.DDETest.LinkPoke 'Write data to RSLinx
FrmMain.DDETest.LinkMode = 0 'Close DDE link
Exit Function
its just now and then that i get an error when trying to write, message que filled, or "no forgein application responded to a DDEInitiate" when trying to perform the line DDETest.linkmode = 2. Once this error occurs i am stuck. My error handler disconnects all DDE conversations, but when looking at the server diagnostics on RSLinx it appears as though there are still conversations active. So my code is stuck because linkmode = 2 just generates an error every time, unless i restart rslinx. It is interesting however that my rsichan will create a link ok and perform reads ok. Its just this write that is giving me grief
BobLfoot
Sep 17 2008, 06:12 PM
I think the following sub should work in VB6 for your stress test. Let me know?
Public Sub TestDDEComms
Dim RSIChan
Dim RSITopic
Dim DataFile
Dim DataElement
Dim DDETarget
Dim Target
RSITopic = "BOARD_GRADER"
RSIChan = DDEInitiate("RSLinx", RSITopic)
DataFile = ????? ' Change ???? to the Data File you are writing to
DataElement = ????? ' Change ???? to the DataElement youa re writing to
Target = ????? ' Change ????? to the actual write data.
DDETarget = DataFile & "[" & DataElement & "]"
DDEPoke RSIChan, DDETarget, Target
DDETerminate (RSIChan)
End Sub
Datman
Sep 17 2008, 09:16 PM
QUOTE(BobLfoot @ Sep 18 2008, 11:12 AM) [snapback]73734[/snapback]
I think the following sub should work in VB6 for your stress test. Let me know?
Public Sub TestDDEComms
Dim RSIChan
Dim RSITopic
Dim DataFile
Dim DataElement
Dim DDETarget
Dim Target
RSITopic = "BOARD_GRADER"
RSIChan = DDEInitiate("RSLinx", RSITopic)
DataFile = ????? ' Change ???? to the Data File you are writing to
DataElement = ????? ' Change ???? to the DataElement youa re writing to
Target = ????? ' Change ????? to the actual write data.
DDETarget = DataFile & "[" & DataElement & "]"
DDEPoke RSIChan, DDETarget, Target
DDETerminate (RSIChan)
End Sub
tried the above. DDEPoke does not work with vb6, although i understand it works with VBA in excel. VB6 needs an actual object to do DDE pokes, hence why i have to use a text box. I made a slight change to my code, and I've been running for 4 hours without error as yet. a good sign. Note that the after the while loop was added i was still getting errors. adding the line as shown seems to have fixed the problem. it doesnt make much sense to me...
FrmMain.DDETest.Text = data
FrmMain.DDETest.LinkMode = 0 '[ADDED THIS LINE]
'double check no channel is open
FrmMain.DDETest.LinkTopic = "RSLinx|BOARD_GRADER"
'Define DDE application and Topic
FrmMain.DDETest.LinkItem = address
'Define DDE link item
FrmMain.DDETest.LinkMode = 2
'Open DDE link (manual)
FrmMain.DDETest.LinkPoke
'Write data to RSLinx
While FrmMain.DDETest.LinkMode <> 0
FrmMain.DDETest.LinkMode = 0
Wend
Exit Function
paulengr
Sep 18 2008, 12:32 AM
QUOTE(Datman @ Sep 17 2008, 10:16 PM) [snapback]73737[/snapback]
tried the above. DDEPoke does not work with vb6, although i understand it works with VBA in excel. VB6 needs an actual object to do DDE pokes, hence why i have to use a text box. I made a slight change to my code, and I've been running for 4 hours without error as yet. a good sign. Note that the after the while loop was added i was still getting errors. adding the line as shown seems to have fixed the problem. it doesnt make much sense to me...
First off, you need to realize that DDE is not very stable to begin with. It's not your fault or RS-Linx. It's just typical behavior of Windows. It is mostly related to COM/DCOM, so this is also not unusual for OPC either (switching to OPC is not a way out), although it happens much less often with OPC. The fact that OPC is more stable is one of the reasons that DDE was not recommended even 10 years ago when Microsoft still "supported" it. What you see is exactly what happens...everything looks good then suddenly nothing will talk anymore and you got to start over. It could be hours, days, or weeks. It's not you either. I've had this exact same behavior from Wonderware InSQL even though supposedly Wonderware actually wrote DDE and their DDE drivers are very unconventional compared to everyone else and just about as stable as OPC.
This brings up the only other possibility. Make sure you've got good cables and solid communications. If you don't, the frequency of this problem goes way up.
I've been told that the problem is related to overflowing internal buffers in Windows in COM/DCOM. In OPC this usually happens only after several days of lack of communication with the PLC but the failure mode is identical. With DDE it happens much quicker. I haven't pinned it down but I suspect even a single garbled packet can do it with DDE. Other than the lack of support forthcoming from Microsoft, this is one of the many reasons that OPC UA is being developed.
If it happens, the solution is usually to close ALL connections to RS-Linx, then reopen them. This works under OPC but I'm not 100% sure if it works with DDE (I had to do the kill/restart RS-Linx approach myself back when I had to deal with Wonderware InSQL). You have 2 connections open so you must close both of them. At that point, RS-Linx should drop communication with the PLC. Then it will restart after that. Even having an RSWho session open does it, so remember to not have any RSWho or similar windows open in RS-Linx, or it won't drop communication with the PLC and restart. That's assuming that this works at all with DDE. I haven't used DDE for years so I'm assuming that DDE problems are identical to the OPC one at this point.
Under OPC, you've got a few more failed packets to play with before it croaks. So, you can set up a second connection and just monitor the virtual tag called "@ispresent". It doesn't show up in the browse listing so you have to manually type it in (this is true of all the "@" tags). Whenever you see this bit go to 0, stop & close out your other sessions and wait for it to go back to a 1. This doesn't solve the buffers issue (you've still got to occasionally stop/restart everything) but it stretches out the time between total resets to enough years (instead of weeks, hours, or days) that it shouldn't ever be a problem.
As to overloading the connections, each RS-Linx session takes 4 "connections" in Logix terminology. The number of connections depends on your particular PLC and you can look in the manual for that to find out when you've saturated the number of connections (not conversations). A connection is effectively the buffers and other data that the PLC has to store and maintain.
If you are dealing with a PLC-5 or a SLC, then there is another way out. You can write your own drivers and bypass RS-Linx (DDE or OPC) altogether. Once you go this route, you eliminate the evil COM/DCOM layer that is the problem. Ron Gage has a web site (google for it) with source code in C++ (easily rewritten in any other language) plus pointers to the DF-1 manual from Rockwell if you are doing Ethernet. Simply talk the protocol directly with the PLC. The serial port version is almost identical. You can do similar things even with *Logix processors except that you are pretty much stuck with downloading someone else's code for talking Ethernet/IP. I suggest searching around for Unix libraries since these tend to be very standard and open source code. I know that at least a couple of them exist in C, which I believe you can use under VB (full VB, so you'll have to roll an OCX if you want to use it from VBA). Unfortunately although Ethernet/IP is an "open" protocol, you have to ante up about $5000 in license fees to join the organization and gain access to the specifications and source codes.
CLX does talk some form of DF-1 via the serial port. If that's your plan of attack, then there's a problem. Allen Bradley has chosen NOT to publish the new op codes for CLX processors, so you can't theoretically use DF-1. I believe you could set up the mapping back to PLC-5 registers (there's a way to do this in Logix 5000) but you probably want direct (tag-based) communication. You can still do it but you're going to need a protocol analyzer so that you can pick the packets apart and figure out what the new codes are. I've never had a CLX processor until last month so I haven't had the time or opportunity (or need) to do this myself either.
Datman
Sep 18 2008, 11:26 PM
ahh that makes a lot of sense. not a lot of help to the application but a lot of sense. I was always against using DDE, but because it was effectively free its what management wanted...
OPC was what i was hoping to use, interesting that the same issues occur though. Anyway ive done all i can do, hopefully the application runs a lot better as it is not doing as much work as my destructive testing was.
thanks heaps for the info and help
Datman
Sep 25 2008, 04:02 PM
out of interest you dont know of any free OPC client tools for vb6 do you?
BobLfoot
Sep 25 2008, 10:25 PM
QUOTE(Datman @ Sep 25 2008, 05:02 PM) [snapback]73967[/snapback]
out of interest you dont know of any free OPC client tools for vb6 do you?
IF you were doing DDE with Rslinx then you have a non-lite edition of Linx and should have the RSIAutoOPC.dll or it's successor on the Installation disc.
Check the RA Website for more information, but it is basically free to use when you buy RSLinx.
Datman
Oct 1 2008, 07:11 PM
QUOTE(BobLfoot @ Sep 26 2008, 04:25 PM) [snapback]73975[/snapback]
QUOTE(Datman @ Sep 25 2008, 05:02 PM) [snapback]73967[/snapback]
out of interest you dont know of any free OPC client tools for vb6 do you?
IF you were doing DDE with Rslinx then you have a non-lite edition of Linx and should have the RSIAutoOPC.dll or it's successor on the Installation disc.
Check the RA Website for more information, but it is basically free to use when you buy RSLinx.
awesome tried that and ive got it working well!
one question though... i want to create an item like this:
OPCItemIDs(1) = "[BOARD_GRADER]N7:0,L10,C10"
i can then perform a syncread and read the 10 valeus into an array fine. however vb just crashes when i try and write to this item. it only like writing to singular items. is there a way to write to something like the above?
BobLfoot
Oct 2 2008, 06:11 AM
I am not an OPC guru, but I think for write you add items to the group and then write the group.
Datman
Oct 2 2008, 03:14 PM
QUOTE(BobLfoot @ Oct 3 2008, 12:11 AM) [snapback]74169[/snapback]
I am not an OPC guru, but I think for write you add items to the group and then write the group.
hmm well i can make it loop and write to a block of different items at once no problem. but making it write to one item which references a block of data doesnt work. i guess i have to create each individual integer as an individual item. thats gonna be over 500 items for me!!
Stupidav
Oct 2 2008, 09:46 PM
It has been a while but this is the basic, NumberOfItems starts at 1 not 0. If a good portion of items is at the bit level, I would combine them into integers and read and or write the integer, and break it back down or assemble the integers within the VB app.
WriteDataGroup.SyncWrite(NumberOfItems, SyncItemServerHandles, Values, Errors)
DLeino
Oct 8 2008, 05:38 AM
For what it's worth, I've been dealing with various weird RSLynx problems by upgrading RSLynx to Ver 2.54. I had lost several tags, lost the ability to connect via PCMK, lost a couple of paths in Topuc Configuration, completely lost EDS files for PLC5/40's, and several other weird problems. I've upgraded all the workstations to 2.54. The previous tech had loaded different versions ranging from 2.31 to 2.50. Now all my communication problems seem to be resolved.
paulengr
Oct 9 2008, 07:55 PM
QUOTE(Datman @ Oct 1 2008, 08:11 PM) [snapback]74144[/snapback]
QUOTE(BobLfoot @ Sep 26 2008, 04:25 PM) [snapback]73975[/snapback]
QUOTE(Datman @ Sep 25 2008, 05:02 PM) [snapback]73967[/snapback]
out of interest you dont know of any free OPC client tools for vb6 do you?
IF you were doing DDE with Rslinx then you have a non-lite edition of Linx and should have the RSIAutoOPC.dll or it's successor on the Installation disc.
Check the RA Website for more information, but it is basically free to use when you buy RSLinx.
awesome tried that and ive got it working well!
one question though... i want to create an item like this:
OPCItemIDs(1) = "[BOARD_GRADER]N7:0,L10,C10"
i can then perform a syncread and read the 10 valeus into an array fine. however vb just crashes when i try and write to this item. it only like writing to singular items. is there a way to write to something like the above?
You are attempting to use the array trick. OPC does not have a defined standard for arrays. Instead, you are relying on a trick where most OPC vendors support something that works very similar to arrays. The object comes across as a binary object and the OPC client allows you to assign it to an array and it gets interpreted like an array, but it's not really an array at all (from the OPC point of view). So reading the data works just fine because everyone agrees on what is going on except the OPC Foundation.
Writing is another matter. To write, you have to push the whole thing back out as a binary object. It might be possible to do so but most of the time, I can't get it to work. The only safe way to do so is to write individual objects. Fortunately OPC lets you do mass updates of several objects at once (a whole group) so this doesn't have to be as slow as it sounds.
Datman
Oct 21 2008, 10:19 PM
Ive managed to get this all working. Block writes, reads, anything under the sun. but i have a problem someone might be able to point me in the right direction... I get no error feedback from the RSlinx server when no PLC is connected. ie i can create my group, connect to the opc server and everything fine, and when i perform writes and reads, i get no indication of an error. ie for the call:
ConnectedGroup.AsyncRead index, SyncItemServerHandles, SyncItemServerErrors, 0, 0
SyncItemServerErrors(1) is 0, indicating everything is ok. I need to implement some error trapping so i know if the PLC is recieving the data or not??
Stupidav
Oct 21 2008, 11:43 PM
I wouldn't recommend binary either, although the simple way around that with out the problems, is to do integers, with the 1100 that is 16 bits, for one read or one write, within the VB break the integer down into the bits to read or assemble the bits and then write. When you declare each Item within the Group and you want to write or read multiples "WriteDataGroup.SyncWrite(NumberOfItems, SyncItemServerHandles, Values, Errors)" The Number of Items is just as it sounds, the starting point is the SyncItemServerHandles. This way there is No OPC manipluation. I can find the VB.Net code to break down integers into a binary if you need, just let me know.
paulengr
Oct 22 2008, 05:31 AM
QUOTE(Datman @ Oct 21 2008, 11:19 PM) [snapback]74871[/snapback]
Ive managed to get this all working. Block writes, reads, anything under the sun. but i have a problem someone might be able to point me in the right direction... I get no error feedback from the RSlinx server when no PLC is connected. ie i can create my group, connect to the opc server and everything fine, and when i perform writes and reads, i get no indication of an error. ie for the call:
ConnectedGroup.AsyncRead index, SyncItemServerHandles, SyncItemServerErrors, 0, 0
SyncItemServerErrors(1) is 0, indicating everything is ok. I need to implement some error trapping so i know if the PLC is recieving the data or not??
Hehehe. Yep, it's the old broken RS-Linx OPC implementation. The best part is that if you keep trying to get it to work, eventually it will even overflow Windows buffers and simply seize up until you close/reopen your connection to the OPC server. It even makes sure to keep sending you old stale data with no "data bad" bits indicating a problem. Rockwell does a whole lot of hand waving about how it's not a bug but a feature on this point but just like with Windows "features", I fail to grok how this can be the case.
The secret is to check the "@IsPresent" item. A quick search through the Rockwell website will give you information on a whole bunch of status indicators that are built into the OPC server but will never BROWSE (so you can't find them the obvious way). Also, make sure that you recheck this bit a couple times before you declare it hopeless because if even one packet gets garbled, it will pretend that the PLC is totally out to lunch until it gets a successful retry.
I was forced into going with OPC with ControlLogix with Cimplicity HMI. To get around the broken implementation of RS-Linx OPC, I had to create two "devices". One monitors @IsPresent tags. The other one is the "real" device, one per PLC. Then through some secret arcane commands (and the instructions from GE Fanuc of course are not quite correct), I have to monitor the @IsPresent tags and purposely enable/disable the real "devices". If I don't do this, eventually when OPC locks up (Windows buffer overflow), I have to totally shut down either RS-Linx or Cimplicity to restore communication to the PLC even if it's running!
BobLfoot
Oct 22 2008, 06:52 AM
QUOTE(paulengr @ Oct 22 2008, 06:31 AM) [snapback]74882[/snapback]
I was forced into going with OPC with ControlLogix with Cimplicity HMI. To get around the broken implementation of RS-Linx OPC, I had to create two "devices". One monitors @IsPresent tags. The other one is the "real" device, one per PLC. Then through some secret arcane commands (and the instructions from GE Fanuc of course are not quite correct), I have to monitor the @IsPresent tags and purposely enable/disable the real "devices". If I don't do this, eventually when OPC locks up (Windows buffer overflow), I have to totally shut down either RS-Linx or Cimplicity to restore communication to the PLC even if it's running!
Take a look at your RSLinx Error Log. We've found that if this reaches 1000 entries we start to have DDE/OPC troubles. Routinely clearing the log circumnavigates this issue.
Datman
Oct 22 2008, 02:21 PM
QUOTE(paulengr @ Oct 22 2008, 11:31 PM) [snapback]74882[/snapback]
Hehehe. Yep, it's the old broken RS-Linx OPC implementation. The best part is that if you keep trying to get it to work, eventually it will even overflow Windows buffers and simply seize up until you close/reopen your connection to the OPC server. It even makes sure to keep sending you old stale data with no "data bad" bits indicating a problem. Rockwell does a whole lot of hand waving about how it's not a bug but a feature on this point but just like with Windows "features", I fail to grok how this can be the case.
The secret is to check the "@IsPresent" item. A quick search through the Rockwell website will give you information on a whole bunch of status indicators that are built into the OPC server but will never BROWSE (so you can't find them the obvious way). Also, make sure that you recheck this bit a couple times before you declare it hopeless because if even one packet gets garbled, it will pretend that the PLC is totally out to lunch until it gets a successful retry.
I was forced into going with OPC with ControlLogix with Cimplicity HMI. To get around the broken implementation of RS-Linx OPC, I had to create two "devices". One monitors @IsPresent tags. The other one is the "real" device, one per PLC. Then through some secret arcane commands (and the instructions from GE Fanuc of course are not quite correct), I have to monitor the @IsPresent tags and purposely enable/disable the real "devices". If I don't do this, eventually when OPC locks up (Windows buffer overflow), I have to totally shut down either RS-Linx or Cimplicity to restore communication to the PLC even if it's running!
ok not quite sure i understand, do i add the "@IsPresent" as an OPC item just as for all my other items i am using. then read this every so often to see what the value is? This would work for me, I could check it once every loop in my code to make sure PLC is happy... correct me if im wrong?
paulengr
Oct 23 2008, 05:09 AM
QUOTE(Datman @ Oct 22 2008, 03:21 PM) [snapback]74915[/snapback]
ok not quite sure i understand, do i add the "@IsPresent" as an OPC item just as for all my other items i am using. then read this every so often to see what the value is? This would work for me, I could check it once every loop in my code to make sure PLC is happy... correct me if im wrong?
Yes and no. Yes, read it periodically. It will indicate at THAT MOMENT whether there is a comm problem with your PLC. HOWEVER, that's not the full story. Also, you can't necessarily rely on the first poll because the @IsPresent bit has a nasty habit of being flat out wrong. If a packet gets deleted, RS-Linx will signal an error in spite of the fact that it's just a matter of waiting for the TCP/IP retry to occur for instance.
TechJunki
Oct 23 2008, 01:06 PM
The @IsPresent bit will not work on a SLC type CPU (have tried on a SLC 5/03 and always returns 0), or at least I have never been able to get it to work. This may also be true on the Micrologix 1100 your using..
It does however work "OK" on PLC-5 and Logix 5000 CPU's as previously stated.
Is there an equivilent Status word to use for 500 series CPU's??
Datman
Oct 23 2008, 01:57 PM
QUOTE(TechJunki @ Oct 24 2008, 07:06 AM) [snapback]74950[/snapback]
The @IsPresent bit will not work on a SLC type CPU (have tried on a SLC 5/03 and always returns 0), or at least I have never been able to get it to work. This may also be true on the Micrologix 1100 your using..
It does however work "OK" on PLC-5 and Logix 5000 CPU's as previously stated.
Is there an equivilent Status word to use for 500 series CPU's??
Once we get our office network back online today ill let you know how it goes (f*cking windows!!) i can always check the bit four or five times, and once it comes back as an error a few times in a row thats when i decide to flag a comms error on my system... something like that anyway, pretty primitive but what can ya do...
Datman
Oct 23 2008, 03:29 PM
OK, plot thickens... I seem to be able to do all my OPC comms ok with the processor type set to SLC500 or 503, but in this instance the Ispresent or status tags will not work...
ispresent tag will work when i change type to PLC-5. BUT then none of my other OPC comms will work, RSLINX appears to perform the write, but the data just does not get to the PLC...
its driving me mad!! im going to resort to writing to a bit in the plc every loop, getting the plc to clear this bit, then read it back, if the bit didnt change between when i wrote it and read it then assume a comms error? grrr!!!
Datman
Oct 23 2008, 07:18 PM
When doing these block writes, im getting very weird stuff happen with my arrays in VB.
this is my write block routine
CODE
Public Sub OPC_Write_Block(index As Integer, value() As Integer)
On Error GoTo errorhandler
' Write a block of items
ItemCount = 1
' Create some local scope variables to hold the value to be sent.
' These arrays could just as easily contain all of the item we have added.
Dim SyncItemValues(1) As Variant
Dim SyncItemServerHandles(1) As Long
Dim SyncItemServerErrors() As Long
' Get the Servers handle for the desired item
SyncItemServerHandles(1) = ItemServerHandles(index)
' Load the value to be written
SyncItemValues(1) = CVar(value)
' Invoke the AsyncWrite operation. Remember this call will wait until completion
ConnectedGroup.AsyncWrite ItemCount, SyncItemServerHandles, SyncItemValues, SyncItemServerErrors, 0, 0
Exit Sub
This item has been defined as following:
CODE
OPCItemIDs(22) = "[TEST_PLC]N14:0,L30,C30" 'Item22 = Block 1 PLC Run Information
I have test code running below to write to the above item. i have an array of dimension 30. Now if i make the first value in the array a number above 18, or below 9 it will write the block of data fine. However if the first element in the array is between 9 and 18, i get garbage written down to the PLC. ie the first value in the block on the PLC is something like -2040.
Alternatively, it seems if i write the LAST value in the array as a "1" and no other number, then everything else in the block will write correctly. Very weird and extremely fustrating, any ideas??? I dont know if you guys deal with VB much, or is it an issue with the DLL... maybe i have to stop being greedy and write to all my integers individually, and not as a block
CODE
Dim temparray2(1 To 30) As Integer
For i = 1 To 30
temparray2(i) = 0
Next i
temparray2(1) = 18
Call frmOPC_Comms.OPC_Write_Block(22, temparray2)
paulengr
Oct 24 2008, 05:04 AM
QUOTE(Datman @ Oct 23 2008, 04:29 PM) [snapback]74958[/snapback]
OK, plot thickens... I seem to be able to do all my OPC comms ok with the processor type set to SLC500 or 503, but in this instance the Ispresent or status tags will not work...
ispresent tag will work when i change type to PLC-5. BUT then none of my other OPC comms will work, RSLINX appears to perform the write, but the data just does not get to the PLC...
its driving me mad!! im going to resort to writing to a bit in the plc every loop, getting the plc to clear this bit, then read it back, if the bit didnt change between when i wrote it and read it then assume a comms error? grrr!!!
That explains it. One of the techs at AB said something about opening a second OPC connection and ONLY using it for checking the @IsPresent bit. That explains why he said not to use the channel for anything else (real data pulls).
My PLC count is 1 CLX, 18 PLC-5's, 1 SLC 5/05, and 4 or 5 Micrologix (2 1500's, rest are 1100's). I don't normally do anything fancy with the SLC 5/05 and until recently I didn't bother doing anything much with the Micrologix. So that explains why I never saw the problems you are referring to.
paulengr
Oct 24 2008, 05:16 AM
QUOTE(Datman @ Oct 23 2008, 08:18 PM) [snapback]74968[/snapback]
When doing these block writes, im getting very weird stuff happen with my arrays in VB.
this is my write block routine
CODE
Dim temparray2(1 To 30) As Integer
For i = 1 To 30
temparray2(i) = 0
Next i
temparray2(1) = 18
Call frmOPC_Comms.OPC_Write_Block(22, temparray2)
This is just an idea but I see a potential problem here. You are using arrays with user defined base index addresses instead of just the default. The base address for VB is normally 0. I'm not sure what the binary format of the array looks like when you define it this way and pass it over the COM/DCOM wire but it makes me nervous nonetheless because most OPC drivers are written in C which doesn't allow for user defined base index addresses and uses 0 as the base address. So the OPC driver could be thrown off by the funky array that is being passed to it, especially if the array comes across in some sort of "alternative" format that the OPC driver doesn't recognize or if the COM/DCOM wire format translation is doing something screwy with the data as it copies and translates the data from one COM object to another (although methinks it will just pass a memory reference in this case which is even worse!). Try this instead:
CODE
dim temparray2(29) as Integer
dim i as Integer
for i = 0 to 29
temparray2(i) = 0
next i
temparray2(0)=10
call frmOPC_Comms.OPC_Write_Block(22, temparray2)
TechJunki
Oct 24 2008, 07:56 AM
Are you using a Multi Dimension Array??
Unless I am missing something....?
This address you are using is a length of 30 with a index of 30...
OPCItemIDs(22) = "[TEST_PLC]N14:0,L30,C30"
If you are only writing to a single array .. elements N14:0 to n14:29 then it
should not be "C30" it SHOULD BE "C1".. like this... OPCItemIDs(22) = "[TEST_PLC]N14:0,L30,C1"
This may be causing the strange results you are seeing.
For reference I usually do my writes as follows.
Note this is in VB.NET not sure what you are using, I also have in VB6 if you are using that.
CODE
Public Sub SyncWrite()
Dim ItemCount As Integer
Dim i As Integer
' Get Number of Items in Group From Server
ItemCount = LinxOPCGroup.OPCItems.Count
' Dim Arrays for SyncWrite
Dim SyncServerHandles(ItemCount) As Integer
Dim Values(ItemCount) As Object
Dim WriteData(ItemCount) As Object
Dim SyncErrors As System.Array = Nothing
' Write values 1 to 10 to N63:500 to N63:509 and N63:510 to N63:519
Dim WriteValues() As Short = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
' Copy Array Data to System Object
WriteData(1) = WriteValues 'Data to First Item in Group -- [TopicName]N63:500,L10,C1
WriteData(2) = WriteValues 'Data to Second Item in Group -- [TopicName]N63:510,L10,C1
' Pass in the ServerHandles and Values for the items active in Linx
For i = 1 To ItemCount
' Pass in ServerHandles
SyncServerHandles(i) = LinxOPCGroup.OPCItems.Item(i).ServerHandle
' Pass in ClientHandles
Values(i) = WriteData(LinxOPCGroup.OPCItems.Item(i).ClientHandle)
Next
' Write data to server
LinxOPCGroup.SyncWrite(ItemCount, SyncServerHandles, Values, SyncErrors)
End Sub
Datman
Nov 16 2008, 08:37 PM
QUOTE(TechJunki @ Oct 25 2008, 01:56 AM) [snapback]74991[/snapback]
Are you using a Multi Dimension Array??
Unless I am missing something....?
This address you are using is a length of 30 with a index of 30...
OPCItemIDs(22) = "[TEST_PLC]N14:0,L30,C30"
If you are only writing to a single array .. elements N14:0 to n14:29 then it
should not be "C30" it SHOULD BE "C1".. like this... OPCItemIDs(22) = "[TEST_PLC]N14:0,L30,C1"
This may be causing the strange results you are seeing.
For reference I usually do my writes as follows.
Note this is in VB.NET not sure what you are using, I also have in VB6 if you are using that.
CODE
Public Sub SyncWrite()
Dim ItemCount As Integer
Dim i As Integer
' Get Number of Items in Group From Server
ItemCount = LinxOPCGroup.OPCItems.Count
' Dim Arrays for SyncWrite
Dim SyncServerHandles(ItemCount) As Integer
Dim Values(ItemCount) As Object
Dim WriteData(ItemCount) As Object
Dim SyncErrors As System.Array = Nothing
' Write values 1 to 10 to N63:500 to N63:509 and N63:510 to N63:519
Dim WriteValues() As Short = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
' Copy Array Data to System Object
WriteData(1) = WriteValues 'Data to First Item in Group -- [TopicName]N63:500,L10,C1
WriteData(2) = WriteValues 'Data to Second Item in Group -- [TopicName]N63:510,L10,C1
' Pass in the ServerHandles and Values for the items active in Linx
For i = 1 To ItemCount
' Pass in ServerHandles
SyncServerHandles(i) = LinxOPCGroup.OPCItems.Item(i).ServerHandle
' Pass in ClientHandles
Values(i) = WriteData(LinxOPCGroup.OPCItems.Item(i).ClientHandle)
Next
' Write data to server
LinxOPCGroup.SyncWrite(ItemCount, SyncServerHandles, Values, SyncErrors)
End Sub
do you have an example using vb6? that is what im using.
In reply to paulengr - I tried your suggest, same results
TechJunki
Nov 17 2008, 09:19 AM
For VB6...almost the same
CODE
Public Sub SyncWrite()
' Dim Arrays for SyncWrite
Dim SyncServerHandles() As Long
Dim Values() As Variant
Dim WriteData
Dim SyncErrors() As Long
Dim ItemCount As Integer
Dim WriteValues() As Integer
' Get Number of Items in Group From Server
ItemCount = LinxOPCGroup.OPCItems.Count
' Redim Arrays for Item Count
ReDim SyncServerHandles(ItemCount)
ReDim Values(ItemCount)
ReDim WriteData(ItemCount)
' Write values 1 to 10 to N63:500 to N63:509 and N63:510 to N63:519
ReDim WriteValues(9)
' Fill with Data
For i = 0 To 9
WriteValues(i) = i + 1
Next
' Copy Array Data
WriteData(1) = WriteValues 'Data to First Item in Group -- [TopicName]N63:500,L10,C1
WriteData(2) = WriteValues 'Data to Second Item in Group -- [TopicName]N63:510,L10,C1
' Pass in the ServerHandles and Values for the items active in Linx
For i = 1 To ItemCount
' Pass in ServerHandles
SyncServerHandles(i) = LinxOPCGroup.OPCItems.Item(i).ServerHandle
' Pass in ClientHandles
Values(i) = WriteData(LinxOPCGroup.OPCItems.Item(i).ClientHandle)
Next
' Write data to server
LinxOPCGroup.SyncWrite ItemCount, SyncServerHandles, Values, SyncErrors
End Sub
Datman
Nov 17 2008, 02:22 PM
ok now i just tried that, exact same result. with the first value in the array to be written as a value 9, vb just crashes out... It must be something to do with my topic setup in rslinx...?? Im using 1msec polled message, using maximum ethernet packet size, and optimising poke packets. Are these wrong, or any other topic settings that should be set???
TechJunki
Nov 17 2008, 04:48 PM
I doubt it has anything to do with the setup in linx...
Are you adding the items something like this....here is the rest of the code to add the items
QUOTE
Public RsLinxOPCServer As New RsiOPCAuto.OPCServer
Public WithEvents LinxOPCGroup As RsiOPCAuto.OPCGroup
Private Sub AddGrp_Click()
Dim AddItemServdrErrors() As Long
Dim TagName As String
Dim i As Integer
Dim Numoftags
' Add two tags to linx group
Numoftags = 2
' OPC Item related data
Dim ItemServerHandles() As Long
Dim OPCItemIDs() As String
Dim OPCItemIDs_VERIFY() As String
Dim ClientHandles() As Long
ReDim OPCItemIDs(Numoftags)
ReDim OPCItemIDs_VERIFY(Numoftags)
ReDim ClientHandles(Numoftags)
'Create Server
Set RsLinxOPCServer = New RsiOPCAuto.OPCServer
'Connect to Server
RsLinxOPCServer.Connect "RSLinx OPC Server"
'Add Group to Server
Set LinxOPCGroup = RsLinxOPCServer.OPCGroups.add("MyGroup")
'Set Group Active for Data Updates and Events
LinxOPCGroup.IsActive = False
'Group Update Rate
LinxOPCGroup.UpdateRate = 1000
LinxOPCGroup.IsSubscribed = False
Dim WordIndex
WordIndex = 500
'Add Items to Group
For i = 1 To Numoftags
TagName = "[TopicName]N63:" & WordIndex & ",L10,C1"
OPCItemIDs(i) = TagName
ClientHandles(i) = i
WordIndex = WordIndex + 10
Next
' Add Items to RsLinx Server
LinxOPCGroup.OPCItems.additems Numoftags, OPCItemIDs, ClientHandles, ItemServerHandles, AddItemServerErrors
End Sub
Datman
Nov 17 2008, 04:57 PM
yes exactly as that except i make the opc items directly, instead of passing the tagname from a variable string as you do with TagName.
eg OPCItemIDs(1) = "[TopicName]N13:0,L10,C1"
TechJunki
Nov 17 2008, 05:10 PM
You could try posting or e-mailing your project file and I could take a look at it to see if it acts the same on my end. Not sure why it won't work correctly.
Datman
Nov 17 2008, 05:23 PM
easiest if i just post my code here. these are my declarations:
CODE
Dim WithEvents AnOPCServer As OPCServer
Dim WithEvents ConnectedOPCServer As OPCServer
Dim ConnectedServerGroup As OPCGroups
Dim WithEvents ConnectedGroup As OPCGroup
Dim Groupname As String
Dim OPCItemCollection As OPCItems
Dim ItemCount As Long
Dim OPCItemIDs() As String
Dim ItemServerHandles() As Long
Dim ItemServerErrors() As Long
Dim ClientHandles() As Long
CODE
Public Function OPC_Connect()
'Call OPC_Connect("BOARD_GRADER")
Dim ConnectedServerName As String
Dim ConnectedServerName2 As String
Dim i As Integer
Dim test As Variant
'Create a new OPC Server object
Set ConnectedOPCServer = New OPCServer
'Load the selected server name to start the interface
ConnectedServerName = "RSLinx OPC Server"
'Attempt to connect with the server (Local only)
ConnectedOPCServer.Connect (ConnectedServerName)
'Prepare to add a group to the current OPC Server
' Get the group interface from the server object
Set ConnectedServerGroup = ConnectedOPCServer.OPCGroups
' Set the desire active state for the group
ConnectedServerGroup.DefaultGroupIsActive = True
'Set the desired percent deadband
ConnectedServerGroup.DefaultGroupDeadband = 0
' Add the group and set its update rate
Groupname = "GRADER"
Set ConnectedGroup = ConnectedServerGroup.Add(Groupname)
' Set the update rate for the group
ConnectedGroup.UpdateRate = 500
ConnectedGroup.IsSubscribed = True
'create the items in the group
ItemCount = 1
OPCItemIDs(1) = "[BOARD_GRADER]N13:0,L10,C1" 'Item1 = Primary PLC Control Word
ClientHandles(1) = 1
Set OPCItemCollection = ConnectedGroup.OPCItems 'Gets an items collection from the current Group
OPCItemCollection.DefaultIsActive = True 'Sets the items collection to active
'This line adds the items we’ve chosen to the items collection and in turn to the group in the OPC Server
OPCItemCollection.AddItems ItemCount, OPCItemIDs, ClientHandles, ItemServerHandles, ItemServerErrors
End Function
this is my test function for performing the write. taken from your function above and modified slightly. if you increase the value that the array WriteValues is written as, (WriteValues(i) = i + 2) so that the first element is 9, you should see the error occur..
CODE
Public Sub TestWrite()
' Dim Arrays for SyncWrite
Dim SyncServerHandles() As Long
Dim Values() As Variant
Dim WriteData
Dim SyncErrors() As Long
Dim ItemCount As Integer
Dim WriteValues() As Integer
Dim i As Long
' Get Number of Items in Group From Server
ItemCount = ConnectedGroup.OPCItems.Count
ItemCount = 1
' Redim Arrays for Item Count
ReDim SyncServerHandles(ItemCount)
ReDim Values(ItemCount)
ReDim WriteData(ItemCount)
' Write values 1 to 10 to N63:500 to N63:509 and N63:510 to N63:519
ReDim WriteValues(9)
' Fill with Data
For i = 0 To 9
WriteValues(i) = i + 2
Next
' Copy Array Data
WriteData(1) = WriteValues 'Data to First Item in Group -- [TopicName]N63:500,L10,C1
'WriteData(2) = WriteValues 'Data to Second Item in Group -- [TopicName]N63:510,L10,C1
' Pass in the ServerHandles and Values for the items active in Linx
For i = 1 To ItemCount
' Pass in ServerHandles
SyncServerHandles(i) = ConnectedGroup.OPCItems.Item(i).ServerHandle
' Pass in ClientHandles
Values(i) = WriteData(ConnectedGroup.OPCItems.Item(i).ClientHandle)
Next
' Write data to server
ConnectedGroup.SyncWrite ItemCount, SyncServerHandles, Values, SyncErrors
End Sub
TechJunki
Nov 18 2008, 10:51 AM
That is really strange, I was able to reproduce the problem, with a nine in the first element of the array it will "bomb" out VB6.
I found that changing the Declaration datatype in the "Write" sub to a Variant seems to eliminate the problem. I tryed a few other datatypes all with out any success, either same thing or it just plain old didn't work. Must have something to do with how VB stores and sends the data in its memory.
Anyway by changing the following line I have gotten this to work with a "9" as the first element of the array.
let me know if you have the same result..
Dim WriteValues() As Integer --> Dim WriteValues() As Variant
Datman
Nov 18 2008, 03:15 PM
you are right... whats even weirder, is i cant pass my array into this fucntion as an integer, then cast it as a variant by doing writevalues = cvar(temparray)... the array must be declared and passed into this function as variant...
i suspect maybe something to do with the size, a variant is 16bytes, an integer 2 bytes? why we only see it with the value 9 is beyond me though...
anyway, thanks very much for your help!!!
TechJunki
Nov 18 2008, 03:31 PM
Glad you got it working... Sometimes better not to question if it works...
Datman
Nov 23 2008, 08:19 PM
just one more question on this... is OPC slow to write? I have just a single write, which seems to take RSLinx 1 - 1.5seconds to write the data down to the PLC after the syncwrite call has finished. Is this normal? My updaterate in VB is set to something like 20, polled messages setting in RSLinx is set to 1msec. It is causing me some timing issue in my program, can i expect any faster?
Datman
Nov 23 2008, 10:08 PM
also whats the difference between asyncwrite and syncwrite, same with the read??
BobLfoot
Nov 24 2008, 06:30 PM
QUOTE(Datman @ Nov 23 2008, 08:19 PM) [snapback]76110[/snapback]
just one more question on this... is OPC slow to write? I have just a single write, which seems to take RSLinx 1 - 1.5seconds to write the data down to the PLC after the syncwrite call has finished. Is this normal? My updaterate in VB is set to something like 20, polled messages setting in RSLinx is set to 1msec. It is causing me some timing issue in my program, can i expect any faster?
What is the medium of communication between PC and PLC?
With Devicenet, ControlNet, DHPlus and RIO you have deterministic predictable data rates, due in large part to the passed token or other communication guarantees.
With Ethernet any other traffic can pause the delivery of your PLC Data. Something to think about.
QUOTE(Datman @ Nov 23 2008, 10:08 PM) [snapback]76115[/snapback]
also whats the difference between asyncwrite and syncwrite, same with the read??
Not 100% sure with this, but Async can happen at any time, but Sync happens immediately after the call.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please
click here.