Modellare classi per usb device

Modellare classi per usb device

Messaggioda MauroTec » 21 mag , 2012 12:29 pm

Salve sono alle prese con openusb che è un fork di libusb. Il mio obbiettivo è modellare delle classi per gestire i device usb da user space tramite appunta la libreria openusb.
Ho un device manager (vedi sotto) singleton il quale crea una lista di puntatori ad oggetti Device sul quale posso fare la ricerca di uno che corrisponde a vid e pid specificati tramite:
Codice: Seleziona tutto
QList<Device *> getDevicesFromVendor(uint16_t _vendor, uint16_t _product);


Il quale ritorna una lista di puntatori da cui posso scegliere il device che mi interessa.

Classe DeviceManager
Codice: Seleziona tutto
#ifndef DEVICEMANAGER_H
#define DEVICEMANAGER_H
#include <openusb.h>
#include "device.h"
#include <QObject>

#include <QList>
#include <QPair>
#include <QMap>
#include <QDebug>

namespace System {
namespace Usb {

class DeviceManager : public QObject
{
    Q_OBJECT
public:

    static DeviceManager *instance() {
        if (!m_instance) {
            m_instance = new DeviceManager;
            m_instance->init();
            qDebug() << "crea nuova instanza di DeviceManager";
        } else {
             ;
        }
        qDebug() << "ritorna l'instanza di DeviceManager" << m_instance ;
        return m_instance;
    }
    openusb_handle_t handle() { return libhandle; }
    QList<Device *> getDevicesFromVendor(uint16_t _vendor, uint16_t _product);
    ~DeviceManager();
    int lastError();

private:
    static DeviceManager *m_instance;

    DeviceManager();
    DeviceManager(const DeviceManager &);
    DeviceManager &operator=(const DeviceManager &);
    openusb_handle_t libhandle;
    openusb_devid_t *devids;
    uint32_t devnum;
    uint32_t busnum;
    openusb_busid_t *bus;

    //struct usb_device_desc devDescriptor;
    QMap<int /*devEnum*/, Device *> enumeratorDeviceMap;
    QList<Device *> garbage;
    void doGarbage() {
        if (garbage.count())
            foreach (Device* dev, garbage) {
                delete dev;
            }
    }

    static bool disableEvent;
    bool needUpdate;
    static void eventHandling(openusb_handle_t handle, openusb_devid_t devid,
                  openusb_event_t event, void *arg);
    int _lastError;
    void eventSlot(uint8_t event, uint16_t enumDev);
    uint16_t eventDeviceId;

signals:
    void systemDeviceConnected(uint16_t deviceId);
    void systemDeviceDisconnected(uint16_t deviceId);
    void systemDeviceChanged();



public slots:

private slots:
    void init();
    void deviceAttached();
    void deviceRemoved();
};

} // Usb namespace
} // System namespace

#endif // DEVICEMANAGER_H


Il device manager sembra funzionare, brevemente lo spiego:
eventHandling è statica ma dovrà essere una funzione friend perchè è la callback da passare alla libreria openusb, comunque così funziona anche se ho duvuto fare un magheggio che spero di evitare con eventHandling friend.

Ogni volta che un device viene rimosso, il puntatore a Device* viene rimosso dalla lista e messo in garbage, così ogni volta che richiamo il metodo instance() se garbage.count() è vera ci sono oggetti da distruggere.

Ora il problema si sposta sul device:
Un device usb è composto da varie interfaccie che possono avere più endpoint con cui dialogare, per cui un device è un contenitore di interfaccia ed endpoint. La cosa che mi è venuta in mente subito è: eredito QIODevice in ogni classe Device, ma QIODevice ha un solo buffer interno e posso leggere e scrivere su un solo endpoint, quindi come faccio a modellare il device usb?

Ho pensato a queste due possibilità:
Nota :Device eredita QObject

Creao una classe EndPoint(Device*) che eredita QIODevice, EndPoin sa come usare un Device* e quindi finisco per creare solo gli endpoint che mi servono.
Oppure:
Chiedo a device di creare un'oggetto di classe EndPoint e su questo opero con i metodi di QIODevice.

Per adesso ho scritto solo codice per prendere confidenza con openusb e sono riuscito a comunicare con un device AVRISP MKII inviandoglio il comando CMD_SIGN_ON
e leggendo la risposta prevista composta da:
1 byte STATUS_CMD_OK 0
1 byte Signature length 10
10 byte String “AVRISP_MK2” No null terminated

