Comunicaciones USB entre Pinguino y PC

ProgramaciónLa idea es familiarizarnos con el interfaz USB, las comunicaciones que podemos desarrollar entre un dispositivo y el PC, y poner en práctica lo que sabemos de lenguaje C. Todo ello utilizando la librería libusb (1.0), que es la que nos permitirá programar el PC para habilitar este tipo de comunicaciones entre el PC y Pinguino. De este modo, realizaremos algunos programas simples para comunicarnos con Pinguino, que más adelante nos servirán como base para propósitos más ambiciosos.

Conceptos Generales

Algunos conceptos que tenemos que tener claro en una transferencia USB son por ejemplo:

  • Host: Dispositivo maestro que inicia la comunicación (Generalmente un PC/computador).
  • Puntos terminales (Endpoints): Es una localidad especifica dentro del dispositivo. El Endpoint es un buffer que almacena múltiples bytes, típicamente es un bloque de la memoria de datos o un registro dentro del microcontrolador. Todos lo dispositivos deben soportar el punto terminal 0. Este punto terminal es el que recibe todo el control y la peticiones de estado durante la enumeración cuando el dispositivo esta sobre el bus.
  • Tuberías (Pipes): Es un enlace virtual entre el host (el PC) y el dispositivo USB, este enlace configura los parámetros asociados con el ancho de banda, que tipo de transferencia se va a utilizar (Control, Bulk, Isócrona o Interrupt), dirección del flujo de datos y el máximo y/o mínimo tamaño de los paquetes/buffers. Cada enlace está caracterizado por su banda de paso (Token), su tipo de servicio, el número de punto terminal (End Point) y el tamaño de los paquetes. Estos enlaces se definen y crean durante la inicialización del USB . Siempre existe un enlace virtual 0 que permite tener acceso a la información de configuración del periférico USB (estado, control e información). La norma USB define 2 tipos de enlaces virtuales (pipe):stream y message:
  • Stream Pipes: se trata de un flujo sin formato USB definido, esto significa que se puede enviar cualquier tipo de dato. Este tipo de pipe soporta las transferencias bulk, isocronas, e interrupt. Además tanto el host como el dispositivo USB pueden controlar.
  • Message Pipes: este tipo de enlace virtual si tiene un formato USB definido y solo puede soportar la transferencia Control.

Por dar algún otro detalle de los modos de transferencia que pueden existir entre un host y un dispositivo USB que se han mencionado antes los definimos un poco más aquí:

  • Control: En el tipo control los parámetros se utilizan para permitir el acceso a diferentes partes del dispositivo USB. Se utiliza para configurar el dispositivo, obtener información sobre el dispositivo, el envío de comandos al dispositivo, o recuperar los informes sobre la situación sobre el dispositivo. Los datos enviados son generalmente de pequeño tamaño. Cada dispositivo USB tiene un tipo de transferencia de control denominado «endpoint 0 «que es utilizado por el núcleo para configurar el dispositivo USB cuando es insertado. Estas transferencias están garantizadas a través del protocolo USB que siempre va a disponer de suficiente ancho de banda.
  • Interrupción: Los endpoints de interrupción transfieren pequeñas cantidades de datos a una velocidad estable cada vez que el computador pide datos al dispositivo USB. Este tipo es el el principal método de comunicación para teclados USB y ratones. También son comúnmente usados para enviar datos a los dispositivos USB para controlar el dispositivo, pero no se utiliza generalmente para la transferencia de grandes cantidades de datos. Estas transferencias están garantizadas por el protocolo USB para que siempre tenga suficiente ancho de banda reservado.
  • Masivo (bulk): Este tipo transfiere grandes cantidades de datos. Estos datos son normalmente mucho más numerosos que los transmitidos por la transmisión por interrupción. Este tipo es usado normalmente por los dispositivos que necesitan transferir cualquier cantidad de información sin pérdida de datos. Estos tipos son comunes en las impresoras, almacenamiento y dispositivos de red.
  • Isócrona: modo utilizado para la transmisión de audio o video comprimido. Este tipo de transmisión funciona en tiempo real. Este es el modo de mayor prioridad. La transmisión de la voz es un ejemplo de esta aplicación.

Para más información sobre como trabaja la comunicación USB podeis dirigiros a la página de especificación de USB, o buscar en internet por información sobre las comunicaciones USB. De momento nosotros nos podemos apañar para empezar a trabajar con Pinguino con los datos hasta aquí expuestos.

