// Copyright © 2006-2010 Travis Robinson. All rights reserved.
//
// website: http://sourceforge.net/projects/libusbdotnet
// e-mail: libusbdotnet@gmail.com
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or
// visit www.gnu.org.
//
//
using System;
using System.Threading;
using LibUsbDotNet.Main;
namespace MonoLibUsb
{
///
/// Manages a static Libusb-1.0 and "handle_events" thread for simplified asynchronous IO.
///
///
/// This class contains its own that is initialized with one of the overloaded MonoUsbEventHandler.Init() functions.
/// This class contains a static thread that execute . See the and methods.
///
public static class MonoUsbEventHandler
{
private static readonly ManualResetEvent mIsStoppedEvent = new ManualResetEvent(true);
private static bool mRunning;
private static MonoUsbSessionHandle mSessionHandle;
internal static Thread mUsbEventThread;
private static ThreadPriority mPriority = ThreadPriority.Normal;
private static UnixNativeTimeval mWaitUnixNativeTimeval;
///
/// Gets the session handle.
///
///
/// Used for MonoLibUsb members that require the parameter.
///
public static MonoUsbSessionHandle SessionHandle
{
get { return mSessionHandle; }
}
///
/// False if the handle events thread is running.
///
public static bool IsStopped
{
get { return mIsStoppedEvent.WaitOne(0, false); }
}
///
/// Thread proirity to use for the handle events thread.
///
public static ThreadPriority Priority
{
get { return mPriority; }
set {mPriority=value;}
}
///
/// Stops the handle events thread and closes the session handle.
///
public static void Exit()
{
Stop(true);
if (mSessionHandle == null) return;
if (mSessionHandle.IsInvalid) return;
mSessionHandle.Close();
mSessionHandle = null;
}
private static void HandleEventFn(object oHandle)
{
MonoUsbSessionHandle sessionHandle = oHandle as MonoUsbSessionHandle;
mIsStoppedEvent.Reset();
while (mRunning)
MonoUsbApi.HandleEventsTimeout(sessionHandle, ref mWaitUnixNativeTimeval);
mIsStoppedEvent.Set();
}
///
/// Initializes the and sets a custom polling interval.
///
/// polling interval seconds
/// polling interval milliseconds
///
///
public static void Init(long tvSec, long tvUsec) { Init(new UnixNativeTimeval(tvSec, tvUsec)); }
///
/// Initializes the .
///
///
/// If the session has already been initialized, this method does nothing.
/// The handle events thread is not started until the method is called.
/// Uses the MonoLibUsb polling interval for .
///
public static void Init() { Init(UnixNativeTimeval.Default); }
private static void Init(UnixNativeTimeval unixNativeTimeval)
{
if (IsStopped && !mRunning && mSessionHandle==null)
{
mWaitUnixNativeTimeval = unixNativeTimeval;
mSessionHandle=new MonoUsbSessionHandle();
if (mSessionHandle.IsInvalid)
{
mSessionHandle = null;
throw new UsbException(typeof (MonoUsbApi), String.Format("Init:libusb_init Failed:Invalid Session Handle"));
}
}
}
///
/// Starts the handle events thread.
///
///
/// If the thread is already running, this method does nothing.
///
/// Using a seperate thread which executes can simplify asynchronous I/O
/// and improve performance in multi-threaded applications which use multiple endpoints.
///
///
///
/// True if the thread is started or is already running.
///
public static bool Start()
{
if (IsStopped && !mRunning && mSessionHandle!=null)
{
mRunning = true;
mUsbEventThread = new Thread(HandleEventFn);
mUsbEventThread.Priority = mPriority;
mUsbEventThread.Start(mSessionHandle);
}
return true;
}
///
/// Stops the handle events thread.
///
///
/// Calling this method when the thread is not running will have no affect.
///
/// If the thread is running, this method must be called before the application exits.
/// Failure to do so will cause the application to hang.
///
///
/// If true, wait for the thread to exit before returning.
public static void Stop(bool bWait)
{
if (!IsStopped && mRunning)
{
mRunning = false;
if (bWait)
{
bool bSuccess = mUsbEventThread.Join((int)((mWaitUnixNativeTimeval.tv_sec * 1000 + mWaitUnixNativeTimeval.tv_usec) * 1.2));
//bool bSuccess = mIsStoppedEvent.WaitOne((int)((mWaitUnixNativeTimeval.tv_sec * 1000 + mWaitUnixNativeTimeval.tv_usec) * 1.2), false);
if (!bSuccess)
{
mUsbEventThread.Abort();
throw new UsbException(typeof(MonoUsbEventHandler), "Critical timeout failure! MonoUsbApi.HandleEventsTimeout did not return within the allotted time.");
//LibUsbDotNet.UsbError.Error(ErrorCode.UnknownError, 0, "Critical timeout failure!", typeof(MonoUsbEventHandler));
//mIsStoppedEvent.Set();
}
}
mUsbEventThread = null;
}
}
}
}