Voi come procedereste?

Ciao.
MauroTec
Trollino in fasce
 
Messaggi: 21
Iscritto il: 11 feb , 2011 3:01 pm
Località: Palermo
Programmo in: C/C++ python

Re: Modellare classi per usb device

Messaggioda MauroTec » 28 mag , 2012 12:28 pm

Ci sono riuscito. :D

Ho ancora il problema della funzione statica eventHandling, che ho provato a fare amica di DeviceManager ma mi ritorna sempre errore tipo privato in questo contesto.
Forse da funzione friend di classe A non posso accedere a membri statici di classe A, in quanto m_instance e statica.

Così come lo vedete funziona.

Codice: Seleziona tutto
#ifndef DEVICEMANAGER_H
#define DEVICEMANAGER_H
#include <openusb.h>
#include "device.h"
#include "endpoint.h"
#include <QObject>
#include <QList>
#include <QMap>
#include <QDebug>

namespace System {
namespace Usb {

class DeviceManager : public QObject
{
    Q_OBJECT
public:

    static DeviceManager *instance() {
        if (!m_instance) {

            m_instance = new DeviceManager;
            m_instance->init();
            //qDebug() << "crea nuova instanza di DeviceManager";

        } else {

            m_instance->doGarbage();

        }
        //qDebug() << "ritorna l'instanza di DeviceManager" << m_instance ;
        return m_instance;
    }

    openusb_handle_t handle() { return libhandle; }
    QList<Device *> getDevicesFromVendor(uint16_t _vendor, uint16_t _product);

    ~DeviceManager();
    int lastError();

private:
    static DeviceManager *m_instance;

    DeviceManager();
    DeviceManager(const DeviceManager &);
    DeviceManager &operator=(const DeviceManager &);

    openusb_handle_t libhandle;
    openusb_devid_t *devids;
    uint32_t devnum;
    uint32_t busnum;
    openusb_busid_t *bus;

    QMap<int /*devEnum*/, Device *> enumeratorDeviceMap;
    QList<Device *> garbage;
    void doGarbage() {
        //qDebug() << "garbage.count()" << garbage.count();
        if (garbage.count()) {

            foreach (Device* dev, garbage) {
                delete dev;
                //qDebug() << "delete dev";
            }

            garbage.clear();

        }
    }

    static bool disableEvent;
    bool needUpdate;

    static void eventHandling(openusb_handle_t handle, openusb_devid_t devid,
                  openusb_event_t event, void *arg);
    int _lastError;
    void eventSlot(uint8_t event, uint16_t enumDev);
    uint16_t eventDeviceId;

signals:
    void systemDeviceConnected(uint16_t deviceId);
    void systemDeviceDisconnected(uint16_t deviceId);
    void systemDeviceChanged();

public slots:

private slots:
    void init();
    void deviceAttached();
    void deviceRemoved();
};

} // Usb namespace
} // System namespace

#endif // DEVICEMANAGER_H



Quando un device usb viene rimosso o collegato al pc viene chiamata la funzione eventHandling che gestisce la creazione e rimozione dell'oggetto di classe Device.
In realtà quando viene rimosso un device l'oggetto non viene rimosso con "delete" subito ma messo nella lista garbage, inoltre sull'oggetto viene chiamato il metodo
unplugged() per comunicare al device che esiste ma non più valido.

Codice: Seleziona tutto
#include "devicemanager.h"
#include "tools.h"
#include <QDebug>
#include <QTimer>
using namespace System;
using namespace Usb;
// flag per abilitare o meno gli eventi scatenati dall'inserimeno o rimozione del device
bool DeviceManager::disableEvent = true;
// puntatore statico a instanza di DeviceManager
DeviceManager *DeviceManager::m_instance = 0;

// distruttore
DeviceManager::~DeviceManager()
{
    openusb_free_devid_list(devids);
    openusb_fini(libhandle);
}
// Costruttore private
DeviceManager::DeviceManager() : bus(0)
                                ,eventDeviceId(0)
                                ,needUpdate(false)
{
    int ret;

    // libhandle in realta è struct usbi_handle
    ret = openusb_init(0 /*flags*/, &libhandle);           // openusb richiede l'inizializzazione
    if (ret < 0 )
        qFatal("Device Manager: openusb_init() return with error %d"
               "\nmessge: '%s'", ret, openusb_strerror(ret));

    ret = openusb_set_default_timeout(libhandle, USB_TYPE_CONTROL, 10);       // da rivedere
    if (ret < 0 ) {
        qWarning("Device Manager: openusb_set_default_timeout() return with error %d"
                 "\nmessge: '%s'", ret, openusb_strerror(ret));
    }
    // ritorna il numero totale di bus in "busnum" e l'array di bus in "bus"
    ret = openusb_get_busid_list(libhandle, &bus, &busnum);
    if(ret) {
        qFatal("Device Manager: openusb_get_busid_list() return with error %d"
               "\nmessge: '%s'", ret, openusb_strerror(ret));
    }
    //qDebug() << "busnum" << busnum;

}

