Jump to content

As of July 17, 2015, the LabJack forums here at forums.labjack.com are shut down. New registrations, topics, and replies are disabled. All forums are in a read-only state for archive purposes.

Please visit our current forums at labjack.com/forums to view and make new posts. To post on the current forums, use your labjack.com login account. Your old LabJack forums login credentials have been retired. There are no longer separate logins for labjack.com and LabJack forums.


Photo

C# UE9 PRO Streaming Network Re-connection Issues

C# UE9 PRO Streaming Counter0 re-connection

  • Please log in to reply
4 replies to this topic

#1 RPS_metocean

RPS_metocean
  • Members
  • 5 posts

Posted 05 August 2014 - 01:56 AM

I followed the sample code using LDUDDotNet.dll to write some real time data acquisition code for our weather monitoring system.  Current, I tested with four channels with the counter0 channel for wind speed and the other three to read the voltages with BIP5V. I set the scan rate to 20 Hz with a 5 second interval loop to retrieve the streaming buffer, so the size will be roughly something like 4 x 20 x 5 = 400, I supply a buffer size 5 x 400 = 2000 in case the PC clock will lag a bit.

Overall, the streaming is working fine. Just one issue frustrated me all the time. For a real time data acquisition system, we will prepare to handle any network outage, the program needs to reconnect to the device as soon as the network is up again without restart of the program. I tested to disconnect the device from the network while streaming is on, and re-plug the cable back in a short time, the reconnection procedure works fine. But if the network down time last for several minutes, it becomes impossible to re-establish a real connection nor the streaming can be restarted. I am keen to know what’s wrong with the code and how to correct the procedure.

Here is the major part of the code to call the LJUDDotNet:

1.       Open

ljDevice = new UE9();

LJUD.LJUDERROR error = LJUD.OpenLabJack(LJUD.DEVICE.UE9, connectiontype, deviceAddress, true, ref ljDevice.ljhandle);

if (ljDevice == null || error != LJUD.LJUDERROR.NOERROR)

{

                // handle the error …

2.       Clear Counter Timer

try

{

    LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.NUMBER_TIMERS_ENABLED, 0, 0, 0);

    LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_COUNTER_ENABLE, 0, 0, 0, 0);

    LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_COUNTER_ENABLE, 1, 0, 0, 0);

    LJUD.GoOne(ljDevice.ljhandle);

}

catch (Exception e)

{

 

3.       Setup Channel and Start Streaming

try

{

 

    LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.AIN_RESOLUTION, Resolution, 0, 0);

 

    foreach (var ljchan in channels)

    {

        if (LabJackChannel.IsCounterType(ljchan.RangeTypeName))

        {

            LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_COUNTER_ENABLE, (int)(ljchan.ChannelIndex), 1, 0, 0);

        }

        else

        {

            var type = LabJackChannel.GetRangeType(ljchan.RangeTypeName);

            LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_AIN_RANGE, (LJUD.CHANNEL)(ljchan.ChannelIndex),

                            (double)type, 0, 0);

        }

    }

 

    LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.STREAM_SCAN_FREQUENCY, ScanRate, 0, 0);

 

    int _channels = GetNumberOfChannels(channels);

LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.STREAM_BUFFER_SIZE, 5 * ScanRate *  

                        SampleInterval.TotalSeconds * _channels, 0, 0);

 

    LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.STREAM_WAIT_MODE, (double)LJUD.STREAMWAITMODES.NONE, 0, 0);

 

    LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.CLEAR_STREAM_CHANNELS, 0, 0, 0, 0);

 

    foreach (var ljchan in channels)

    {

        if (LabJackChannel.IsCounterType(ljchan.RangeTypeName))

        {

            LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.ADD_STREAM_CHANNEL, 210, 0, 0, 0);

        }

        else

        {

            LJUD.AddRequest(ljDevice.ljhandle, LJUD.IO.ADD_STREAM_CHANNEL, (int)ljchan.ChannelIndex, 0, 0, 0);

        }

    }

 

    LJUD.GoOne(ljDevice.ljhandle);

 

    LJUD.IO ioType = 0;

    LJUD.CHANNEL channel = 0;

    double dblValue = 0;

    double dummyDouble = 0;

    int dummyInt = 0;

 

               

    LJUD.GetFirstResult(ljDevice.ljhandle, ref ioType, ref channel, ref dblValue, ref dummyInt, ref dummyDouble);

 

    bool isFinished = false;

 

    while (!isFinished)

    {

        try

        {

           LJUD.GetNextResult(ljDevice.ljhandle, ref ioType, ref channel, ref dblValue, ref dummyInt, ref dummyDouble);

        }

        catch (LabJackUDException exc)

        {

           if (exc.LJUDError == UE9.LJUDERROR.NO_MORE_DATA_AVAILABLE)

              isFinished = true;

           else

           {

               // report error            

               return false;

           }

        }

     }

 

     LJUD.eGet(ljDevice.ljhandle, LJUD.IO.START_STREAM, 0, ref dblValue, 0);

 

}

catch (Exception e)

