Está en la página 1de 18

(para realizar el ejercicio 1 de la ejercitación

propuesta para la Unidad 1)


 comencemos por entender un poco como
se estructura el USB …
 Diseñado para vincular dispositivos (“devices” or
“nodes”) con computadoras (host)
 Velocidades de 1.5Mbps (USB1.0) a 10Gbps
(USB3.1)
 4 hilos: V(5v), Data+, Data-, Ground
 Hasta 127 dispositivos por host
 Hasta 5 capas (“tiers”) vía “hubs”
 El cliente (software) se comunica con un
dispositivo utilizando “pipes” (conducto,
tubo o cañería)
 Cada “pipe” es un canal de comunicación
entre el software corriendo en el host y un
“endpoint” (punto de conexión) del
dispositivo ep0

Software
Cliente ep15
(aplicación)
Dispositivo

epX
 Cada endpoint tiene un propósito específico
(ej.: recibir comandos, transmitir datos, etc.)
 Hasta 16 endpoints (solo 3 en dispositivos de
baja velocidad).
 El endpoint “0” esta siempre disponible: se usa
para las inicializaciones y para obtener cuales
otros endpoints están disponibles en el
dispositivo
 Cada endpoint se caracteriza por su número
(cualquier número decidido por el diseñador),
ancho de banda, tipo de modo de
transferencia, etc.
 Los endpoints se agrupan en “interfaces” y estas en
“configuraciones”.
 Estas entidades lógicas tienen una
representación en el código basada en
descriptores
 Dos tipos de pipes:
◦ Para transportar mensajes con datos concernientes a USB
◦ Para transportar flujos (streams): con datos que solo
interesan a la aplicación y el dispositivo.
 Cuatro tipos de transferencia (siempre por
paquetes):
◦ Transferencias para control: comandos o pedidos de
estado
◦ Transferencias para interrupción: iniciada por el
dispositivo para que el host haga algo
◦ Transferencias isosíncronas: para transportar datos donde
el tiempo es crítico (video, voz, etc.)
◦ Transferencias “bulk” (paquete o bulto): que usan todo el
ancho de banda pero no tienen requisitos estrictos de
tiempo
 Permite comunicar una aplicación de nivel de
usuario (“userspace”) con dispositivos USB

 No hacen falta privilegios para acceder a un


dispositivo USB

 Cada dispositivo USB es manipulado mediante dos


objetos que provee la API: libusb_device y
libusb_device_handle

 EL API provee de dos interfaces para acceder a los


dispositivos de diferentes modo: una sincrónica y
otra asincrónica
 Vea rápidamente las funciones y estructuras que
componen esta API: http://libusb.sourceforge.net/api-
1.0/api.html
(los nombres deben darle una idea de la función de cada elemento)

 Vea como se agrupan “módulos”´:


http://libusb.sourceforge.net/api-1.0/modules.html

 Vea los diversos “descriptores” que existen (sus


propiedades).

 Relacione las funciones con algunos de los conceptos


vistos en la unidad 1
Hagamos un programa que :

1) Inicialice la librería: llamar a la fuinción libusb_init y crear una sesión.


2) Obtenga una la lista de dispositivos conectados al sistema: llamar a la
función libusb_get_device_list (esto crea un arreglo de libusb_device).
3) Barra la lista de dispositivos y muestre que opciones (interfaces,
configuraciones, endpoints, etc.) tiene cada uno .
4) Libere la lista de dispositivos : lamar a libusb_free_device_list
5) Cierre el dispositivo: llamar a libusb_close
6) Libere el API : llamar a libusb_exit
 En su linux:
Verifique que cuenta con el compilador (gcc)
Asegúrese que la librería está instalada
 Puede realizar todo “a mano”:
◦ Usando un editor de texto para escribir su
programa (el “nano” por ejemplo)
◦ Y compilar a mano desde línea de comando:
gcc –miprog.c . . .
 O quizás prefiera utilizar un IDE completo