PCyPinguino_peq

Trabajando con Pinguino

Para trabajar con Pinguino nos centraremos en el modo de transferencia BULK. Necesitamos conocer entonces básicamente qué configuración es la que necesita el dispositivo, qué interface tiene definido, y cuales son los Endpoints que vamos a utilizar para enviarle datos (Endpoint OUT) y para recibir datos de él (Endpoint IN). Para conocer estos datos nos podemos ir al código del bootloader que hayamos cargado en Pinguino. Yo he utilizado la última versión a día de hoy, es decir la 4.13. De modo, que si miramos el fichero picUSB.c, nos encontramos con los siguientes datos:

  • Configuración = 1
  • Interface = 0
  • Endpoint_OUT = 0x01
  • Endpoint_IN = 0x82

Además, para identificar nuestro dispositivo Pinguino de la lista de dispositivos conectados a nuestro Host (PC), necesitamos anotar también estos 2 datos addicionales:

  • Vendor ID (el de microchip): 0x04D8
  • Product ID : 0xFEAA (*)

(*) Este es el Product ID que os podreis encontrar cuando utiliceis un Pinguino 18F2550 o 18F4550. También podeis verlos si una vez cargado nuestro programa de comunicaciones USB en Pinguino haceis:

lsusb

Bien, a partir de aqui, vamos a crear un programa muy simple para que Pinguino haga una tarea muy simple: Recibir lo que se le envíe desde el PC, y a continuación enviarlo de vuelta al PC. Esta es la parte más sencilla, y queda resumida en el siguiente programa. Como podeis ver nos limitamos a utilizar las funciones:

  • BULK.available: que nos permite saber si hay algún dato disponible en el bus.
  • BULK.read: que nos permite guardar el contenido enviado en una cadena.
  • BULK.write: que nos permite enviar una cadena por el bus USB hacia el host.

La tarea que debe realizar Pinguino para el propósito que hemos definido queda descrita en el siguiente diagrama de flujo:

ProgramaBasicoPinguino

Y queda autoexplicado en el siguiente código:

/*-----------------------------------------------------
Author: Jesús Carmona Esteban
Date: 20 de Nov de 2013
Description: Comunicación con el PC utilizando las
funciones BULK.read y BULK.write.
El PIC tiene cargado el bootloader v4.x
-------------------------------------------------------*/
u8 receivedbyte;
char buffer[64];

void setup()
{
    pinMode(USERLED, OUTPUT);
}

void loop()
{
    receivedbyte=0;

    // Esperamos a que existan datos disponibles en USB
    if(BULK.available()) {
        receivedbyte = BULK.read(buffer);
    }

    // C string must be null-terminated
        buffer[receivedbyte] = 0;

    // Si se recibió algo...
    if (receivedbyte > 0) {
    //Cambiamos de estado el LED de usuario,
        toggle(USERLED);
        // ...y reenviamos la cadena de vuelta al host.
        BULK.write(buffer,receivedbyte);
    }
}

Carga este programa en Pinguino desde el IDE, y pasamos a programar el PC para que se comunique con él. Lo primero, debemos instalarnos la librería libusb en caso de que no la tuviesemos. En UBUNTU:

sudo apt-get install libusb-dev

Para trabajar con libusb hace falta que tengamos claros varias cosas:

  • Qué pasos debemos realizar para iniciar la comunicación con nuestro dispositivo.
  • Qué tipo de comunicación vamos a establecer con nuestro dispositivo: asíncrona o síncrona.

Pasos a realizar para iniciar la comunicación

    1. Inicializar la librería.
    2. Listar los dispositivos USB conectados a nuestra máquina, y buscar nuestro dispositivo especifico (Pinguino).
    3. Abrir nuestro dispositivo.
    4. Comprobar que la configuración de Pinguino activa es la correcta, y si no seleccionarla.
    5. Reclamar el interfaz.

¡¡¡Ya estamos listos para comunicarnos con el dispositivo !!!

Qué tipo de comunicación establecer con nuestro dispositivo