// chiamato da instance()
void DeviceManager::init()
{
    int ret;
    unsigned int deviceId, busId;
    // conta da 0 fino a busnum
    for(busId=0; busId<busnum; busId++) {
        // ritorna in devnum il numero di device presenti in bus[j]
        // ritorna in devids la lista degli id
        ret = openusb_get_devids_by_bus(libhandle, bus[busId], &devids, &devnum);
        if(ret < 0) {
            qFatal("Device Manager: openusb_get_devids_by_bus() return with error %d"
                   "\nmessge: '%s'", ret, openusb_strerror(ret));
        }
        // conta da 0 fino a devnum
        for(deviceId=0; deviceId<devnum; deviceId++) {
            qDebug() << devids[deviceId];
            Device *q_Device = new Device(devids[deviceId], this);
            enumeratorDeviceMap.insert(devids[deviceId], q_Device);
        }
    }

    // connect callback to signal Note: must be the last thing to do
    ret = openusb_set_event_callback(libhandle, USB_ATTACH, eventHandling, NULL);
    if (ret < 0 )
        qFatal("Device Manager: openusb_set_event_callback(USB_ATTACH)"
               "return with error %c \nmessge: '%s'", ret, openusb_strerror(ret));

    ret = openusb_set_event_callback(libhandle, USB_REMOVE, eventHandling, NULL);
    if (ret < 0 )
        qFatal("Device Manager: openusb_set_event_callback(USB_REMOVE) return with error %c"
               "\nmessge: '%s'", ret, openusb_strerror(ret));

    disableEvent = false;

}

// fixme fai questa funzione amica
// niente da fare ci ho provato e non funziona
// eventHandling è statica perchè deve essere un puntatore a funzione
// qui noi non possiamo creare nuovi oggetti perchè questa funzione potrebbe
// essere chiamata da altri thread e non posso passare un parent che risiede in
// un altro thread ad un oggetto creato in diverso thread, Qt non lo permette.

void DeviceManager::eventHandling(openusb_handle_t handle,
                                  openusb_devid_t devid,
                                  openusb_event_t event,
                                  void *arg)
{
    // se gli eventi sono disabilitati ritorna senza fare nulla
    if (disableEvent)
        return;
    // qui chiamo una eventSlot passando il tipo di evento castato e il
    // device id castato
    m_instance->eventSlot((uint8_t)event, (uint16_t)devid);

}

void DeviceManager::deviceAttached()
{
    //qDebug() << "new device attached" << "devid" << eventDeviceId;
    Device *q_Device = new Device(eventDeviceId, this);

    enumeratorDeviceMap.insert(eventDeviceId, q_Device);
    emit systemDeviceConnected(eventDeviceId);
    emit systemDeviceChanged();
}

void DeviceManager::deviceRemoved()
{
    //qDebug() << "device removed" << "devid" << eventDeviceId;
    Device *d_dev = enumeratorDeviceMap.take(eventDeviceId);
    // nota il garbage
    garbage.append(d_dev);
    //  cominica all'getto che la risorsa è stata scollegata
    d_dev->unplugged();
    needUpdate = true;
    emit systemDeviceDisconnected(eventDeviceId);
    emit systemDeviceChanged();
}

/*!
    return last error
*/
int DeviceManager::lastError()
{
    int e;
    e = _lastError;
    _lastError = 0;
    return e;
}

// anche qui posso trovarmi in un'altro thread e allora connetto
// tutto al timer. Qui lo posso fare perchè questa è una funzione membro non statica.
void DeviceManager::eventSlot(uint8_t event, uint16_t enumDev)
{
    // mi serve questo dato membro perchè non posso passare enumDev allo slot

    switch(event) {
    case USB_ATTACH:
        eventDeviceId = enumDev;
        QTimer::singleShot(0, m_instance, SLOT(deviceAttached()));
        break;
    case USB_REMOVE:
        eventDeviceId = enumDev;
        QTimer::singleShot(0, m_instance, SLOT(deviceRemoved()));
        break;
    case USB_SUSPEND:
        break;
    case USB_RESUME:
        break;
    case USB_HC_ATTACH:
        break;
    case USB_HC_REMOVE:
        break;
    case USB_COLDPLUG_COMPLETED:
        break;
    default:
        break;
    }
}

