2013-01-05 3 views
4

J'ai un protocole USB que je veux implémenter mais je suis un peu perdu sur la meilleure façon de le faire.Conception du programme pour la mise en œuvre du protocole USB

Le protocole USB implique l'échange de données et des paquets d'accusé de réception avant et en arrière comme si:

Device: data 
Host: ACK 
Host: reply 
Device: ACK 

Mais parfois, les paquets peuvent venir de manière asynchrone comme ceci:

Device: data #1 
Device: data #2 
Host: ACK #1 
... 

Je veux avoir une API Cela permettra de faire abstraction de tous les détails de l'USB et de faire fonctionner le programme avec les données réelles sans avoir à se soucier des en-têtes de paquets ou de reconnaître les paquets ou quelque chose comme ça. Idéalement, il y aura une fonction write_to_device qui bloque jusqu'à ce que le périphérique reconnaisse le paquet, une read_from_device qui bloquera jusqu'à ce qu'un paquet soit reçu et une fonction is_data_available qui renvoie immédiatement s'il y a des données dans la file d'attente.

Je pense à exécuter un thread séparé qui gère les événements USB. Ce thread va gérer toute l'encapsulation et la reconnaissance des données.

Lorsqu'un paquet arrive, le thread de traitement envoie un paquet ACK puis extrait et écrit les données brutes dans un canal. La fonction read_from_device (appelée à partir du thread principal) lira simplement à partir de ce tuyau et bloquera naturellement jusqu'à ce qu'il y ait des données. Mais si j'utilise ce schéma, je n'aurai pas une manière propre d'implémenter une fonction is_data_available - il n'y a aucun moyen de vérifier s'il y a des données dans un tube sans le lire.

Quelque chose comme ceci:

[ Main thread ][ Processing thread ] 
| Read from pipe ||      | 
|    || USB packet comes in | 
|    || Send ACK packet  | 
|    || Extract data  | 
|    || Write data to pipe | 
| Read succeeds ||      | 
| Return data ||      | 

La vraie question est implémenter une fonction write_to_device. Comment puis-je mettre en œuvre de manière propre un moyen d'envoyer le paquet, attendre un paquet d'accusé de réception, puis retourner?

+0

Cela n'a aucun sens, l'USB l'implémente déjà. Notez le paquet de prise de contact ACK dans cette description: http://www.beyondlogic.org/usbnutshell/usb3.shtml –

+0

L'ACK est requis au niveau du protocole d'application. – tangrs

Répondre

1

Je vous suggère de créer une classe ou une structure de tuyau personnalisée ou quelque chose de ce genre. Pour cela, vous définissez une méthode d'écriture, qui contient également les attentes d'un sémaphore à déclencher. Si vous êtes sur linux, sem_wait (de la famille de la fonction sémaphore, sem_*) est ce que vous voulez regarder.

La fonction d'écriture écrirait alors les données dans la mémoire FIFO et attendrait que le sémaphore soit marqué. Cependant, comment le thread d'écriture sait quand toutes les données sont arrivées à travers le tuyau que vous vouliez envoyer? Si le thread doit lire de manière bloquante, des problèmes peuvent survenir ici.

Donc, je suggère que vous utilisiez un microformat à l'intérieur du tuyau du thread principal au thread de traitement, en envoyant une taille d'entier qui définit combien d'octets vous allez écrire. Le thread de traitement lira alors cette quantité d'octets, la transmettra au périphérique et marquera le sémaphore dès que toutes les données seront marquées. La fonction write attendra le sémaphore, donc le blocage non occupé jusqu'à la fin du processus de traitement.

Voilà comment un struct tuyau personnalisé et la fonction d'écriture décrit pourraient être rédigés:

#include <stdlib.h> 
#include <unistd.h> 
#include <semaphore.h> 

typedef struct { 
    int write_to_pipe, read_from_pipe; 
    sem_t *write_sem; 
} MyPipe; 

MyPipe *pipe_new() { 
    int fds[2]; 
    if (pipe(fds)) { 
     // handle error here 
     return NULL; 
    } 

    sem_t *sem = NULL; 
    if (sem_init(sem, 0, 0)) { 
     // handle error here 
     close(fds[0]); 
     close(fds[1]); 
     return NULL; 
    } 

    MyPipe *result = malloc(sizeof(MyPipe)); 
    result->write_to_pipe = fds[1]; 
    result->read_from_pipe = fds[0]; 
    result->write_sem = sem; 
    return result; 
} 

void pipe_write(MyPipe *pipe, const unsigned char *buf, const int size) { 
    write(pipe->write_to_pipe, &size, sizeof(int)); 
    write(pipe->write_to_pipe, buf, size); 
    sem_wait(pipe->write_sem); 
} 

Le fil de traitement ne saurait l'instance MyPipe et lire read_from_pipe chaque fois qu'il le désire.Il lit d'abord la quantité d'octets que le thread principal a écrit sur le tuyau et ensuite tous les octets sont des morceaux arbitraires. Après toutes les données ont été envoyées à l'appareil et a été ACK par elle, il peut sem_post le sémaphore, de sorte que pipe_write reviendra.

En option, on peut ajouter un autre sémaphore, qui pipe_write poste pour que le thread de traitement ne lise les données que lorsqu'il y a réellement des données disponibles.

Avertissement: N'a pas testé le code, seulement vérifié qu'il compile. Doit être construit avec -pthread, pour avoir sem_* disponible.

+0

Ah, je n'ai pas pensé à utiliser des sémaphores comme méthode de signalisation. Merci! – tangrs

1

libusb plus ou moins déjà fait tout ce que vous avez décrit. Chaque point de terminaison USB peut être vu comme un socket datagramme, que vous pouvez écrire avec libusb_interrupt_transfer (ou libusb_control_transfer). Dans ces fonctions, vous passez un tableau qui fonctionne comme l'entrée ou la sortie. Il n'y a pas besoin d'envoyer des accusés de réception et autres. La direction de l'entrée ou de la sortie dépend de la configuration du point de terminaison.

Il y a aussi un asynchronous API où vous initiez le transfert et ajouter des descripteurs de fichiers à votre boucle principale select ou poll, et éventuellement obtenir un rappel lorsque l'E/S est terminée.

+0

Le périphérique USB avec lequel je travaille utilise des transferts groupés pour tout. L'ACK est pour le protocole d'application qui se trouve au-dessus du protocole USB. J'utilise déjà l'API asynchrone dans le thread de traitement. – tangrs

Questions connexes