Comm Objects


andrewjfox

Recommended Posts

Hi ,

I've been using objects for ports and devices in an existing project but am still getting some behaviour which I don't understand

I am trying to close and -reopen a ethernet connection as follows

//Instatiate objects, and open connections


define CTRL_PORT = 0
define RADIO_PORT = 1

class DeviceObj
local iDevice
local RxBuff
local State

function OnCreate()
iDevice = new(CCommDevice)
State = DEVICE_STATE_CLOSED
endfunction

endclass

global MyDevice
global MyPort

for(private i=0,i<MAX_READERS,i++)
MyPort[i*2 + CTRL_PORT] = new(CCommEthernet)
MyDevice[i*2 + CTRL_PORT] = new(DeviceObj)
MyPort[i*2 + RADIO_PORT] = new(CCommEthernet)
MyDevice[i*2 + RADIO_PORT] = new(DeviceObj)
OpenConnection(i)
endfor
[/CODE]

// functions to open & close connections

[CODE]
function OpenConnection(ReaderIndex)

private pDevice
private pPort

try
pDevice = MyDevice[ReaderIndex*2 + CTRL_PORT]
if(pDevice.State == DEVICE_STATE_CLOSED)
pPort = MyPort[ReaderIndex*2 + CTRL_PORT]
pPort.Address = strAddressBase + DoubleToStr(DeviceAddress[ReaderIndex])
pPort.Port = CPORT
pPort.Timeout = 1000

pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + CTRL_PORT]
pDevice.iDevice.ProtocolName = "NULL Protocol"
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_OPEN
endif
pDevice = MyDevice[ReaderIndex*2 + RADIO_PORT]
if(pDevice.State == DEVICE_STATE_CLOSED)
pPort = MyPort[ReaderIndex*2 + RADIO_PORT]
pPort.Address = strAddressBase + DoubleToStr(DeviceAddress[ReaderIndex])
pPort.Port = RPORT
pPort.Timeout = 1000

pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + RADIO_PORT]
pDevice.iDevice.ProtocolName = "NULL Protocol"
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_OPEN
endif
catch()
Event.AddValue(Format("Error: Rdr%02d, ",ReaderIndex)+strLastError)
endcatch
endfunction


function CloseConnection(ReaderIndex)

private pDevice
private pPort
//try
pDevice = MyDevice[ReaderIndex*2 + CTRL_PORT]
pPort = MyPort[ReaderIndex*2 + CTRL_PORT]

pPort.Address = ""
pPort.Port = 0
pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + CTRL_PORT]
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_CLOSED

pDevice = MyDevice[ReaderIndex*2 + RADIO_PORT]
pPort = MyPort[ReaderIndex*2 + RADIO_PORT]

pPort.Address = ""
pPort.Port = 0
pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + RADIO_PORT]
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_CLOSED

//catch()
// Event.AddValue(Format("Error: Rdr%02d, ",ReaderIndex)+strLastError)
//endcatch
endfunction
[/CODE]

When I call the CloseConnection function I get an error at the InitComm() function

CloseConnection(0)

C1000 Channel or function not found: CloseConnection Line 15: Line 1

My understanding is that the InitComm() call should be successful regardless of whether connection is open /closed. Do you have any ideas for me to try?

Also I tried including the port object in my device object

class DeviceObj

local iDevice

local RxBuff

local State

function OnCreate()

iDevice = new(CCommDevice)

State = DEVICE_STATE_CLOSED

endfunction

endclass

Regards

Andrew

Link to comment
Share on other sites

In the sequence line numbering, line 15 is the initComm line. Is this one of those instances where, because I'm using objects, the error message is not pointing to where I think it's pointing?

I had also meant to ask about including port object in my MyDevice object but accidentally submitted the post before finishing.

As I started to mention, I tried including the port object in MyDevice object

class DeviceObj

Link to comment
Share on other sites

Hi,

after some more testing I'm pretty sure the problem occurs at the .InitComm() line

As above I have 8 device objects instantiated thusly;


class DeviceObj
local iDevice
local RxBuff
local State

function OnCreate()
iDevice = new(CCommDevice)
State = DEVICE_STATE_CLOSED
endfunction

endclass
global MyDevice
global MyPort

NumReaders = 4

for(private i=0,i<NumReaders,i++)
MyPort[i*2 + CTRL_PORT] = new(CCommEthernet)
MyDevice[i*2 + CTRL_PORT] = new(DeviceObj)

MyPort[i*2 + RADIO_PORT] = new(CCommEthernet)
MyDevice[i*2 + RADIO_PORT] = new(DeviceObj)
OpenConnection(i)

// additional stuff here

endfor

[/CODE]

[CODE]
function OpenConnection(ReaderIndex)

private pDevice
private pPort