La librería nos ofrece 2 formas de hacerlo. El modo síncrono y el modo asíncrono. La elección de dicho modo va a depender más del tipo de aplicación que estemos desarrollando. En la página de la librería se describen estos 2 modos, pero básicamente podemos decir que trabajan así:

  • Modo síncrono: Este modo es el más sencillo. Con una sola llamada hacemos la transferencia de nuestros datos desde nuestra aplicación. Para esta llamada tan solo tenemos que utilizar la función de la librería libusb_bulk_transfer() . El inconveniente de este modo, es que nuestra aplicación se puede quedar dormida dentro de la llamada libusb_bulk_transfer() hasta que la transacción I/O haya sido completada. Esto puede pasar en el caso de que nuestro dispositivo tarde mucho en realizar el trabajo por su parte por cualquier razón.
  • Modo asíncrono: Este modo es más complejo, pero más potente. En lugar de proporcionar funciones que bloquean nuestro programa hasta que la I/O ha sido completada, el modo asíncrono dispone de funciones no bloqueantes las cuales inician una transferencia y retornan inmediatamente. Tu aplicación le pasa un puntero a una función diseñada por ti, para procesar el retorno a esta función no bloqueante, a la cual libusb llamará una vez que la transacción haya sido completada. Sin embargo, esta flexibilidad no está exenta de alguna que otra complicación más al diseñar tu programa. Pero no voy a entrar en esos detalles aquí y ahora, si no que en todo caso los abordaremos en posteriores articulos. De momento, si quieres ampliar los conocimientos puedes consultar la documentación sobre I/O de la librería.

Nosotros en este primer ejemplo empezaremos por lo sencillo. Utilizaremos un modo de comunicación síncrono, y la llamada libusb_bulk_transfer() . Lo haremos basicamente, porque nuestro programa no tendrá otra cosa que hacer que enviar una cadena de texto a Pinguino y esperar a que la devuelva. Y por otro lado Pinguino ya está programado con el programa que hemos expuesto más arriba para responder a esta interacción, es decir, escuchar lo que le vamos a enviar y devolverlo instantaneamente.

De modo que el diagrama de flujo de nuestro programa en C para nuestro PC es bien sencillo:

ProgramaBasicoPC

El diagrama anterior está muy a groso modo. El programa en C permite ver algún que otro detalle adicional. El codigo para el programa en el PC es el siguiente:

// ---------------------------------------------------------------------------------
// Autor: Jesús Carmona Esteban
// Fecha: 20/11/2013
// Versión: 1.0
// Desccripción:
// El siguiente programa muestra como utilizar las funciones de libusb
// para comunicarse con Pinguino desde C.
// Para completar la comunicación es necesario haber cargado en el otro extremo,
// en Pinguino, el programa adjunto para comunicarse con el PC a través de este.
// ---------------------------------------------------------------------------------
#include <stdio>
#include 	<libusb-1.0/libusb.h>
//Compilar con...
//gcc -o usb_conversacion usb_conversacion.c -I/usr/local -L/usr/local -lusb-1.0
#define MICROCHIP_VENDOR_ID 0x04D8
#define PINGUINO_PRODUCT_ID 0xFEAA
#define PINGUINO_CONFIGURATION 1
#define PINGUINO_INTERFACE 0
#define BULK_EP_OUT 0x01
#define BULK_EP_IN 0x81

//Función para comprobar nuestro VID & PID
int is_usbdevblockPinguino( libusb_device *dev ) {
    struct libusb_device_descriptor desc;
    int r = libusb_get_device_descriptor( dev, &desc );
    if( desc.idVendor == MICROCHIP_VENDOR_ID && desc.idProduct == PINGUINO_PRODUCT_ID ){
        return 1;
    }
    return 0;
}

