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)
{
{
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;
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;
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;
{
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);
}
<ItemGroup>
<ProjectReference Include="..\Tizen\Tizen.csproj" />
<ProjectReference Include="..\Tizen.Log\Tizen.Log.csproj" />
+ <ProjectReference Include="..\Tizen.System.Information\Tizen.System.Information.csproj" />
</ItemGroup>
</Project>
/// <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);
}
}
/// <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()
_parent.ThrowIfDisposed();
}
+ internal void ThrowIfDeviceNotOpened()
+ {
+ _parent.ThrowIfDeviceNotOpened();
+ }
+
#region IDisposable Support
private bool disposedValue = false;
{
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>
/// <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);
}
}
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;
}
}
/// <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");
}
}
/// <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");
}
_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;
{
if (!disposedValue)
{
- if (IsOpened)
- {
- Close();
- }
- foreach(var config in _configurations.Values) {
- config.Dispose();
- }
- _configurations.Clear();
_handle.Dispose();
disposedValue = true;
}
* limitations under the License.
*/
-using System;
-
namespace Tizen.System.Usb
{
/// <summary>
/// <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;
}
}
/// <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.
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;
}
public void Release()
{
ThrowIfDisposed();
+ _parent.ThrowIfDeviceNotOpened();
+
if (_isClaimed == false) return;
_handle.ReleaseInterface().ThrowIfFailed("Failed to release interface");
_isClaimed = false;
/// <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>
get
{
ThrowIfDisposed();
- return _devices;
+ return _context.GetDeviceList().Select(devHandle => new UsbDevice(this, devHandle)).ToList();
}
}
/// <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()
{
if (!disposedValue)
{
- if (_hotpluggedHandle != null) _hotpluggedHandle.Dispose();
- if (_context != null) _context.Dispose();
+ if (_hotpluggedAttachHandle != null) _hotpluggedAttachHandle.Dispose();
+ if (_hotpluggedDetachHandle != null) _hotpluggedDetachHandle.Dispose();
disposedValue = true;
}
}