// try
pDevice = MyDevice[ReaderIndex*2 + CTRL_PORT]
//if(pDevice.State == DEVICE_STATE_CLOSED)
pPort = MyPort[ReaderIndex*2 + CTRL_PORT]
pPort.Address = strAddressBase + DoubleToStr(DeviceAddress[ReaderIndex])
pPort.Port = CPORT
pPort.Timeout = 1000

pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + CTRL_PORT]
pDevice.iDevice.ProtocolName = "NULL Protocol"
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_OPEN
//endif
pDevice = MyDevice[ReaderIndex*2 + RADIO_PORT]
//if(pDevice.State == DEVICE_STATE_CLOSED)
pPort = MyPort[ReaderIndex*2 + RADIO_PORT]
pPort.Address = strAddressBase + DoubleToStr(DeviceAddress[ReaderIndex])
pPort.Port = RPORT
pPort.Timeout = 1000

pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + RADIO_PORT]
pDevice.iDevice.ProtocolName = "NULL Protocol"
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_OPEN
//endif
// catch()
// Event.AddValue(Format("Error: Rdr%02d, ",ReaderIndex)+strLastError)
// endcatch

endfunction
[/CODE]

when I try to close the connection using following I get an error at the InitComm(). (I stepped through the sequence and the error definitely occurs when trying to execute the InitComm() line)

[CODE]
//function CloseConnection(ReaderIndex)
private ReaderIndex = 1

private pDevice
private pPort

// try
pDevice = MyDevice[ReaderIndex*2 + CTRL_PORT]
pPort = MyPort[ReaderIndex*2 + CTRL_PORT]
pPort.Address = ""

pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + CTRL_PORT]
? MyDevice[].iDevice.Address
? MyDevice[].iDevice.Port
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_CLOSED
pDevice = MyDevice[ReaderIndex*2 + RADIO_PORT]
pPort = MyPort[ReaderIndex*2 + RADIO_PORT]
pPort.Address = ""

pDevice.iDevice.PortObject = MyPort[ReaderIndex*2 + RADIO_PORT]
pDevice.iDevice.InitComm()
pDevice.State = DEVICE_STATE_CLOSED
// catch()
// Event.AddValue(Format("Error: Rdr%02d, ",ReaderIndex)+strLastError)
// endcatch

//endfunction
[/CODE]

if, however, I replace the line

pDevice.iDevice.InitComm()

with

MyDevice[ReaderIndex*2 + CTRL_PORT].iDevice.InitComm()

it works ok.

I know that the objects can be funny about using brackets on both sides, is it possible that for object function calls I need to use the actual object, MyDevice[2].iDevice.InitComm() rather than a pointer like pDevice.iDevice.InitComm()

Regards

Andrew

Link to comment
Share on other sites

