lifeemotions / knx.net

KNX.net provides a KNX API for .NET
MIT License
101 stars 47 forks source link

conn.Action hangs with connection not established #43

Open FalcoGer opened 6 years ago

FalcoGer commented 6 years ago

You can set up a connection like so:

conn = new KnxConnectionTunneling(knxIp, 3671, ownIp, 3672);
conn.KnxConnectedDelegate += Connected;
conn.KnxEventDelegate += Event;
conn.KnxStatusDelegate += Status;
conn.KnxDisconnectedDelegate += Disconnected;
conn.Connect();

And when the connection can't be established (I turned off my knx test setup for this), you can still do conn.Action(GA, val) this in turn will cause the application to hang indefenitely at KnxLockManager.cs (60) private void SendLock() _sendLock.Wait()

FalcoGer commented 5 years ago

As workaround for this I created this wrapper function:

/// <summary>
/// Send a byte array to the specified group address
/// </summary>
/// <param name="address">Target group address</param>
/// <param name="data">The data to send</param>
/// <returns>Success or not</returns>
public bool Action(string address, byte[] data)
{
    try
    {
        if (ChkKnxGroupAddress(address))
        {
            if (ConnectedState)
            {
                Thread t = new Thread(() => { try { conn.Action(address, data); } catch (Exception ex) { Helper.PrintException(ex); } })
                {
                    Name = "Action"
                };

                bool finished = RunWithTimeout(t, ACTIVE_KNX_TIMEOUT);
                return finished ? finished : throw new TimeoutException("Thread " + t.Name + " didn't finish in it's alloted time of " + ACTIVE_KNX_TIMEOUT.ToString());
            }
            else
            {
                return false;
            }
        }
        else
        {
            throw new ArgumentException("Invalid knx groupaddress " + address);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("ACTION - EXCEPTION: " + ex.ToString());
        return false;
    }
}

/// <summary>
/// Run a thread with a timeout.
/// </summary>
/// <param name="workerThread">The thread to run</param>
/// <param name="timeout">How long the thread may live</param>
/// <returns>true if the thread finished before the time, false if it was aborted prematurely</returns>
private static bool RunWithTimeout(System.Threading.Thread workerThread, TimeSpan timeout)
{
    workerThread.Start();

    bool finished = workerThread.Join(timeout);
    if (!finished)
    {
        workerThread.Abort();
    }
    return finished;
}