QList<Device *> DeviceManager::getDevicesFromVendor(uint16_t _vendor, uint16_t _product)
{
    // ricavo una lista di device dalla mappa ed elimino dalla lista solo i device che non corrispondono a quello cercato
    // nota che ritorna una lista perchè possono esserci più device usb identici connessi al pc
    QList<Device*> alldevs = enumeratorDeviceMap.values();
    foreach(Device* d, alldevs) {
        if (d->vendor() != _vendor && d->product() != _product) {
            uint16_t idx = alldevs.indexOf(d);
            alldevs.removeAt(idx);
        }
    }
    return alldevs;
}


Codice: Seleziona tutto
#ifndef DEVICE_H
#define DEVICE_H
#include <QObject>
#include <openusb.h>

class Endpoint;

namespace System { namespace  Usb  { class DeviceManager; } }

/*!
   La classe device rappresenta un usb, sarebbe comodo creare una classe astratta
   da cui ereditare, possibile nome AbsMultiDevice.
   La classe descrive un device e tutti i canali di comunicazione e configurazione
   possibili prensenti in un dispositivo usb. Si comunica con i canali attraverso
   gli Endpoin Class che ereditano da QIODevice.

   USO: Questa classe viene usata dal device manager il quale ne crea n istanze.
*/
class Device : public QObject
{
    Q_OBJECT
public:
    // classi amiche
    friend class System::Usb::DeviceManager;
    friend class Endpoint;
    // modalità di apertura del device. Nota da non confondere con l'apertura del
    // canale Endpoin.
    enum UsbOpenMode { InitDefault, InitFailFast, InitReversible, InitNonReversible };
    // Prende un device enumerator e un parent
    explicit Device(uint16_t devEnum, QObject *parent = 0);
    ~Device();
    //void setObjectState(ObjectState state) { objState = state; }
    //uint8_t objectState() { return objState; }
    int lastError() { return _lastError; }

    bool open(UsbOpenMode mode = InitDefault);
    void close();
    uint16_t vendor() { return vid; }
    uint16_t product() { return pid; }
    uint16_t deviceEnum() { return enumerator; }

private:
    char buf[256];
    uint8_t objState;
    int _lastError;
    // le stringhe conservate nel dispositivo usb sono strutture unicode
    // toQString() converte le strutture in oggetti QString
    QString toQString(usb_string_desc_t *unicodeStruct);
    // metodo chiamato da device manager quando questo device viene rimosso
    void unplugged();
    // alcuni device non ritornano un puntatore valido a devdata, questo
    // flag segnala la validità di devdata.
    bool nodevdata;

    // openusb type
    struct usb_device_desc descriptor;
    openusb_dev_data_t *devdata;        // vedi nodevdata
    openusb_dev_handle_t devh;
    uint16_t enumerator;                // l'enumeratore che identifica il device
    qint64 libhandle;
    uint16_t vid;
    uint16_t pid;
    QString serialNumber;
    QString productName;
    QString manufacturer;

    // Un device usb può avere più impostazioni alternative.
    // mantiene informazioni circa l'impostazione alternativa di un device usb,
    // sempre se presente.

    struct AlternateSetting {
        usb_interface_desc_t *interface;
        QList<usb_endpoint_desc *> endpoints;
    };

    // Un device usb può avere più interfacce
    // struttura Interfaccia
    struct UsbInterface {
        usb_interface_desc_t *interface;
        QList<usb_endpoint_desc_t *> endpoints;
        QList<AlternateSetting *> alternateSettings;
    };

    // Un device usb può avere più configurazioni
    // struttura configurazione
    struct UsbConfig {
        usb_config_desc_t *config;
        QList<UsbInterface *> interfaces;
    } ;

    QList<UsbConfig *> configs;


signals:
    // emesso a seguito della chiamata di funzione unplugged()
    void deviceUnplugged();

public slots:

};

#endif // DEVICE_H


Codice: Seleziona tutto
#include "device.h"
#include "devicemanager.h"
#include "tools.h"
using namespace System;
using namespace Usb;