I'd be more apt to think that the second version (the one that works) isn't doing what you think it is. Instead of initing [readerIndex*2 + CTRL_PORT] its doing [0] because of a bug in how DAQFactory parses it. In fact, to get around this bug (which may be fixed, I don't remember), I often do what you did with pDevice, so I doubt that is the problem, though anything is possible. Are you using a USB -> Serial converter? Can you create a blank document, then try creating a normal device for that port (not dynamically), then see if initcomm() works on it using device.myDevice.initComm().

Link to comment
Share on other sites

-bug in parsing ? Is it a problem using calculations in indexes in general, or only for objects?

Can I use a calculated variable to solve eg private index = readerindex*2 + CTRL_PORT, then MyDevice[index].

How do I assign the object pointer if there is a problem with the indexing ie pDevice = MyDevice[???]

-the devices are TCP, does initcomm attempt to open the TCP connection, and will it fail gracefully if it can't make the connection?

I will put a test file together to try and isolate the problem as suggested

Andrew

Link to comment
Share on other sites

Have done a few quick tests, as suggested.

Created blank document and new devices using configuration wizard

Device1Ctrl, Device1Radio, Device2Ctrl and Device2Radio

Tried opening and closing first using Device.Device1Ctrl.InitComm(), etc then using private pDevice = Device.Device1Ctrl and pDevice.InitComm()

following is output from attached test doc "comms_test.ctrl".

Opening connections

Closing connections

Reopening connections with ptrs

09/08/12 13:43:56.941

C1000 Channel or function not found: startup Line 44 - Uncaught error in sequence startup

using pDevice.InitComm(), at least on my system, throws an error.

If this is the case then it might also explain why I am getting irregular errors when calling .Read & .Write functions using ptrs. It works sometimes, but not others. Up till know I have been assuming the end devices are causing all the problems. If ptrs only work in some cases, I need to know the guidelines for usage.

Please I need a practical fix/workaround asap, .

Eagerly awaiting reply, Andrew

comms_test.ctl

Link to comment
Share on other sites

The sample you did doesn't work because although device.myDevice looks like an object, its not a user object so can't be assigned to another variable. You can only do this with comm objects created dynamically using new(). Perhaps that's your problem? Are you trying to reference devices created in with "New Serial / Ethernet device"?

Link to comment
Share on other sites

My apologies, I misunderstood the intention of your post #6.

No, in the actual application, all of the devices are created dynamically. In the test doc (comms_test.ctl) I'm opening connections to the same, real, devices as in the actual application.

My concern is not that one or the other method of referencing object functions doesn't work, but that it appears to be inconsistent, sometimes working, but not others, and I don't see how this is device dependent since a function (any function) can only succeed or fail after it's been called. It shouldn't throw an exception before attempting to call the function, on the expectation that the device comms may or may not fail, should it?

Which method will work 100% of the time

- indexed objects ie MyDevice[index].Device.InitComm()

- or can I use pointer reference such as pDevice = MyDevice[index].Device, and pDevice.InitComm()

Link to comment
Share on other sites

Remember, DAQFactory is an interpretted language. This means a function can fail without being called if DAQFactory can't find the function. DAQFactory doesn't look up the functions at compile time, it does it at runtime. This is why you can create a function that references non-existant channels or other objects and compile it, and then add the channels or other objects later.

Anyhow, there is a bug in some versions of DAQFactory that makes it so you can't have more than one [] or () in the function specification. This means that x[index].foo() won't work, though x[index].myVar will. The workaround is what you described second:

z = x[index]

z.foo()

Link to comment
Share on other sites

This brings us back to the original post, when I do this the function can't be found

See above for more details but basically I have several dynamically created objects MyDevice[], each containing a device object, iDevice which is instatiated using the OnCreate function of the parent object, iDevice = new(CComDevice). The whole object is then referenced using a pointer.

private pDevice = MyDevice[index]

then calling the InitComm function using pDevice.iDevice.InitComm(), which fails with error C1000 Channel or function not found

calling MyDevice[index].iDevice.InitComm() works ok, however you suggest that the indexing is wrong, please explain further.

I've changed the application in the (numerous) field systems so that it's using the indexing method MyDevice[index].iDevice.InitComm(), however from the content of this thread I'm not confident that this is working correctly either, it's just not throwing exceptions. I'm having comms problems in the field but so far I've been unable to determine if it's DF comms issues or the physical devices.

I've already tested that InitComm isn't failing because of the physical device, there must be a software issue, perhaps something to do with the pointer referencing.

Andrew

Link to comment
Share on other sites

Sorry to hassle you guys again, but you're suggestions aren't working and I'm still having trouble understanding what's going on with objects and InitComm()

Have been doing some testing to try and demonstrate what I'm seeing and have attached the following

EchoServer.exe

Echo server is a basic TCP server on ports 1515 & 1516 that displays messages when clients connect/disconnect and echos any data received back to client

Test.ctl - This is my test doc, it opens TCP connections using dynamic comm devices to local 127.0.0.1 and ports 1515 & 1516

You'll see that towards the end I have setup 2 options for closing the connection however,

OPTION = 0, trying to clear TCP address by writing to MyDevice.iDevice.Address = "", however this approach throws an error when it gets to InitComm() which should be closing the connection. From looking at the server console it does appear to close the connection before throwing the error

OPTION = 1, clear the port object address, then assign the port object to the device, this has no errors, but doesn't close the connection. When I write to port after it is suppossedly closed, the echo works fine, almost as if it re-opens the connection even though the address should be "".

I'm doing all the things you've suggested in regards referencing objects using pointers, and clearing the port address before calling InitComm() to close the connection, but either approach I take doesn't work correctly

Please have a look and let me know if the problems is something I've done, or don't understand or other.

Test.zip

Test.zip

Link to comment
Share on other sites

Thanks, that seems to work bit better. When I close the connection the only error is when I try to call .Write later which makes sense.

I do still have a problem in regards modifying the port parameters

When I instatiate the port object MyPort[index] = new(CCommEthernet)

then assign values

MyPort[index].Address = "127.0.0.1"

MyPort[index].Port = 1515

then assign port to device

pDevice.PortObject = MyPort[index]

This all works ok first time.

If I want to change port values do I change the port object then reassign

MyPort[index].Port = -1 then pDevice.Portobject = MyPort[index]

OR

change device values directly pDevice.Port = -1

When I change Port to -1 to close connection then it doesn't assign value to device

eg

MyPort[index].Port = -1

pDevice.Portobject = MyPort[index]

? pDevice.Port // displays 1515, value of port hasn't changed

versus

pDevice.Port = -1

? pDevice.Port // displays 4294967295

I had thought that assigning port object to the device is just like assigning a pointer, rather than a param copy, so any changes to the port object would be reflected in the device params.

Regards

Andrew

Link to comment
Share on other sites

I can't really say. This is why this is an undocumented feature. You have to experiment to see what works. OOP is generally undocumented, but has only a couple issues. Using internal objects as user oop objects however has a few extra issues, and this I guess is one. The other that I can think of is that ToJson() and fromJson() don't work.

4294967295 is -1 by the way. Port is an unsigned long, so -1 gets translated to the biggest unsigned value an unsigned long can hold.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.