int main( int argc, char **argv) {

    // Definiendo variables y buscando dispositivos USB:
    // -------------------------------------------------
    libusb_device **list;
    libusb_device *found = NULL;
    libusb_context *ctx = NULL;
    int attached = 0;
    libusb_init(&ctx);
    libusb_set_debug(ctx,3);
    ssize_t cnt = libusb_get_device_list(ctx, &list);
    ssize_t i = 0;
    int err = 0;
    if (cnt < 0){
        printf( "Ningun dispositivo usb encontrado.\n" );
        error();
    }
    // Localizando el Pinguino
    // -----------------------
    for(i = 0; i < cnt; i++){
        libusb_device *device = list[i];
        if( is_usbdevblockPinguino(device) ){
            found = device;
            break;
        }
    }

    // Si lo encontramos, lo abrimos:
    if(found){
        printf( "Encontrado usb-dev-block Pinguino !\n" );
        libusb_device_handle *handle;
        err = libusb_open(found, &handle);
        if (err){
            printf("Imposible abrir dispositivo usb Pinguino\n"); error();
        }
        if ( libusb_kernel_driver_active(handle,0) ){
            printf("Dispositivo ocupado...desconectándolo para utilizarlo.\n");
            libusb_detach_kernel_driver(handle,0);
            attached = 1;
        }else printf("Dispositivo ya desvinculado del kernel. Lo podemos utilizar.\n");

        // Comprobamos la configuración activa y
        // ...si no es la que necesitamos, la cambiamos.
        int config;
        err = libusb_get_configuration( handle , &config);

        if (!err){ printf("Configuración activa: %x\n",config);
            if (config != PINGUINO_CONFIGURATION){
                err = libusb_set_configuration( handle , PINGUINO_CONFIGURATION);
                if (err){
                    printf( "Fallo al intentar configurar: " );
                    switch( err ){
                        case LIBUSB_ERROR_NOT_FOUND: printf( "no encontrado\n" ); break;
                        case LIBUSB_ERROR_BUSY: printf( "ocupado\n" ); break;
                        case LIBUSB_ERROR_NO_DEVICE: printf( "no hay dispositivo\n" ); break;
                        default: printf( "otro\n" ); break;
                    }
                    error();
                }
            }
        } else printf("Error intentando obtener la configuración.\n");

        // Reclamamos el interfaz (Claim interface):
        err = libusb_claim_interface( handle, PINGUINO_INTERFACE );
        if (err){ printf( "Fallo al reclamar el interfaz: " );
            switch( err ){
                case LIBUSB_ERROR_NOT_FOUND: printf( "no encontrado\n" ); break;
                case LIBUSB_ERROR_BUSY: printf( "ocupado\n" ); break;
                case LIBUSB_ERROR_NO_DEVICE: printf( "no hay dispositivo\n" ); break;
                default: printf( "otro\n" ); break;
            }
            error();
        }

        // Enviamos un string a Pinguino
        char data[15]="Hola Pinguino!"; //La cadena tiene que terminar en 0x00 (null).
        int actual_length;
        int r = libusb_bulk_transfer(handle, BULK_EP_OUT, data, sizeof(data), &actual_length, 1000);
        if (r == 0 && actual_length == sizeof(data)) {
            printf("Cadena enviada: %s\n",data);
            printf("longitud transmitida=%d.\n",actual_length);
            printf("longitud cadena origen=%d.\n",sizeof(data));
        } else { error(); }

        // Recibimos los datos de vuelta de Pinguino
        char inputPacketBuffer[65];
        printf("Listos para recibir...\n");
        r = libusb_bulk_transfer(handle, BULK_EP_IN, inputPacketBuffer,65, &actual_length, 1000);

        if (r == 0) {
            printf("Lo hemos recibido.\n");
            printf("longitud recibida=%d.\n",actual_length);
            inputPacketBuffer[actual_length]=0; //terminamos la cadena con un null.
            printf("cadena recibida: %s\n",inputPacketBuffer);
        } else { error(); }

        if( attached == 1 ){
            libusb_attach_kernel_driver( handle, 0 );
        }

        libusb_close( handle );
    }

    //Liberamos y cerramos el dispositivo y el contexto:
    libusb_free_device_list(list, 1);
    libusb_exit( ctx );
}

Lo guardamos con un editor de texto. Yo lo llamé usb_conversacion.c . Y lo compilamos con la siguiente llamada:

gcc -o usb_conversacion usb_conversacion.c -I/usr/local -L/usr/local -lusb-1.0

Finalmente lo ejecutamos desde la linea de comandos, teniendo Pinguino ya programado y conectado por USB con lo que hemos descrito anteriormente:

sudo ./usb_conversacion

y el resultado en pantalla deberá ser similar a este:

Captura de pantalla de 2013-11-21 13:06:00

Espero que esto os pueda servir de base para comenzar a hacer programas con Pinguino y el PC comunicandose entre sí.

En posteriores articulos daré más detalles de por qué quiero utilizar esta comunicación.

Autor: Sphinx

Robotics enthusiast

