[USB] Update exception handling code 96/162096/3
authorDinesh Dwivedi <dinesh.d@samsung.com>
Wed, 29 Nov 2017 09:34:56 +0000 (15:04 +0530)
committerDinesh Dwivedi <dinesh.d@samsung.com>
Wed, 29 Nov 2017 09:34:56 +0000 (15:04 +0530)
Change-Id: I4d0a22c75490971dcd27f627e83187ad09b7c108
Signed-off-by: Dinesh Dwivedi <dinesh.d@samsung.com>
src/Tizen.System.Usb/Interop/Interop.ErrorCode.cs
src/Tizen.System.Usb/Interop/Interop.SafeUsbHandle.cs
src/Tizen.System.Usb/Tizen.System.Usb.csproj
src/Tizen.System.Usb/Usb/UsbConfiguration.cs
src/Tizen.System.Usb/Usb/UsbDevice.cs
src/Tizen.System.Usb/Usb/UsbDeviceStrings.cs
src/Tizen.System.Usb/Usb/UsbInterface.cs
src/Tizen.System.Usb/Usb/UsbManager.cs

index 38d9ee2..6c97a70 100644 (file)
@@ -43,7 +43,7 @@ internal static partial class Interop
 
 internal static class ErrorCodeExtensions
 {
-    private const string LogTag = "Tizen.System.Usb";
+    private const string LogTag = "USB_HOST_CSHARP";
 
     internal static bool IsSuccess(this Interop.ErrorCode err)
     {
@@ -63,7 +63,8 @@ internal static class ErrorCodeExtensions
     {
         if (err.IsFailed())
         {
-            Log.Debug(LogTag, $"{msg}, err: {err.ToString()}", file, func, line);
+            Log.Info(LogTag, $"{msg}, err: {err.ToString()}", file, func, line);
+            Console.WriteLine($"I/{LogTag}: {msg}, err: {err.ToString()}");
             return false;
         }
         return true;
@@ -78,6 +79,7 @@ internal static class ErrorCodeExtensions
         if (err.IsFailed())
         {
             Log.Error(LogTag, $"{msg}, err: {err.ToString()}", file, func, line);
+            Console.WriteLine($"E/{LogTag}: {msg}, err: {err.ToString()}");
             throw err.GetException(msg);
         }
         return true;
index 086b28e..88c34f2 100755 (executable)
@@ -26,6 +26,12 @@ internal static partial class Interop
     public delegate ErrorCode GetDescriptorString(ref int length, byte[] data);
     public delegate ErrorCode SetterMethod<T>(T value);
 
+    internal static void Log(string msg, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0)
+    {
+        Tizen.Log.Error("USB_HOST_CSHARP", $"{msg}", file, func, line);
+        Console.WriteLine($"USB_HOST_CSHARP: {System.IO.Path.GetFileName(file)}: {func}({line}) > {msg}");
+    }
+
     internal static T NativeGet<T>(GetterMethod<T> getter, [CallerMemberName] string propertyName = "")
     {
         T value;
@@ -43,7 +49,14 @@ internal static partial class Interop
     {
         int len = MaxStringDescriptorSize;
         byte[] data = new byte[len];
-        getter(ref len, data).ThrowIfFailed($"Native setter for {propertyName} failed");
+        var err = getter(ref len, data);
+        if (err.IsFailed() && err == ErrorCode.InvalidParameter)
+        {
+            // this happens if descriptor string is empty
+            err.WarnIfFailed($"Failed to get DescriptorString");
+            return "";
+        }
+        var descriptor = Encoding.GetEncoding(language).GetString(data, 0, len);
         return Encoding.GetEncoding(language).GetString(data, 0, len);
     }
 
index 1407501..9ff6f14 100755 (executable)
@@ -7,6 +7,7 @@
   <ItemGroup>
     <ProjectReference Include="..\Tizen\Tizen.csproj" />
     <ProjectReference Include="..\Tizen.Log\Tizen.Log.csproj" />
+    <ProjectReference Include="..\Tizen.System.Information\Tizen.System.Information.csproj" />
   </ItemGroup>
 
 </Project>
index 53acadb..bb5582e 100755 (executable)
@@ -103,12 +103,14 @@ namespace Tizen.System.Usb
         /// <summary>
         /// Configuration string.
         /// </summary>
+        /// <exception cref="InvalidOperationException"> Throws exception if device is disconnected or not opened for operation. </exception>
         /// <since_tizen> 4 </since_tizen>
         public string ConfigurationString
         {
             get
             {
                 ThrowIfDisposed();
+                _parent.ThrowIfDeviceNotOpened();
                 return Interop.DescriptorString(_handle.GetConfigStr);
             }
         }
@@ -116,14 +118,13 @@ namespace Tizen.System.Usb
         /// <summary>
         /// Set this configuration as active configuration for the device.
         /// </summary>
-        /// <exception cref="InvalidOperationException">
-        /// Throws exception if device is disconnected or not opened for operation or busy as its interfaces are currently claimed.
-        /// </exception>
+        /// <exception cref="InvalidOperationException"> Throws exception if device is disconnected or not opened for operation. </exception>
         /// <since_tizen> 4 </since_tizen>
         public void SetAsActive()
         {
             ThrowIfDisposed();
-            _handle.SetAsActive();
+            _parent.ThrowIfDeviceNotOpened();
+            _handle.SetAsActive().ThrowIfFailed("Failed to activate this configuration");
         }
 
         internal void ThrowIfDisposed()
@@ -132,6 +133,11 @@ namespace Tizen.System.Usb
             _parent.ThrowIfDisposed();
         }
 
+        internal void ThrowIfDeviceNotOpened()
+        {
+            _parent.ThrowIfDeviceNotOpened();
+        }
+
         #region IDisposable Support
         private bool disposedValue = false;
 
index 6d7bf01..7dbb34d 100755 (executable)
@@ -28,20 +28,11 @@ namespace Tizen.System.Usb
     {
         internal readonly Interop.HostDeviceHandle _handle;
         private readonly UsbManager _parent;
-        private Dictionary<int, UsbConfiguration> _configurations = new Dictionary<int, UsbConfiguration>();
 
         internal UsbDevice(UsbManager parent, Interop.HostDeviceHandle handle)
         {
             _parent = parent;
             _handle = handle;
-
-            int count = Interop.NativeGet<int>(_handle.GetNumConfigurations);
-            for (int i = 0; i < count; ++i)
-            {
-                IntPtr configHandle;
-                _handle.GetConfig(i, out configHandle);
-                _configurations.Add(i, new UsbConfiguration(this, new Interop.UsbConfigHandle(configHandle)));
-            }
         }
 
         /// <summary>
@@ -112,16 +103,17 @@ namespace Tizen.System.Usb
         /// <summary>
         /// Active configuration for the device.
         /// </summary>
-        /// <exception cref="InvalidOperationException">Throws exception if device is disconnected.</exception>
+        /// <exception cref="InvalidOperationException">Throws exception if device is disconnected or not opened for operation. </exception>
         /// <since_tizen> 4 </since_tizen>
         public UsbConfiguration ActiveConfiguration
         {
             get
             {
                 ThrowIfDisposed();
+                ThrowIfDeviceNotOpened();
                 IntPtr handle = Interop.NativeGet<IntPtr>(_handle.GetActiveConfig);
                 Interop.UsbConfigHandle configHandle = new Interop.UsbConfigHandle(handle);
-                return _configurations.Values.Where(config => config._handle == configHandle).First();
+                return new UsbConfiguration(this, configHandle);
             }
         }
 
@@ -134,7 +126,15 @@ namespace Tizen.System.Usb
             get
             {
                 ThrowIfDisposed();
-                return _configurations;
+                var configurations = new Dictionary<int, UsbConfiguration>();
+                int count = Interop.NativeGet<int>(_handle.GetNumConfigurations);
+                for (int i = 0; i < count; ++i)
+                {
+                    IntPtr configHandle;
+                    _handle.GetConfig(i, out configHandle);
+                    configurations.Add(i, new UsbConfiguration(this, new Interop.UsbConfigHandle(configHandle)));
+                }
+                return configurations;
             }
         }
 
@@ -154,12 +154,14 @@ namespace Tizen.System.Usb
         /// <summary>
         /// String associated with device.
         /// </summary>
+        /// <exception cref="InvalidOperationException"> Throws exception if device is disconnected or not opened for operation. </exception>
         /// <since_tizen> 4 </since_tizen>
         public UsbDeviceStrings Strings
         {
             get
             {
                 ThrowIfDisposed();
+                ThrowIfDeviceNotOpened();
                 return new UsbDeviceStrings(this, "us-ascii");
             }
         }
@@ -180,12 +182,11 @@ namespace Tizen.System.Usb
         /// <summary>
         /// Closes device for operations.
         /// </summary>
-        /// <exception cref="InvalidOperationException">Throws exception if device is not opened for operation.</exception>
         /// <since_tizen> 4 </since_tizen>
         public void Close()
         {
             ThrowIfDisposed();
-            if (IsOpened == false) throw new InvalidOperationException("Device must be opened for operation first");
+            if (IsOpened == false) return;
 
             _handle.CloseHandle().ThrowIfFailed("Failed to close device for use");
         }
@@ -196,6 +197,11 @@ namespace Tizen.System.Usb
             _parent.ThrowIfDisposed();
         }
 
+        internal void ThrowIfDeviceNotOpened()
+        {
+            if (IsOpened == false) throw new InvalidOperationException("USB Device is should be in open state for this operation");
+        }
+
         #region IDisposable Support
         private bool disposedValue = false;
 
@@ -207,14 +213,6 @@ namespace Tizen.System.Usb
         {
             if (!disposedValue)
             {
-                if (IsOpened)
-                {
-                    Close();
-                }
-                foreach(var config in _configurations.Values) {
-                    config.Dispose();
-                }
-                _configurations.Clear();
                 _handle.Dispose();
                 disposedValue = true;
             }
index d5ac067..a682b73 100755 (executable)
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-using System;
-
 namespace Tizen.System.Usb
 {
     /// <summary>
@@ -24,58 +22,29 @@ namespace Tizen.System.Usb
     /// <since_tizen> 4 </since_tizen>
     public class UsbDeviceStrings
     {
-        private readonly UsbDevice _device;
-        private string _language;
-
         internal UsbDeviceStrings(UsbDevice device, string language)
         {
-            _device = device;
-            _language = language;
+            Manufacturer = Interop.DescriptorString(device._handle.GetManufacturerStr, language);
+            Product = Interop.DescriptorString(device._handle.GetProductStr, language);
+            Serial = Interop.DescriptorString(device._handle.GetSerialNumberStr, language);
         }
 
         /// <summary>
         /// Gets string describing device manufacturer.
         /// </summary>
-        /// <exception cref="InvalidOperationException">Throws exception if device is disconnected or not opened for operation.</exception>
-        /// <exception cref="UnauthorizedAccessException">Throws exception if user has insufficient permission on device.</exception>
         /// <since_tizen> 4 </since_tizen>
-        public string Manufacturer
-        {
-            get
-            {
-                _device.ThrowIfDisposed();
-                return Interop.DescriptorString(_device._handle.GetManufacturerStr, _language);
-            }
-        }
+        public string Manufacturer;
 
         /// <summary>
         /// Gets product string of device
         /// </summary>
-        /// <exception cref="InvalidOperationException">Throws exception if device is not opened for operation.</exception>
-        /// <exception cref="UnauthorizedAccessException">Throws exception if user has insufficient permission on device.</exception>
         /// <since_tizen> 4 </since_tizen>
-        public string Product
-        {
-            get
-            {
-                _device.ThrowIfDisposed();
-                return Interop.DescriptorString(_device._handle.GetProductStr, _language);
-            }
-        }
+        public string Product;
 
         /// <summary>
         /// Gets serial number of a device.
         /// </summary>
-        /// <exception cref="InvalidOperationException">Throws exception if device is not opened for operation.</exception>
-        /// <exception cref="UnauthorizedAccessException">Throws exception if user has insufficient permission on device.</exception>
         /// <since_tizen> 4 </since_tizen>
-        public string Serial
-        {
-            get
-            {
-                _device.ThrowIfDisposed();
-                return Interop.DescriptorString(_device._handle.GetSerialNumberStr, _language);
-            }
-        }
+        public string Serial;
     }
 }
index 1fd26d2..bf5ddae 100755 (executable)
@@ -91,13 +91,17 @@ namespace Tizen.System.Usb
         /// <summary>
         /// Gets string describing an interface.
         /// </summary>
-        /// <returns></returns>
+        /// <exception cref="InvalidOperationException"> Throws exception if device is disconnected or not opened for operation. </exception>
         /// <since_tizen> 4 </since_tizen>
-        public string InterfaceString()
+        public string InterfaceString
+        {
+            get
         {
             ThrowIfDisposed();
+                _parent.ThrowIfDeviceNotOpened();
             return Interop.DescriptorString(_handle.GetStr);
         }
+        }
 
         /// <summary>
         /// Claims interface on a device. Interface must be claimed first to perform I/O operations.
@@ -110,8 +114,14 @@ namespace Tizen.System.Usb
         public void Claim(bool force)
         {
             ThrowIfDisposed();
+            _parent.ThrowIfDeviceNotOpened();
+
             if (_isClaimed == true) return;
-            _handle.ClaimInterface(force).ThrowIfFailed("Failed to claim interface");
+            var err = _handle.ClaimInterface(force);
+            if (err.IsFailed() && err != Interop.ErrorCode.ResourceBusy)
+            {
+                err.ThrowIfFailed("Failed to claim interface");
+            }
             _isClaimed = true;
         }
 
@@ -125,6 +135,8 @@ namespace Tizen.System.Usb
         public void Release()
         {
             ThrowIfDisposed();
+            _parent.ThrowIfDeviceNotOpened();
+
             if (_isClaimed == false) return;
             _handle.ReleaseInterface().ThrowIfFailed("Failed to release interface");
             _isClaimed = false;
index bb3211e..366ca76 100755 (executable)
@@ -26,30 +26,46 @@ namespace Tizen.System.Usb
     /// <since_tizen> 4 </since_tizen>
     public class UsbManager : IDisposable
     {
-        private readonly Interop.UsbContextHandle _context = null;
-        private readonly Interop.HostHotplugHandle _hotpluggedHandle = null;
-        private List<UsbDevice> _devices = new List<UsbDevice>();
+        // It needs to be static as its destroy function must be called after closing all devices and before application close.
+        // It has to be called to clean the memory used by library.
+        private static readonly Interop.UsbContextHandle _context = null;
+
+        private readonly Interop.HostHotplugHandle _hotpluggedAttachHandle = null;
+        private readonly Interop.HostHotplugHandle _hotpluggedDetachHandle = null;
+
+        static UsbManager()
+        {
+            bool isSupported;
+            Information.TryGetValue("http://tizen.org/feature/usb.host", out isSupported);
+            if (isSupported)
+            {
+                _context = Interop.UsbContextHandle.GetContextHandle();
+            }
+        }
 
         /// <summary>
         /// USB Manager Constructor.
         /// </summary>
+        /// <exception cref="NotSupportedException">Throws exception if USB host feature is not enabled.</exception>
         /// <since_tizen> 4 </since_tizen>
         public UsbManager()
         {
-            _context = Interop.UsbContextHandle.GetContextHandle();
-            _devices = _context.GetDeviceList().Select(devHandle => new UsbDevice(this, devHandle)).ToList();
+            if (_context == null) throw new NotSupportedException("USB host operations are not supported in this device");
+
+            IntPtr hotpluggedAttachHandle, hotpluggedDetachHandle;
+            _context.SetHotplugCb(HostHotplugAttachCallback, Interop.HotplugEventType.Attach,
+                IntPtr.Zero, out hotpluggedAttachHandle).ThrowIfFailed("Failed to set hot plugged callback");
 
-            IntPtr hotpluggedHandle;
-            _context.SetHotplugCb(HostHotplugCallback, Interop.HotplugEventType.Any,
-                IntPtr.Zero, out hotpluggedHandle).ThrowIfFailed("Failed to set hot plugged callback");
+            _context.SetHotplugCb(HostHotplugDetachCallback, Interop.HotplugEventType.Detach,
+                IntPtr.Zero, out hotpluggedDetachHandle).ThrowIfFailed("Failed to set hot plugged callback");
 
-            _hotpluggedHandle = new Interop.HostHotplugHandle(hotpluggedHandle);
+            _hotpluggedAttachHandle = new Interop.HostHotplugHandle(hotpluggedAttachHandle);
+            _hotpluggedDetachHandle = new Interop.HostHotplugHandle(hotpluggedDetachHandle);
         }
 
         /// <summary>
         /// This function returns list of USB devices attached to system.
         /// </summary>
-        /// <exception cref="NotSupportedException">Throws exception if USB host feature is not enabled.</exception>
         /// <exception cref="OutOfMemoryException">Throws exception in case of insufficient memory.</exception>
         /// <exception cref="UnauthorizedAccessException">Throws exception if user has insufficient permission on device.</exception>
         /// <since_tizen> 4 </since_tizen>
@@ -58,7 +74,7 @@ namespace Tizen.System.Usb
             get
             {
                 ThrowIfDisposed();
-                return _devices;
+                return _context.GetDeviceList().Select(devHandle => new UsbDevice(this, devHandle)).ToList();
             }
         }
 
@@ -68,30 +84,30 @@ namespace Tizen.System.Usb
         /// <since_tizen> 4 </since_tizen>
         public event EventHandler<HotPluggedEventArgs> DeviceHotPlugged;
 
-        internal void HostHotplugCallback(IntPtr devHandle, IntPtr userData)
+        internal void HostHotplugAttachCallback(IntPtr devHandle, IntPtr userData)
         {
             Interop.HostDeviceHandle handle = new Interop.HostDeviceHandle(devHandle);
-            UsbDevice device = _devices.Where(dev => dev._handle == handle).FirstOrDefault();
-            if (device == null)
+            UsbDevice device = new UsbDevice(this, handle);
+            if (DeviceHotPlugged != null)
             {
-                device = new UsbDevice(this, handle);
-                _devices.Add(device);
+                DeviceHotPlugged.Invoke(this, new HotPluggedEventArgs(device, HotplugEventType.Attach));
+            }
 
-                if (DeviceHotPlugged != null)
-                {
-                    DeviceHotPlugged.Invoke(this, new HotPluggedEventArgs(device, HotplugEventType.Attach));
-                }
+            //AvailableDevices.Remove(device);
+            // do we need to dispose device here ?
             }
-            else
-            {
-                if (DeviceHotPlugged != null)
-                {
-                    DeviceHotPlugged.Invoke(this, new HotPluggedEventArgs(device, HotplugEventType.Detach));
-                }
 
-                _devices.Remove(device);
-                // do we need to dispose device here ?
+        internal void HostHotplugDetachCallback(IntPtr devHandle, IntPtr userData)
+            {
+            Interop.HostDeviceHandle handle = new Interop.HostDeviceHandle(devHandle);
+            UsbDevice device = new UsbDevice(this, handle);
+            if (DeviceHotPlugged != null)
+            {
+                DeviceHotPlugged.Invoke(this, new HotPluggedEventArgs(device, HotplugEventType.Detach));
             }
+
+            //AvailableDevices.Remove(device);
+            // do we need to dispose device here ?
         }
 
         internal void ThrowIfDisposed()
@@ -106,8 +122,8 @@ namespace Tizen.System.Usb
         {
             if (!disposedValue)
             {
-                if (_hotpluggedHandle != null) _hotpluggedHandle.Dispose();
-                if (_context != null) _context.Dispose();
+                if (_hotpluggedAttachHandle != null) _hotpluggedAttachHandle.Dispose();
+                if (_hotpluggedDetachHandle != null) _hotpluggedDetachHandle.Dispose();
                 disposedValue = true;
             }
         }