{

4.       Timer Callback to Read

try

{

    int _channels = GetNumberOfChannels(channels);

    int numScansRequested = (int) (5 * ScanRate * SampleInterval.TotalSeconds * _channels);

    double dnumScansRequested = (int)(5 * ScanRate * SampleInterval.TotalSeconds);

 

    if (dataarray == null)

    {

        dataarray = new double[numScansRequested];

    }

 

    for (int i = 0; i < numScansRequested; i++) dataarray[i] = double.NaN;

 

    LJUD.eGet(ljDevice.ljhandle, LJUD.IO.GET_STREAM_DATA, LJUD.CHANNEL.ALL_CHANNELS, ref dnumScansRequested, dataarray);

               

    double dblCommBacklog = 0;

    double dblUDBacklog = 0;

    LJUD.eGet(ljDevice.ljhandle, LJUD.IO.GET_CONFIG, LJUD.CHANNEL.STREAM_BACKLOG_COMM, ref dblCommBacklog, 0);

    LJUD.eGet(ljDevice.ljhandle, LJUD.IO.GET_CONFIG, LJUD.CHANNEL.STREAM_BACKLOG_UD, ref dblUDBacklog, 0);

    if (dblCommBacklog != 0 || dblUDBacklog != 0)

    {

       // report

    }

               

    // check if empty buffer read

}

catch (LabJackUDException e)

{

5.       Stop Streaming

try

{

    double dummyDouble = 0;

    double[] dummyDoubleArray = { 0 };

LJUD.eGet(ljDevice.ljhandle, LJUD.IO.STOP_STREAM, 0, ref dummyDouble, dummyDoubleArray);

}

catch (Exception e)

 

6.       Re-connection

If any exception thrown or empty buffer read (for several times) in stage 5, we will try to reopen a connection and setup the channels, start streaming again

 

     6.1 ljDevice = null;

     6.2 call stage 1. Open, if successful, then

     6.3 call stage 2. Clear Counter Timer, if ok, then

     6.4 call stage 3. Setup channels and start streaming

    

 

The trouble is when the network is down for a long time, the stage 6 will always failed. I tried to open, close and reopen again, and add some code to stop streaming after first successful opening.

 

One observation, one the LJUD.OpenLabJack(LJUD.DEVICE.UE9, connectiontype, deviceAddress, true, ref ljDevice.ljhandle) call is successful for the first time, any subsequent call will always ok even the network cable is unplugged. I checked the handle number, it all the same, not quite sure if there is any new socket connection actually made after the first time.

 

Thank you for your help.



#2 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 05 August 2014 - 09:40 AM

The LabJackUD library will always return the same handle for a given LabJack once that LabJack is first opened.  i.e. whether or not the open call succeedes is not based on whether the LabJack is currently connected to.  This is due to several reasons, but one of the main ones is that in order to detect whether a TCP connection is still valid, the only way to verify that is to send a packet and see if you get a response.  For instance, if you have a TCP connection between two PCs, and you remove a cable between the two (but not connected to either) both sides will still consider the TCP connection valid until it tries to send a packet.  When that packet fails, that side can close the TCP connection but the other side will still consider it open.  This can make things tricky.

 

Thus, the LJUD.OpenLabJack() call should not be used to check for network connectivity.  To do that, you should read something from the LabJack using that handle.  For instance, you can use LJ_ioGET_CONFIG with LJ_chSERIAL_NUMBER or read an analog or digital input using eAIN() or eDI(). 

 

The LabJackUD library will also try and keep that connection open automatically.  So the creation/destruction of the connection is handled independently and automatically once the LabJack is first opened.

 

If you call the Close() function from the LabJackUD library, then you will have to call OpenLabJack() again to re-open the device and get a new handle.  This would work, and sometimes fixes issues, but shouldn't be necessary.

 

When you say stage 6 fails, how does it fail?  Do you get an error back from one of the LabJackUD calls?  If so, which error and which call?



#3 RPS_metocean

RPS_metocean
  • Members
  • 5 posts

Posted 05 August 2014 - 07:53 PM

Thank you for prompt reply.

 

When trying to recover in stage 6, after several minutes network down, I will have a "communication error" whenever any LJUD call to send command to the device, eg, LJUD.GoOne(ljDevice.ljhandle) after some addrequest. Of course, open always successful as you said.

 

I tried LJUD.Close(), it is sort of working, but there is an unhandled exception thrown as follows:

 

System.AccessViolationException was unhandled
  HResult=-2147467261
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=LJUDDotNet
  StackTrace:
       at LabJack.LabJackUD.LJUD.UDClose()
       at LabJack.LabJackUD.LJUD.Close()
      ......
 
Normal try-catch couldn't handle that.


#4 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 06 August 2014 - 03:40 PM

That exception sounds like a bug we recently fixed in the LabJackUD library but haven't yet released publically.  Can you send us an email at [email protected]?  If you do I can send you a version of that copy of the LabJackUD.dll to test and see if it gets rid of the access violation.



#5 RPS_metocean

RPS_metocean
  • Members
  • 5 posts

Posted 06 August 2014 - 05:58 PM

Thanks. I'll send my email to [email protected] so that I can test your new version of the LabJackUD.dll.

Meanwhile, I use attribute [HandleProcessCorruptedStateExceptions] to get the exception handled so that every is still running and

recovery from network outrage works nicely.





Also tagged with one or more of these keywords: C#, UE9 PRO, Streaming, Counter0, re-connection

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users