# Dudas con detección de coneccion/desconeccion de dispositivo USB



## Moyano Jonathan (Jul 16, 2010)

Bueno muchos dirán ......pero es algo muy sencillo de hacer  . La verdad NO, hasta ahora no había tenido ningún tipo de problemas en el uso de la librería mcHID.dl, pero en el camino me he encontrado con dificultades bastante interesantes, una de las cuales voy a tratar de exponer ahora para que alguien que tenga más conocimiento de programación pueda ayudarme.

Lo que trato de descubrir es como detectar la conexión fisica de un dispositivo determinado al host o PC.
mi programa de aplicación tiene un botón en donde nosotros conectamos o desconectamos de manera manual el dispositivo , a su vez tenemos la facilidad de configurar el VID, PID y los tamaños de los buffers de entrada y salida.
La aplicación es la siguiente:





Bueno como se ve en la inmágen podemos configurar los parámetros básicos del USB y tenemos un botón de conección / desconección.

Mi problema radica en cuanto yo desconecto el dispositivo de forma física , es decir desconecto el cable que une el dispositivo con el host ...dicha desconexion no es posible detectarla si el programa de aplicación no está conectado al handler....les muestro mi error..





yo en mi forma de buscar el error me di cuenta que la conexión se detecta mediante una interrupción que produce el dispositivo al enlazarse con el handler ...esta interrupción activa un flag o bandera y en la aplicación la activación de este flag nos indica o no la condición fisica en la que se encuentra nuestro dispositivo.

Paso a mostrarles el código que hace esto posible:


> Private Function WinProc(ByVal pHWnd As Integer, ByVal pMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
> If pMsg = WM_HID_EVENT Then
> Select Case wParam
> 
> ...


y su conjunto de flags o banderas definidas:

Private Const NOTIFY_PLUGGED As Short = 1              CONECCIÓN DEL DISPOSITIVO
    Private Const NOTIFY_UNPLUGGED As Short = 2      DESCONECCIÓN DEL DISPOSITIVO
    Private Const NOTIFY_CHANGED As Short = 3          
    Private Const NOTIFY_READ As Short = 4

En esta porción de código que defini anteriormente se encuentra la función que según la interrupción que produzca el dispositivo se activa alguna de las cuatro banderas....

Ahora el problema radica que estas interrupciones se producen solo cuando la aplicación está conectada al handler....y aqui muestro la función de conección:


```
Public Function ConnectToHID(ByRef targetForm As Form) As Boolean
        Dim pHostWin As Integer = targetForm.Handle.ToInt32
        FWinHandle = pHostWin
        pHostWin = hidConnect(FWinHandle)
        FPrevWinProc = DelegateSetWindowLong(FWinHandle, GWL_WNDPROC, Ref_WinProc)
        HostForm = targetForm
    End Function
```
Por lo tanto si yo me conecto primero al handler ....si me detecta la conexion fisica o desconección del dispositivo. Miren la  aplicación:





*Ahora mi pregunta es si se puede detectar primero la conección al host..y luego conectarme...es decir que la aplicación haga un scaneo para ver si hay un dispositivo conectado al host y en funcion de esto conectarme al mismo o no....*

Les dejo los códigos fuente del programa y de la librería:


```
Public Class Form1

    Dim VendorID As Short  ' Variable que contiene el ID del vendedor del producto USB.
    Dim ProductID As Short ' Variable que contiene el ID del producto USB.
    Dim phandle As Integer

    ' Declaración de Buffers de lectura / escritura.
    Dim BufferInSize As Short ' Declaramos el tamaño del buffer de entrada.
    Dim BufferOutSize As Short ' Declaramos el tamaño del buffer de salida.
    Dim BufferIn(BufferInSize) As Byte ' Variable que contiene los datos de salida cuyo tamaño lo designa BufferInSize.
    Dim BufferOut(BufferOutSize) As Byte ' Variable que contiene los datos de salida cuyo tamaño lo designa BufferOutSize

    Private Sub Hora_windows_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Hora_windows.Tick
        StatusStrip1.Items(0).Text = DateTime.Now.ToLongTimeString() ' Mostramos la hora de Windows.
    End Sub

    Private Sub SalirToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SalirToolStripMenuItem.Click
        Close() ' Cerramos la aplicación al presionar salir.
        DisconnectFromHID() ' Desconectamos el dispositivo USB.
    End Sub

    Private Sub AutorToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AutorToolStripMenuItem.Click
        MessageBox.Show("Pograma de ejemplo Nº1 HID usando mcHID.dll" & vbLf & vbLf & "Autor: Moyano Jonathan." & vbLf & "Contacto: [EMAIL="jonathan215@hotmail.com"]jonathan215@hotmail.com[/EMAIL] " & vbLf & vbLf & "http://www.forosdeelectronica.com" & vbLf & vbLf & "LICENCIA: FREEWARE", "", MessageBoxButtons.OK, MessageBoxIcon.Information) ' Leeme para el usuario.
    End Sub

    Private Sub LeemeToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LeemeToolStripMenuItem.Click
        MessageBox.Show("Programa de ejemplo Nº1 HID:" & vbLf & "Muestra una pantalla de configuración del puerto USB y" & vbLf & "también dentro de un cuadro nos muestra si el" & vbLf & "dispositivo está conectado o no.", "", MessageBoxButtons.OK, MessageBoxIcon.Information) ' Leeme para el usuario.

    End Sub

    Private Sub Conectar_dispositivo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Conectar_dispositivo.Click
        If Conectar_dispositivo.Text = "DESCONECTAR DISPOSITIVO" Then
            Conectar_dispositivo.Text = "CONECTAR DISPOSITIVO"
            DisconnectFromHID() ' Desconectamos el dispositivo USB de la aplicación.
            USB_estado.BackColor = Color.Red
            debug.Items.Add("Dispositivo desconetado por el usuario.")
            debug.Items.Add("Se puede deconectar el dispositivo del host de forma segura")
        ElseIf Conectar_dispositivo.Text = "CONECTAR DISPOSITIVO" Then
            ConnectToHID(Me) ' Enlazamos el dispositivo al programa de aplicación.
            debug.Items.Add("Dispositivo:")
            debug.Items.Add("VID:" & Hex(VendorID))
            debug.Items.Add("PID:" & Hex(ProductID))
            debug.Items.Add("IN_BUFFER: " & BufferInSize.ToString & " bytes.")
            debug.Items.Add("IN_BUFFER: " & BufferOutSize.ToString & " bytes.")
            Conectar_dispositivo.Text = "DESCONECTAR DISPOSITIVO"
        End If

    End Sub
    '**********************************************************************
    ' En caso de que el formulario se cierre el dispositivo se desconecta.
    '**********************************************************************
    Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        DisconnectFromHID()
    End Sub

    '*****************************************************************
    ' Un dispositivo USB ha sido conectado.
    '*****************************************************************
    Public Sub OnPlugged(ByVal pHandle As Integer)
        If hidGetVendorID(pHandle) = VendorID And hidGetProductID(pHandle) = ProductID Then
            USB_estado.BackColor = Color.Green
            debug.Items.Add("El dispositivo ha sido conectado")
        End If
    End Sub

    '*****************************************************************
    ' Un dispositivo USB ha sido desconectado.
    '*****************************************************************
    Public Sub OnUnplugged(ByVal pHandle As Integer)
        If hidGetVendorID(pHandle) = VendorID And hidGetProductID(pHandle) = ProductID Then
            hidSetReadNotify(hidGetHandle(VendorID, ProductID), False)
            USB_estado.BackColor = Color.Red
            debug.Items.Add("El dispositivo ha sido desconectado")
        End If
    End Sub

    '***********************************************************************
    ' Llamada a Notificación de cambios en el controlador en caso 
    ' de que todos los dispositivos hallan sido conectados o desconectados.
    '***********************************************************************
    Public Sub OnChanged()
        ' Toma el manejador del dispositivo en el cuál estemos interasados, luego
        ' luego setea esta notificación a 1 - esto asegura que tengamos una lectura.
        ' Se recibirán notificaciones siempre y cuando hayan datos para leer.
        pHandle = hidGetHandle(VendorID, ProductID)
        hidSetReadNotify(hidGetHandle(VendorID, ProductID), True)
    End Sub

    '*****************************************************************
    ' En un evento de lectura....
    '*****************************************************************
    Public Sub OnRead(ByVal pHandle As Integer)
        If hidRead(pHandle, BufferIn(0)) Then

            ' Primero leemos el reportID, BufferIn(0)
            ' Luego los demás bytes son los datos del microcontrolador...
        End If
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        USB_estado.BackColor = Color.Blue
        debug.Items.Clear() ' Limpiamos la pantalla de debug.
        debug.Items.Add("Dispositivo aún no conectado")
    End Sub

    Private Sub Vid_dispositivo_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Vid_dispositivo.TextChanged
        VendorID = (Val(Vid_dispositivo.Text))
    End Sub

    Private Sub Pid_dispositivo_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Pid_dispositivo.TextChanged
        ProductID = (Val(Pid_dispositivo.Text))
    End Sub

    Private Sub In_USB_buffer_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles In_USB_buffer.TextChanged
        BufferInSize = (Val(In_USB_buffer.Text))
    End Sub

    Private Sub Out_USB_Buffer_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Out_USB_Buffer.TextChanged
        BufferOutSize = (Val(Out_USB_Buffer.Text))
    End Sub

    Public Sub WriteSomeData() ' Si hay un dato listo para enviar...
        hidWriteEx(VendorID, ProductID, BufferOut(0))
    End Sub
End Class
```


```
Imports System.Threading
Imports System.Runtime.InteropServices


Module HIDDLLInterface
    ' this is the interface to the HID controller DLL - you should not
    ' normally need to change anything in this file.
    '
    ' WinProc() calls your main form 'event' procedures - these are currently
    ' set to..
    '
    ' MainForm.OnPlugged(ByVal pHandle as long)
    ' MainForm.OnUnplugged(ByVal pHandle as long)
    ' MainForm.OnChanged()
    ' MainForm.OnRead(ByVal pHandle as long)


    ' HID interface API declarations...
    Declare Function hidConnect Lib "mcHID.dll" Alias "Connect" (ByVal pHostWin As Integer) As Boolean
    Declare Function hidDisconnect Lib "mcHID.dll" Alias "Disconnect" () As Boolean
    Declare Function hidGetItem Lib "mcHID.dll" Alias "GetItem" (ByVal pIndex As Integer) As Integer
    Declare Function hidGetItemCount Lib "mcHID.dll" Alias "GetItemCount" () As Integer
    Declare Function hidRead Lib "mcHID.dll" Alias "Read" (ByVal pHandle As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidWrite Lib "mcHID.dll" Alias "Write" (ByVal pHandle As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidReadEx Lib "mcHID.dll" Alias "ReadEx" (ByVal pVendorID As Integer, ByVal pProductID As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidWriteEx Lib "mcHID.dll" Alias "WriteEx" (ByVal pVendorID As Integer, ByVal pProductID As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidGetHandle Lib "mcHID.dll" Alias "GetHandle" (ByVal pVendoID As Integer, ByVal pProductID As Integer) As Integer
    Declare Function hidGetVendorID Lib "mcHID.dll" Alias "GetVendorID" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetProductID Lib "mcHID.dll" Alias "GetProductID" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetVersion Lib "mcHID.dll" Alias "GetVersion" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetVendorName Lib "mcHID.dll" Alias "GetVendorName" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
    Declare Function hidGetProductName Lib "mcHID.dll" Alias "GetProductName" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
    Declare Function hidGetSerialNumber Lib "mcHID.dll" Alias "GetSerialNumber" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
    Declare Function hidGetInputReportLength Lib "mcHID.dll" Alias "GetInputReportLength" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetOutputReportLength Lib "mcHID.dll" Alias "GetOutputReportLength" (ByVal pHandle As Integer) As Integer
    Declare Sub hidSetReadNotify Lib "mcHID.dll" Alias "SetReadNotify" (ByVal pHandle As Integer, ByVal pValue As Boolean)
    Declare Function hidIsReadNotifyEnabled Lib "mcHID.dll" Alias "IsReadNotifyEnabled" (ByVal pHandle As Integer) As Boolean
    Declare Function hidIsAvailable Lib "mcHID.dll" Alias "IsAvailable" (ByVal pVendorID As Integer, ByVal pProductID As Integer) As Boolean

    ' windows API declarations - used to set up messaging...

    Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Integer, ByVal hwnd As Integer, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
                                          (ByVal hwnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer

    Delegate Function SubClassProcDelegate(ByVal hwnd As Integer, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    Public Declare Function DelegateSetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" _
                                           (ByVal hwnd As Integer, ByVal attr As Integer, ByVal lval As SubClassProcDelegate) As Integer


    ' windows API Constants
    Public Const WM_APP As Integer = 32768
    Public Const GWL_WNDPROC As Short = -4

    ' HID message constants
    Private Const WM_HID_EVENT As Decimal = WM_APP + 200
    Private Const NOTIFY_PLUGGED As Short = 1
    Private Const NOTIFY_UNPLUGGED As Short = 2
    Private Const NOTIFY_CHANGED As Short = 3
    Private Const NOTIFY_READ As Short = 4

    ' local variables
    Private FPrevWinProc As Integer ' Handle to previous window procedure
    Private FWinHandle As Integer ' Handle to message window
    Private Ref_WinProc As New SubClassProcDelegate(AddressOf WinProc)
    Private HostForm As Object

    ' Set up a windows hook to receive notification
    ' messages from the HID controller DLL - then connect
    ' to the controller
    Public Function ConnectToHID(ByRef targetForm As Form) As Boolean
        Dim pHostWin As Integer = targetForm.Handle.ToInt32
        FWinHandle = pHostWin
        pHostWin = hidConnect(FWinHandle)
        FPrevWinProc = DelegateSetWindowLong(FWinHandle, GWL_WNDPROC, Ref_WinProc)
        HostForm = targetForm
    End Function

    ' Unhook from the HID controller and disconnect...
    Public Function DisconnectFromHID() As Boolean
        DisconnectFromHID = hidDisconnect
        SetWindowLong(FWinHandle, GWL_WNDPROC, FPrevWinProc)
    End Function


    ' This is the procedure that intercepts the HID controller messages...

    Private Function WinProc(ByVal pHWnd As Integer, ByVal pMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
        If pMsg = WM_HID_EVENT Then
            Select Case wParam

                ' HID device has been plugged message...
                Case Is = NOTIFY_PLUGGED
                    HostForm.OnPlugged(lParam)

                    ' HID device has been unplugged
                Case Is = NOTIFY_UNPLUGGED
                    HostForm.OnUnplugged(lParam)

                    ' controller has changed...
                Case Is = NOTIFY_CHANGED
                    HostForm.OnChanged()

                    ' read event...
                Case Is = NOTIFY_READ
                    HostForm.OnRead(lParam)
            End Select

        End If

        ' next...
        WinProc = CallWindowProc(FPrevWinProc, pHWnd, pMsg, wParam, lParam)

    End Function
End Module
```


----------



## LIONHEAD (Ago 3, 2010)

saludos..
  Existe la manera de utilizar tu código de configuración del puerto en C?.. estoy trabajando en un proyecto que utiliza esa configuración pero estoy obligado a trabajar en linux mediante un paquete llamado (netbeans), cualquier ayuda agradecido de antemano

jorge lópez


----------



## willynovi (Ago 3, 2010)

hola Lionhead, recuerda que para linux debes usar una libreria distinta, ya que la que presenta Jonathan aqui es para Windows.

Quizas aqui encuentres algo de info http://www.linux-usb.org/USB-guide/book1.html

O aquí tambien, la libhid seria la equivalente a la hid.dll de windows, según tengo entendido, alguien mas en el tema te puede ayudar mas. No programo en Linux, pero si en C bajo windows y tengo hecho un programita similar al de Jonathan con la WINAPI32 http://libhid.alioth.debian.org/

Saludos, Willy


----------