18 opiniones en “Comunicaciones USB entre Pinguino y PC”

  1. Hola buenos dias, ya se que el tema es un poco antiguo, pero estoy muy interesado en programar una interface USB Pinguino (PIC18F4550) desde PC en Visual Studio 2010 (Visual C++) y he visto que lo que comentas me podria ser de mucha ayuda.

    Aunque he conseguido compilar tu programa con Visual C++ (VS2010) me ha lanzadado un Warning:

    —–
    E:\PC00\TRS\Pinguino\Programas\libusb-master\libusb\libusb.h(939): warning C4200: se ha utilizado una extensión no estándar : matriz de tamaño cero en struct/union

    No se puede generar el constructor de copias o el operador de asignación de copias cuando el tipo definido por el usuario contiene una matriz de tamaño cero
    —–

    Aun así se ha compilado ya que solo era un warning. Lo he ejecutado y me da un error de windows. (Lo he probado tanto en XP como en Windows 10)

    El error en XP es:

    «LIBUSB_Test.exe ha detectado un problema y debe cerrarse.»

    En la pantalla de DOS me dice lo siguiente:

    —–
    Encontrado usb-dev-block Pinguino !
    Imposible abrir dispositivo usb Pinguino
    ERRORDispositivo ocupado…desconectándolo para utilizarlo.
    —–

    El driver que he instalado para el dispositivo es el LIBUSB es el «libusb-win32-bin-1.2.6.0»

    He usado la version LIBUSB 1.0.9 para el include y he compilado la libreria incluida en los fuentes con el proyecto MSVC (libusb_vs2010.sln) y utilizo el lib que ha generado (libusb-1.0.lib)

    Por favor necesito que me orientes sobre que puedo estar haciendo mal? El driver instalado no es el correcto?

    Muchas gracias.

    Me gusta

    1. Hola Xavi,

      Con Windows me pillas un poco, la verdad. De todos modos, he buscado por ahí, para ver si veía alguna referencia a versiones de drivers, etc, que pudiesen dar problemas. He encontrado esto: https://github.com/libusb/libusb/wiki/Windows
      En la sección de esa página llamada «How to use libusb on Windows», viene un código, donde la última línea , es decir, esta:
      libusb_set_option(ctx, LIBUSB_OPTION_USE_USBDK);
      …no aparece en mi código arriba (ver líneas de 38 a 42). Entiendo además que te indican que tienes que instalar una DLL para que los driver instalados del dispositivo (en este caso PINGUINO) funcionen correctamente.
      Espero que esto te ayude, aunque como te digo, con Windows no he probado.
      Si te puedo seguir ayudando, lo haré encantado.
      Me alegro de que utilices Pinguino para tus proyectos. Cada vez tengo menos contactos con los que intercambiar ideas referentes a Pinguino.

      Saludos, Jesús.

      Me gusta

      1. Hola de nuevo, como soy muy cabezota el dia de ayer lo dedique a intentar que funcionara todo. Al final lo consegui (Usando un instalador de drivers que arregla y reemplaza drivers de LIBUSB, es el programa LIBUSB Driver zadig-2.4).

        Desgraciadamente algo extraño pasa entre el IDE de Pinguino V11 y los drivers instalados por ZADIG y no reconoce el Pinguino para programarlo.

        Asi que de momento estoy contento porque he conseguido hacer funcionar tu programa y esto me abre la posibilidad de poder acceder por USB al Pinguino desde PC. Pero por otro lado ahora no puedo programar el Pinguino desde el IDE.

        SOLUCION: Tengo en una maquina virtual el IDE y en otra el acceso BULK a USB.

        Aunque no es lo mas adecuado sigo investigando a ver si puedo lograr una configuracion que me permita con el mismo driver acceder a las dos posibilidades.

        PD: Estare encantado de seguir comentandote cosas sobre el tema ya que me he metido a fondo en el mundo del Pinguino y estoy intentando hacer trabajos que habitualmente se hacen con Arduino (Impresoras 3D y CNCs)… 🙂

        Le gusta a 1 persona

      2. Fantástico que lo hayas conseguido!!

        Respecto a lo que comentas en la primera línea… Entonces ya somos dos cabezotas 😀

        No funciona entonces como en Linux. En Linux puedes conectarte a Pinguino , programarlo, y cuando se ejecuta el programa de conexión USB, tener las comunicaciones USB entre Pinguino y el PC.

        Sobre tu PD, me alegro de que quieras hacer todo eso con Pinguino. Yo también tengo algún proyecto a medias con cosas similares, para utilizarlo en lugar de Arduino también. Guardo tu contacto y te escribo para comentar.

        Un saludo!

        Me gusta

  2. Hola, como estás te felicito por tu blog. Te escribo porque no estoy pudiendo compilar el programa en C desde una netbook con Huayra 3.0 (Debian Jessie), salta este error:
    usb_conversacion.c:11:17: fatal error: stdio: No existe el fichero o el directorio
    #include
    ^
    compilation terminated.

    ¿Alguna sugerencia?. Gracias, disculpe. Felicitaciones otra vez. Salud!

    Me gusta

    1. Hola Mateo, gracias por tus palabras.
      No he trabajado con esa distro de Linux. Vengo haciendolo habitualmente con Ubuntu. Pero creo que para este caso es lo mismo. No estoy al 100% seguro, pero sospecho que te faltan por instalar los paquetes básicos de programación.
      Si este es el caso, te paso este link. build-essential es un conjunto de librerías y ejecutables que te permitirán programar y compilar en C, C++ . Mira aquí: https://packages.debian.org/es/sid/build-essential
      Dime si se resolvió.
      Saludos!

      Me gusta

      1. Buenas tardes, amigo he intentado lo siguiente;

        en vez de esto

        // Si se recibió algo…
        if (receivedbyte > 0) {
        //Cambiamos de estado el LED de usuario,
        toggle(USERLED);

        Realice esto

        if (buffer[0] == “1”)
        digitalWrite(7, HIGH);

        y tambien

        if (buffer == “1”)
        digitalWrite(7, HIGH);

        y de ninguna de las dos formas me funciona, lo que quiero es activar un led una vez tecleado una tecla correspondiente.. osea a pulsar el numero uno (1) este verifique si es pulsado y active el led respectivo, que estaría conectado a una pin del pinguino.

        agradesco tu ayuda.

        Me gusta

      2. Hola Angel,

        Lo primero una pregunta:
        Imagino que en tu programa conservas la última linea del código que he puesto en el artículo, de modo que lo que le envías a Pinguino te lo devuelve al ordenador y lo imprimes por pantalla, ¿verdad? Mi pregunta es: ¿Qué es lo que te devuelve Pinguino?

        Ahora un par de ideas que se me ocurren:

        1) utiliza comillas simples en la linea
        Buffer[0] == ‘1’
        Yo puse comillas dobles, pero no sé si eso será un problema. Puedes intentar ese cambio.

        2) Puedes hacer un bucle con ‘for’ y recorrer todo el buffer para encontrar un solo carácter que sea ‘1’. A lo mejor no cae en la posición 0 de buffer, si no en la 1, 2, 3…. De todos modos esto podrás verlo en lo que se imprime de vuelta por la pantalla de tu ordenador.

        3) Puedes intentar utilizar el carácter ASCII del número ‘1’ que es 31 si no me equivoco. Prueba
        buffer[0]==0x31
        Creo que no me equivoco en la notación.

        Prueba estas ideas.

        De todos modos, volveré a meter el programa en Pinguino, y publicaré los resultados en este hilo de conversación.

        Saludos,
        Sphinx

        Me gusta

  3. Hola! Me aclaraste la duda con la respuesta al primer comentario que tambien la tenia. Ahora… Sabrás la diferencia entre USB (BULK) y CDC? y la diferencia entre CDC y Serial? Gracias de antemano!

    Me gusta

    1. Hola igorer88,
      CDC es , también, una forma de comunicar Pinguino y el PC via USB. Sólo que pretende dar un mayor grado de abstracción desde el punto de vista de pinguino. Es decir, no pretende que el usuario de Pinguino se preocupe del modo de funcionamiento de USB, si no que simplemente se proporcionan algunas funciones que permiten enviar datos por el puerto USB, o recibirlos.
      Sin embargo, desde el punto de vista del PC, sí tienes que tener en cuenta que se trata de una comunicación USB. Concretamente en modo Bulk. De modo que a la hora de hacer tu programa en el PC para comunicarte con Pinguino, tienes que tener todo esto en cuenta.
      En la siguiente página de la wiki puedes ver un ejemplo de CDC, con Python en el PC: http://wiki.pinguino.cc/index.php/Interfacing_with_Python

      La ultima vez que se actualizó el fichero de usb.pdl en el proyecto (en r976, 14 Marzo 2014) se actualizó para incorporar la parte de CDC: https://code.google.com/p/pinguino32/source/diff?spec=svn1004&r=976&format=side&path=/ide/x.4/p8/pdl/usb.pdl&old_path=/ide/x.4/p8/pdl/usb.pdl&old=943 (ahí puedes ver la diferencias).

      Un saludo,
      Espero haberte ayudado y disculpa la tardanza en contestar.

      Me gusta

  4. Buen día, Gracias por la info me ah sacado de algunas dudas. si enviara desde la PC diferentes caracteres como 1, 2, 3 … y en el pinguino compararlos, como tendría que compararlos? > if (receivedbyte == ’1′) toggle(USERLED); o if (receivedbyte == 49) , eh intentado de diferentes maneras y aun no logro que este compare.
    PDA: en el código del PC ” #include ” le falto ,h no? >> #include

    Me gusta

    1. Hola fandres,
      en mi programa Pinguino que ves en el artículo, la variable receivedbyte no almacena ningún carácter recibido. Lo que almacena es el número total de caracteres recibidos:

      receivedbyte = BULK.read(buffer);

      Ciertamente esto no está documentado en la wiki de pinguino, y voy a intentar solventarlo cuanto antes. Pero, créeme ;), Lo que devuelve la función es el número de caracteres recibidos.

      Entonces, una vez que compruebes que has recibido algo, es decir if (receivedbyte >0)…. utiliza la variable buffer, e indexa el caracter que quieres comparar. Si por ejemplo le estas enviando un solo número(o carácter) como me indicas en tu mensaje (el 1 ó el 2, ó el 3….), entonces haz esto:

      if (buffer[0] == «1») toggle (USERLED);

      Efectivamente, si en lugar de poner el «1» entre comillas, le indicas el número del código ASCII, la comparación también es válida.

      Espero que te sirva.
      Un saludo,
      Sphinx.

      Me gusta

  5. Hola Sphinx!
    En primer lugar felicitarte por tu blog y los posts relacionados con el proyecto Pinguino, en especial éste que acabo de leer.

    Me pareció más que interesante la rutina en C y su interacción con libusb. Muy bueno!

    Te quería hacer una pregunta al respecto, ya que en la Wiki del proyecto no están documentadas estas funciones: Qué diferencia existe entre las funciones USB.* y BULK.* ? Si utilizo USB.* no estoy haciendo transferencias del tipo Bulk ?

    Desde ya, muchísimas gracias de antemano. Te comento que utilizando de base la rutina .pde y un script en Python y PyUSB puedo ahora controlar la placa Pinguino 2550. Pronto publicaré los sources esperando que le sean de utilidad a alguien más.

    Me gusta

    1. ¡Hola Victor!
      ¡Muchas gracias por tus palabras! Encantado de que lo que hace uno sirva para los demás 😉 Por cierto, estupendo que tú también te animes a hacerlo.

      Interesante tu pregunta al respecto de USB.* y BULK.* No te sabía responder a bote pronto, así que me he ido directamente a mirar el código del proyecto y he visto que las funciones USB.* y BULK.* llaman exactamente a las mismas librerías y funciones. Es decir, BULK.send es exactamente lo mismo que USB.send. Esto lo he encontrado en un fichero donde se mapean las funciones que escribimos en el IDE, con las que están escritas en las librerías de C del proyecto. Este fichero que menciono es h: svn/ide/x.4/p8/pdl/usb.pdl. Ahí podemos ver esto:

      BULK.read BULK_read#include
      BULK.write BULK_write#include
      BULK.printf BULK_printf#include
      BULK.available BULK_available#include
      BULK.gets BULKgets#include
      BULK.puts BULKputs#include

      USB.read BULK_read#include
      USB.write BULK_write#include
      USB.send BULK_write#include
      USB.printf BULK_printf#include
      USB.available BULK_available#include
      USB.gets BULKgets#include
      USB.puts BULKputs#include

      Lo mismo, como ves.
      Así que las puedes usar indistintamente. Como creas que tu código queda más claro.

      Saludos,
      Sphinx.

      PD: Por cierto, lo mismo ya lo habías visto. Pero te dejo este enlace a la wiki del proyecto pinguino que habla de «interfacing Python-Pinguino» : http://wiki.pinguino.cc/index.php/Interfacing_with_Python

      Me gusta

Deja un comentario