Device::Device(uint16_t devEnum, QObject *parent) :
    QObject(parent), enumerator(devEnum), nodevdata(false)
{
    int ret;
    DeviceManager *dm = DeviceManager::instance();
    libhandle = dm->handle();   // serve ricavare il gestore di libreria openusb

    // ricava il descrittore descriptor
    ret = openusb_parse_device_desc(libhandle, enumerator , NULL, 0, &descriptor);
    // OPENUSB_PLATFORM_FAILURE viene ritornato da tutti i devices
    if (ret < OPENUSB_PLATFORM_FAILURE)
        qDebug() << "openusb_parse_device_desc return with error" << ret << endl
                    << "message:" << openusb_strerror(ret);

    // rivaca i dati del device devdata.
    //ATTENZIONE :devdata può essere un puntatore non valido
    ret = openusb_get_device_data(libhandle, enumerator, 0, &devdata);

    if (ret < OPENUSB_PLATFORM_FAILURE)
        qDebug() << "openusb_get_device_data return with error" << ret << endl
                    << "message:" << openusb_strerror(ret);

    vid = descriptor.idVendor;
    pid = descriptor.idProduct;
    qDebug() << "vid:" << vid << "pid:" << pid;

    if (ret < 0) {

        nodevdata = true;       // devdata è un puntatore non valido
        // Il device non ha campi stringa

    } else {

        serialNumber = toQString(devdata->serialnumber);
        qDebug() << "S/N:" << serialNumber << serialNumber.count();
        manufacturer = toQString(devdata->manufacturer);
        qDebug() << "Manufactur:" << manufacturer;
        productName = toQString(devdata->product);
        qDebug() << "Product:" << productName;
        qDebug() << QString::number(devdata->ctrl_max_xfer_size,16).prepend("0x");
        nodevdata = false;

    }

    for (uint cfgidx=0; cfgidx<descriptor.bNumConfigurations; cfgidx++) {

        usb_config_desc_t *cfg = new usb_config_desc_t;
        UsbConfig *usbConfig = new UsbConfig;
        usbConfig->config = cfg;
        configs.append(usbConfig);

        ret = openusb_parse_config_desc(libhandle, enumerator, NULL,
                    0, cfgidx, cfg);
        if(ret != 0)
            qDebug() << "openusb_parse_config_desc() return with error" << ret << endl
                        << "message:" << openusb_strerror(ret);

        for (uint ifcidx = 0; ifcidx < cfg->bNumInterfaces; ifcidx++) {

            usb_interface_desc_t *intf = new usb_interface_desc_t;
            UsbInterface *usbInterface = new UsbInterface;
            usbInterface->interface = intf;
            usbConfig->interfaces.append(usbInterface);

            int alt;

            for (alt = 0;; alt++) {
                /* no clue of how many altsettings here */
                ret = openusb_parse_interface_desc(libhandle,
                                                   enumerator, NULL, 0, cfgidx, ifcidx, alt, intf);

                if(ret != 0)
                    break;

                AlternateSetting *alternateSetting;
                if (alt) {

                    alternateSetting = new AlternateSetting;
                    alternateSetting->interface = intf;
                    usbInterface->alternateSettings.append(alternateSetting);

                }

                for (uint i = 0; i < intf->bNumEndpoints; i++) {
                    usb_endpoint_desc_t *ep = new usb_endpoint_desc_t;

                    if (alt)
                        alternateSetting->endpoints.append(ep);
                    else
                        usbInterface->endpoints.append(ep);

                    ret = openusb_parse_endpoint_desc(libhandle, enumerator, NULL, 0,
                                                      cfgidx, ifcidx, alt, i, ep);
                    if(ret != 0) {
                        //printf("parse endpoint desc fail, ret = %d %s\n",
                        //       ret, openusb_strerror(ret));
                        return;
                    }
                }
            }
        }
    }
}

QString Device::toQString(usb_string_desc_t *unicodeString)
{
    if (unicodeString)
        convert_string(buf, unicodeString, 256);

    return QString(buf);
}


Device::~Device()
{
    close();
    // per alcuni device in caso di errore devdata punta a caso
    // se nodevdata è true il device non ha un puntatore valido per devdata
    if (!nodevdata)
        openusb_free_device_data(devdata);
    //qDebug() << "dtor device";

}

