andrewjfox Posted October 19, 2011 Share Posted October 19, 2011 Is it possible to create a pointer to a device? I have 4 ethernet devices, each using 2 ports (1515 & 1516) for different commands (don't even get me started on how frustrating this is) Lets call these ports Control and Data, so I effectively have 8 devices, Device.RdrCtrl01 Device.RdrData01 . . Device.RdrCtrl04 Device.RdrData04 To read & write I currently do; Device.RdrCtrl01.Write or Device.RdrData01.Read but, is it possible to create a pointer to the device like global pDevice = Device.RdrCtrl01 or global pDevice = evaluate("Device.RdrCtrl" + Format("%02d",Num)) then use that in scripts instead ie pDevice.Write & pDevice.Read Regards Andrew Link to comment Share on other sites More sharing options...
AzeoTech Posted October 20, 2011 Share Posted October 20, 2011 Yes and no. First, in normal DAQFactory there are no real pointers. You can kind of simulate them using a string and evaluate() or execute(), so: global string pDevice = "Device.RdrCtrl01" then, for example, to write: execute(pDevice + ".Write('test')") That all said, you can dynamically create devices as objects and then they are pointers (because objects are always references). This is a more involved and only for those that like scripting. You won't have access to these devices except in their object form and not through the Device Configuration. There are three objects: CCommEthernet CCommSerial CCommDevice The first two correspond to the desired transport layer, Ethernet (TCP) or serial port. The last takes a reference to one of those ports and a protocol name, and then is simply a reference to a device and takes commands just like a normal device would. So for example: global CommPort = new(CCommEthernet) CommPort.Address = "10.0.0.10" CommPort.Port = 502 CommPort.InitConnection() global CommDevice = new(CCommDevice) CommDevice.PortObject = CommPort CommDevice.ProtocolName = "ModbusTCP" You can determine valid protocol names by simply creating a device normally through Device Configuration, then doing: ? device.myDevice.protocolName I have never tried it, but I'm guessing you could create a device using Device Configuration and then using the PortObject member variable, assign a dynamically created port: device.myDevice.PortObject = CommPort But I don't really see an advantage to this as once you do this, the Device Configuration won't work for that device since the dynamically created port won't appear in the list. Link to comment Share on other sites More sharing options...
andrewjfox Posted October 20, 2011 Author Share Posted October 20, 2011 I've been trying out the dynamic objects and have a query about the behaviour of the following code. global CommPort[2] CommPort[0] = new(CCommEthernet) CommPort[0].Address = "192.168.1.203" CommPort[0].Port = 1516 global CommDevice = new(CCommDevice) CommDevice.PortObject = CommPort[0] CommDevice.ProtocolName = "NULL Protocol" CommDevice.InitComm() The above code fails at last line, InitComm(), which I am assuming is because the PortObject is not set correctly using the indexed CommPort object, however the following code works ok global CommPort = new(CCommEthernet) CommPort.Address = "192.168.1.203" CommPort.Port = 1516 private pPort[2] pPort[0] = CommPort global CommDevice = new(CCommDevice) CommDevice.PortObject = pPort[0] CommDevice.ProtocolName = "NULL Protocol" CommDevice.InitComm() Am I missing something? To me they're doing the same thing. Regards Link to comment Share on other sites More sharing options...
AzeoTech Posted October 20, 2011 Share Posted October 20, 2011 This is kind of why for a long time OOP in DAQFactory remained undocumented. There are a few little quirks in it that can throw people if you don't know about it. However, since OOP is so useful for the more experienced user, and the quirks are easy to get around, I keep bringing it up in the forum. The two main quirks are: 1) when you have a member function and there is an error, the line number is from the beginning of the member function, not the beginning of the sequence. This means you have to manually count line numbers. 2) the system often does not like having objects in arrays. You can store them in arrays, but often when referencing it, you need to copy to a private variable and reference it that way. This usually only occurs when you have something after the subsetting (like Commport[0].address). So, for your code, this also works: global CommPort[2] CommPort[0] = new(CCommEthernet) private z = commport[0] z.Address = "192.168.1.203" z.Port = 1516 global CommDevice = new(CCommDevice) CommDevice.PortObject = commPort[0] CommDevice.ProtocolName = "NULL Protocol" CommDevice.InitComm() See how I substituted z for commport[0] whenever I needed to reference a member variable (or function) of the arrayed element. When I simply needed to copy the reference (CommDevice.portObject = ) it was no issue. Link to comment Share on other sites More sharing options...
andrewjfox Posted October 20, 2011 Author Share Posted October 20, 2011 Thanks, that works nicely. Link to comment Share on other sites More sharing options...
EOlsen Posted March 21, 2014 Share Posted March 21, 2014 I thinking somehow the following code should know which object to operate on when calling any of the functions in IOClass. For example when calling io.PointAdd(1, "Test") because it is the io object calling the function within the IOClass shouldn't the function know to use the point array of the io object without it having to be specified? A work around is the PointNew() function where the obj is passed in as a parameter, but isn't there a way to make the code aware it should be using the io object that called it? class PointClass local string name = "" local addr = 0 function OnCreate() ? "Point created" endfunction endclassclass IOClass local state = 0 local port = 1000 local string protocol = "MyProtocol" local point // IO points array function PointAdd(addr, string name) private n = NumRows(io.point) private x io.point[n] = new(PointClass) x = io.point[n] x.addr = addr x.name = name endfunction function PointName(offset, string name) private x = io.point[offset] x.name = name endfunction function PointNew(obj, addr, string name) private n = NumRows(obj.point) private x obj.point[n] = new(PointClass) x = obj.point[n] x.addr = addr x.name = name endfunction endclassglobal io = new(IOClass) Link to comment Share on other sites More sharing options...
AzeoTech Posted March 21, 2014 Share Posted March 21, 2014 You are correct. All those references to "io" or even "obj" in PointNew are unnecessary. The problem is that "point" is reserved word in the global scope, thus the reason you get the error "Function Without Parenthesis". That's the give away, that something is a function that you didn't put () after. Point() is in 4.12.12 of the user's guide. A good way to check if something is a reserved word is to simply go to the command / alert window and type: ? foo If you get "Channel or function not found" then it doesn't exist in the global scope. If you get anything else, like "function without parenthesis", or "'Value' found in expression" then you know its a reserved word. This isn't perfect. There are things in the global scope that you can end up overriding. For example, if you did: global channel = 5 you will basically override the meaning of "channel" and you will no longer have access to the internal channel object for things like channel.listall() and the like. Likewise, you can do: global if = 5 and assign a value to the variable named "if". This will actually work fine, but will make your code really confusing! It won't effect the if() statement. I should also add that you can write these functions a lot simpler by using append(): function pointNew(addr, string name) private p = new(PointClass) p.addr = addr p.name = name pointArray.append(p) endfunction Note also how I initialized the new pointclass object BEFORE adding it to the array. This is the proper way to do it in a multithreaded environment, that way the point isn't in the array where it might be processed by another thread until after it already has its proper parameters. Finally, you don't need this either: x = obj.point[n]x.addr = addrx.name = name you can just do: obj.point[n].addr = addr obj.point[n].name = name The only time you need to assign it to a private variable is if you are going to create a situation where you have multiple [] or () in a single symbol: obj.point[n].foo() or: obj.point[n].addr[2] Those won't work, and you'd have to store a reference to obj.point[n] in a private, then use that reference instead. Link to comment Share on other sites More sharing options...
EOlsen Posted March 23, 2014 Share Posted March 23, 2014 Thanks for your reply. Very helpful. I have run into the problem of trying to use a reserved word for something before and didn't understand the error message generated meant that was the problem. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.