como el Eclipse o elemental como el Genie
Ejemplo de programa posible
Primero el programa principal:
#include <iostream>
#include </usr/include/libusb-1.0/libusb.h>
using namespace std;
void printdev(libusb_device *dev); //declaracion de la funcion
int main() {
libusb_device **dispositivos; //puntero a puntero de dispositivos (la lista de dispositivos)
libusb_context *contexto = NULL; //esta será la session
int resultado; //para guardar los valores de retorno de funciones
ssize_t cantidad; //numero de dispositivos conectados
ssize_t i; //variable auxiliar

//inicializo la librería y creo una session: devuelve 0 si todo va bien


resultado = libusb_init(&contexto);
if(resultado < 0) {
cout<<"Error al inicializar"<<resultado<<endl;
return 1;
}

//esto setea el nivel de "verbosidad" de las llamadas a funciones (vea que tiene disponible)
libusb_set_debug(contexto, LIBUSB_LOG_LEVEL_NONE);
//obtener la lista de dispositivos (notar la TRIPLE indireccion)
cantidad = libusb_get_device_list(contexto, &dispositivos);
if(cantidad < 0) {
cout<<"Hubo un error"<<endl;
return 1;
}

cout<< cantidad <<" dispositivos en la lista."<<endl;

//barro la lista
for(i = 0; i < cantidad; i++) {
cout<< "Dispositivo "<< i+1 <<endl;
printdev(dispositivos[i]);
printdev(dispositivos[i]); //muestro algunos datos de los dispositivos
}
//libero la lista
libusb_free_device_list(dispositivos, 1);

//cierro la sesion
libusb_exit(contexto);
return 0;
}

 Ahora la función:
void printdev(libusb_device *dev) {
libusb_device_descriptor descriptor;
//obtengo la descripcion del dispositivo
int resultado = libusb_get_device_descriptor(dev, &descriptor);
if (resultado < 0) {
cout<<"No se pudo obtener la descripcion del dispositivor"<<endl;
return;
}
cout<<"Configuraciones posibles: "<<(int)descriptor.bNumConfigurations<<" ";
cout<<"Clase de dispositivo: "<<(int)descriptor.bDeviceClass<<" ";
cout<<"Fabricante (vendorID): "<<descriptor.idVendor<<" ";
cout<<"Producto ID: "<<descriptor.idProduct<<endl;

libusb_config_descriptor *config;
libusb_get_config_descriptor(dev, 0, &config);

const libusb_interface *inter;


const libusb_interface_descriptor *interdesc;
const libusb_endpoint_descriptor *epdesc;
cout<<"Interfaces: "<<(int)config->bNumInterfaces<<endl;

for(int i=0; i<(int)config->bNumInterfaces; i++) {


cout << "Interface:"<<i<<endl;
inter = &config->interface[i];
cout<<"Numero de configuraciones alternativas: "<<inter->num_altsetting<<endl;
for(int j=0; j<inter->num_altsetting; j++) {
interdesc = &inter->altsetting[j];
cout<<"Numero de interfaces: "<<(int)interdesc->bInterfaceNumber<<" | ";
cout<<"Numero de endpoints: "<<(int)interdesc->bNumEndpoints<<endl;
for(int k=0; k<(int)interdesc->bNumEndpoints; k++) {
epdesc = &interdesc->endpoint[k];
cout<<"Tipo de descriptor: "<<(int)epdesc->bDescriptorType<<" | ";
cout<<"Direccion del Endpont: "<<(int)epdesc->bEndpointAddress<<" | ";
cout<<endl;
}
}
cout<<endl;
}
cout<<endl<<endl<<endl;
//libero el descriptor
libusb_free_config_descriptor(config);
}
 Compile el programa y ejecútelo (si hay
errores debería ser capaz de corregirlos)
 Inserte algún dispositivo USB y vea los
cambios en la salida del programa
 Ahora:
El comando lsusb de linux brinda una salida distinta:
vuelva a ver los descriptores del API y modifique el
programa para que su salida se parezca a la de lsusb
(puede consultar directamente los fuentes de lsusb,
si le parece)

También podría gustarte