bool Device::open(UsbOpenMode mode)
{
    _lastError = openusb_open_device(libhandle, enumerator, (openusb_init_flag_t)mode, &devh);
    if (_lastError != 0) {
        //qWarning("Device: openusb_open_device() return with error %d"
        //        "\nmessge: '%s'", ret, openusb_strerror(ret));
        return false;
    }
    return true;
}

void Device::close()
{
    openusb_close_device(devh);
}

void Device::unplugged()
{
    emit deviceUnplugged();
}


E per finire la classe Endpoint che modella un canale mono o bidirezionale.

Codice: Seleziona tutto
#ifndef ENDPOINT_H
#define ENDPOINT_H

#include <QIODevice>
#include "device.h"

class Device;

class Endpoint : public QIODevice
{
    Q_OBJECT
public:

    enum UsbOpenMode { InitDefault, InitFailFast, InitReversible, InitNonReversible };
    enum TransferType { Control, Bulk, Interrupt, Isochronous };
    // da usare per endpoint in solo scrittura
    explicit Endpoint(uint writeEpAddress,
                      TransferType xferType = Control,
                      Device *device = 0);
    // da usare per endpoint in lettura e scrittura
    Endpoint(uint writeEpAddress, uint readEpAddress,
             TransferType xferType, Device *device = 0);
    ~Endpoint();
    //bool open(int h, UsbOpenMode mode = InitDefault);
    bool open(OpenMode mode);
    void close();
    void setDevice(Device *device);
    void setInterface(uint usbConfig, uint iNumber, uint alternateSet);
    void setTransferType(TransferType xferType);
    void setTimeout(uint32_t time) { timeout = time; }
    bool isSequential() { return true; }
    // gestisce solo i trasferimenti in modo bulk
    qint64 readBulk(char *data, qint64 maxlen);
    qint64 writeBulk(const char *data, qint64 len);

private:
    Device *theDevice;
    uint32_t timeout;
    TransferType xferType;
    uint writeEndpointAddress;
    uint readEndpointAddress;
    uint interfaceNumber;
    uint usbConfig;
    uint alternateSettingNumber;
    // from QIODevice protect
    qint64 readData(char *data, qint64 maxlen);
    qint64 writeData(const char *data, qint64 len);

signals:

public slots:

};

#endif // ENDPOINT_H


Codice: Seleziona tutto
#include <QDebug>
#include "endpoint.h"

Endpoint::Endpoint(uint writeEpAddress, TransferType xferType, Device *device) :
    QIODevice(qobject_cast<QObject *>(device)), writeEndpointAddress(writeEpAddress),
    theDevice(device), xferType(xferType), readEndpointAddress(0)
{
    QIODevice::setOpenMode(QIODevice::WriteOnly);
}

Endpoint::Endpoint(uint writeEpAddress, uint readEpAddress, TransferType xferType, Device *device) :
    QIODevice(qobject_cast<QObject *>(device)), writeEndpointAddress(writeEpAddress),
    readEndpointAddress(readEpAddress), theDevice(device), xferType(xferType)
{
    QIODevice::setOpenMode(QIODevice::ReadWrite);
}

Endpoint::~Endpoint()
{
    //qDebug() << "dtor avrisp";
}

void Endpoint::setDevice(Device *device)
{
    theDevice = device;
}

// da rivedere USB_INIT_DEFAULT dovrebbe essere un'argomento
bool Endpoint::open(OpenMode mode )
{

    int ret = 0;

    ret = openusb_claim_interface(theDevice->devh, interfaceNumber, USB_INIT_DEFAULT);
    if (ret < 0)
        return true;
    else
        return false;
}

void Endpoint::close()
{
    openusb_release_interface(theDevice->devh, interfaceNumber);
}

