// 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; } } } }