void Endpoint::setInterface(uint nConfig, uint iNumber, uint alternateSet)
{

    bool endpointAddressInWriteMode = false;
    bool endpointAddressInReadMode = false;
    interfaceNumber = iNumber;
    usbConfig = nConfig;
    alternateSettingNumber = alternateSet;
    QList<usb_endpoint_desc_t *> endpointList;

    if (usbConfig > theDevice->configs.count() - 1)
        qFatal("device %d has not the configuration number %d"
               , theDevice->enumerator, usbConfig);

    if (iNumber > theDevice->configs[usbConfig]->interfaces.count() - 1)
        qFatal("device %d configuration number %d has not interface number %d"
               , theDevice->enumerator, usbConfig, iNumber);

    if (alternateSet) {
        if (alternateSet > theDevice->configs[usbConfig]->interfaces[iNumber]->alternateSettings.count() -1)
            qFatal("device %d configuration number %d interface number %d has not alterative setting number %d"
                   , theDevice->enumerator, usbConfig, iNumber, alternateSet);
        endpointList = theDevice->configs[usbConfig]->interfaces[iNumber]->alternateSettings[alternateSet]->endpoints;
        int ret = openusb_set_altsetting(theDevice->devh, iNumber, alternateSet);
        if (ret < 0)
            qFatal("openusb_set_altsetting() return with error %c"
                   "\nmessge: '%s'", ret, openusb_strerror(ret));

    } else {
        endpointList = theDevice->configs[usbConfig]->interfaces[iNumber]->endpoints;
    }

    foreach(usb_endpoint_desc_t *ep, endpointList) {
        if (ep->bEndpointAddress == writeEndpointAddress && endpointAddressInWriteMode == false) {
           if ((ep->bmAttributes & 3) !=  xferType + 1 )
               qFatal("Endpoint address %d does not support the transfer number %d"
                      , writeEndpointAddress, xferType);
           endpointAddressInWriteMode = true;
        }


        if (readEndpointAddress) {
            if (ep->bEndpointAddress == readEndpointAddress && endpointAddressInReadMode == false) {
               if ((ep->bmAttributes & 3) !=  xferType + 1 )
                   qFatal("Endpoint address %d does not support the transfer number %d"
                          , readEndpointAddress, xferType);
               endpointAddressInReadMode = true;
            }
        }
    }
    if (readEndpointAddress && !endpointAddressInReadMode)
        qFatal("Endpoint address %d not exist"
               , readEndpointAddress);
    if (!endpointAddressInWriteMode)
        qFatal("Endpoint address %d not exist"
               , writeEndpointAddress);
}

qint64 Endpoint::writeData(const char *data, qint64 len)
{
    switch (xferType) {
    case Control:
        break;
    case Bulk:
        return writeBulk(data, len);
        break;
    case Interrupt:
        break;
    case Isochronous:
        break;
    }
}

qint64 Endpoint::readData(char *data, qint64 maxlen)
{
    switch (xferType) {
    case Control:
        break;
    case Bulk:
        return readBulk(data, maxlen);
        break;
    case Interrupt:
        break;
    case Isochronous:
        break;
    }
}

qint64 Endpoint::readBulk(char *data, qint64 maxlen)
{
    // usa len e no maxlen
    quint64 len = sizeof(data)-1;

    // il tipo di traferimento
    openusb_bulk_request_t bulk;
    // pulisce bulk
    memset(&bulk, 0, sizeof(bulk));

    // crea array per ospitare il dato letto
    unsigned char bulkrd[len];
    // pulisce array
    memset(bulkrd, 0, len);

    bulk.payload = bulkrd;
    bulk.length = len;
    bulk.timeout = timeout;
    int ret = openusb_bulk_xfer(theDevice->devh, interfaceNumber, readEndpointAddress, &bulk);

    // copia l'array bulkrd nell'array di destinazione
    memcpy(data, bulkrd, len);

    if (ret < 0)
        return -1;
    else
        return len;
}

qint64 Endpoint::writeBulk(const char *data, qint64 len)
{

    // il tipo di traferimento
    openusb_bulk_request_t bulk;
    // pulisce bulk
    memset(&bulk, 0, sizeof(bulk));

    bulk.payload = (uint8_t*)data;
    bulk.length = len;
    bulk.timeout = timeout;
    int ret = openusb_bulk_xfer(theDevice->devh, interfaceNumber, writeEndpointAddress, &bulk);

    if (ret < 0)
        return -1;

    return len;
}


Il codice di basso livello per convertire una struttura unicode in char*
Codice: Seleziona tutto
#ifndef TOOLS_H
#define TOOLS_H

typedef struct usb_string_desc usb_string_desc_t;

static int convert_string(char *buf, usb_string_desc_t *st, int buflen)
{
        int di, si;
        unsigned char *tbuf = (unsigned char *)st;

        for (di = 0, si = 2; si < tbuf[0]; si += 2) {
                if (di >= (buflen - 1)) {
                        break;
                }

                if (tbuf[si + 1]) {
                        buf[di++] = '?';
                } else {
                        buf[di++] = tbuf[si];
                }
        }

        buf[di] = 0;

        return di;
}

#endif // TOOLS_H


Come si usa: Il codice seguente è parte di un progetto orientato a plugin ma non è necessario basta seguire le indicazioni
Codice: Seleziona tutto
// vedilo come il costruttore di mainwindow o di altra classe

void MainWindow::extensionsInitialized()
{
    Usb::DeviceManager *s_deviceManager = Usb::DeviceManager::instance();
    // mi serve connettere il segnale emesso allo slot per riavviare la ricerca del device a seguito della sua rimozione
    connect(s_deviceManager, SIGNAL(systemDeviceConnected(uint16_t)), this, SLOT(reinit(uint16_t)));
    // chiama initUsb() solo se il device è stato dichiarato invalido
    if (invalidDevice)
        initUsb();

   show();    // mostra mainwindow
}

void MainWindow::initUsb()
{
    // se il device è valido deve tornare senza far nulla
    if (!invalidDevice)
        return;

    Usb::DeviceManager *s_deviceManager = Usb::DeviceManager::instance();
    //qDebug() << "initUsb() slot";
    QList<Device*> machList = s_deviceManager->getDevicesFromVendor(1003, 8452);
    // se non trova alcun device matchList è vuota e allora ritorna
    if (!machList.count())
        return;
    Device *avrIspMkii = machList.at(0);          // non indago più di tanto e mi prendo il primo
    //qDebug() << "found device" << machList.count();
    // connetto il segnale emesso a seguito di rimozione allo slot deviceRemoved() dove rendo invalido il device
    connect(avrIspMkii, SIGNAL(deviceUnplugged()), this, SLOT(deviceRemoved()));
    invalidDevice = false;         // no qui è valido


    if (!avrIspMkii->open())
        qDebug() << "errore apertura device" << avrIspMkii->deviceEnum();
    else {
        // endpoint in scittura: address 0x2
        // endpoint in lettura: address 0x82
        ptr_ep = new Endpoint(0x2, 0x2, Endpoint::Bulk, avrIspMkii);   // ho usato un puntatore ma si può usare l'oggetto
        ptr_ep->setInterface(0,0,0);
        ptr_ep->setTimeout(10);
        ptr_ep->open(QIODevice::ReadWrite);

        QByteArray cmdResult;
        QByteArray writeData;
// per ricavare la versione hardware
        writeData.append(char(0x3));
        writeData.append(char(0x90));


        ptr_ep->write(writeData);
        cmdResult.clear();
        cmdResult = ptr_ep->read(3);


        qDebug() << (uint8_t) cmdResult.at(0) << (uint8_t) cmdResult.at(1) << (uint8_t) cmdResult.at(2);

        readFromUsb();


        ptr_ep->close();


    }

}

void MainWindow::readFromUsb()
{
    ptr_ep->open(QIODevice::ReadWrite);   // solo per testare perchè è già aperto
    QByteArray cmdResult;
    QByteArray writeData;
// per leggere la versione software major
    writeData.append(char(0x3));
    writeData.append(char(0x91));

    ptr_ep->write(writeData);

    cmdResult = ptr_ep->read(3);
    qDebug() << (uint8_t) cmdResult.at(0) << (uint8_t) cmdResult.at(1) << (uint8_t) cmdResult.at(2);

    cmdResult.clear();
    writeData.clear();
// per leggere la versione software minor
    writeData.append(char(0x3));
    writeData.append(char(0x92));

    ptr_ep->write(writeData);

    cmdResult = ptr_ep->read(3);
    qDebug() << (uint8_t) cmdResult.at(0) << (uint8_t) cmdResult.at(1) << (uint8_t) cmdResult.at(2);

    ptr_ep->close();


}

void MainWindow::deviceRemoved()
{

    invalidDevice = true;
    qDebug() << "device avrisp rimosso invalid device";

}

void MainWindow::reinit(uint16_t devid)
{
    qDebug() << "un nuovo dispositivo è stato connesso,reinizia se device non è valido " << invalidDevice;
   // l'evento di qualunque dispositivo connesso al pc  chiamerà questa funzione, ma avrà effetto solo se il device è invalido
    if (invalidDevice)
        initUsb();

}



Ok spero che con codice alla mano possiate darmi qualche consiglio di progettazione.

Ciao.
MauroTec
Trollino in fasce
 
Messaggi: 21
Iscritto il: 11 feb , 2011 3:01 pm
Località: Palermo
Programmo in: C/C++ python


Torna a Qt & C++

Chi c’è in linea

Visitano il forum: Nessuno e 2 ospiti

cron