Grosse galère USB

3 views
Skip to first unread message

Alexandre Haffner

unread,
Apr 1, 2008, 10:10:15 PM4/1/08
to Développement et utilisation de NxOS
Bonjour à tous,

Ca fait un petit moment que je tests pas mal de trucs avec l'usb et
y'a des trucs qui m'échappent.

Voilà mon petit bout de code de test :

U32 v = 0;
U32 s = 0;

// Wait for the size of the file to download.
nx_usb_read((U8*)&v, sizeof(U32));
while(!(s=nx_usb_data_read())){ nx_systick_wait_ms(200); }

nx_display_uint(s);
nx_systick_wait_ms(5000);

Le fonctionnement est assez simple : j'attend 4 octets arrivant sur
l'usb, je les balance dans un entier 32 bit et voila. Seulement j'ai 2
soucis plutot génants. Si j'envoie 1, 2, 3 ou 4 octets, je n'ai bien
sur aucun problème et c'est la valeur correct qui s'affiche. Si
j'envoie un 5eme octet j'ai l'impression que la brick se bloque. Je
suppose que c'est parcequ'on essaie de mettre cet octet en &v+4 qui
n'est bien sur pas alloué...

D'ou ma question : la fonction usb_read n'est elle pas censé récupérer
que size (ici sizeof(U32) = 4) octets et laisser le reste dans le
buffer ? Si ce n'est pas le cas je ne vois pas comment gérer l'envoi
de plusieurs entiers par exemple, sans mette de wait coté pc. Et si ce
n'est pas le cas je ne vois pas l'utilité de ce paramètre size.

Après ca arrive la seconde question... je me dis cool je vais
reprendre le script python de la console, l'adapter un peu et envoyer
1 entier sur 4 octet donnant la taille du fichier puis ensuite
télécharger le fichier sur la brick après avoir alloué dynamiquement
la mémoire.

Mon problème est que je n'arrive pas à envouer un entier de 4 octet
depuis python.

J'utilise :

while not (brick.write(...)):
time.sleep(1)

La fonction write prend apparement comme paramètre une séquence. A
priori elle servait à envoyer les commandes, chaine de caractère donc.
Je me suis dit, aller j'envoi un tableau : [12] , ca marche. Mais la
fonction n'envoi qu'un octet. Je test [123456789] bien sur codé sur
largement plus d'un octet (4 je crois), et ma brick ne reçois qu'un
octet.

Conclusion, je suis dans une impasse :)

Sinon j'en profite pour signaler une erreur dans le kernel de tests je
crois :

void tests_usb(void) {
U16 i;
U32 lng = 0;

char buffer[NX_USB_PACKET_SIZE];

hello();

while(1) {
nx_display_cursor_set_pos(0, 0);
nx_display_string("Waiting command ...");

nx_usb_read((U8 *)&buffer, NX_USB_PACKET_SIZE * sizeof(char)); //
<---------------- (U8*)buffer me semble plus approprié, mais
apparement ca n'a pas d'influence, si quelqu'un sait pourquoi...
...
}

...

}

Merci d'avance pour votre aide !

Alexandre H.

Jerome Flesch

unread,
Apr 2, 2008, 12:17:52 AM4/2/08
to nxos-di...@googlegroups.com
>
> Bonjour à tous,
>
> Ca fait un petit moment que je tests pas mal de trucs avec l'usb et
> y'a des trucs qui m'échappent.
>
> Voilà mon petit bout de code de test :
>
> U32 v = 0;
> U32 s = 0;
>
> // Wait for the size of the file to download.
> nx_usb_read((U8*)&v, sizeof(U32));
> while(!(s=nx_usb_data_read())){ nx_systick_wait_ms(200); }
>
> nx_display_uint(s);
> nx_systick_wait_ms(5000);
>
> Le fonctionnement est assez simple : j'attend 4 octets arrivant sur
> l'usb, je les balance dans un entier 32 bit et voila. Seulement j'ai 2
> soucis plutot génants. Si j'envoie 1, 2, 3 ou 4 octets, je n'ai bien
> sur aucun problème et c'est la valeur correct qui s'affiche. Si
> j'envoie un 5eme octet j'ai l'impression que la brick se bloque. Je
> suppose que c'est parcequ'on essaie de mettre cet octet en &v+4 qui
> n'est bien sur pas alloué...
>
> D'ou ma question : la fonction usb_read n'est elle pas censé récupérer
> que size (ici sizeof(U32) = 4) octets et laisser le reste dans le
> buffer ?
>
Quel buffer ? :P
Le pilote doit etre capable de fonctionner sans l'allocateur memoire,
donc pour bufferiser, c'est tendu. Par contre, ca ne devrait pas
planter.


Je ne sais plus si normalement il devrait jeter les octets qu'il
recoit en trop ou s'il est en mesure de bloquer l'ecriture depuis
l'ordinateur. S'il les jete, j'ai du ecrire une fonction genre
nx_usb_overloaded() pour savoir si ca se produit ... mais mes
souvenirs a ce sujet ne sont plus tres frais, je vais tacher de
regarder ca une fois rentre chez moi.


> Si ce n'est pas le cas je ne vois pas comment gérer l'envoi
> de plusieurs entiers par exemple, sans mette de wait coté pc.
>

Je suggererais l'etablissement d'un protocole avec envoi et accuse de reception.
Genre le PC envoi, la brique traite et renvoit un accuse de reception
pour demander la suite. (je sais pas si c'est cette attente d'accuse
de reception que tu appelles un wait() ?)


> Et si ce
> n'est pas le cas je ne vois pas l'utilité de ce paramètre size.
>
> Après ca arrive la seconde question... je me dis cool je vais
> reprendre le script python de la console, l'adapter un peu et envoyer
> 1 entier sur 4 octet donnant la taille du fichier puis ensuite
> télécharger le fichier sur la brick après avoir alloué dynamiquement
> la mémoire.
>
> Mon problème est que je n'arrive pas à envouer un entier de 4 octet
> depuis python.
>
> J'utilise :
>
> while not (brick.write(...)):
> time.sleep(1)
>
> La fonction write prend apparement comme paramètre une séquence. A
> priori elle servait à envoyer les commandes, chaine de caractère donc.
> Je me suis dit, aller j'envoi un tableau : [12] , ca marche. Mais la
> fonction n'envoi qu'un octet. Je test [123456789] bien sur codé sur
> largement plus d'un octet (4 je crois), et ma brick ne reçois qu'un
> octet.
>

Euf, je dirais, essaye un tableau de 4 elements d'un octet chacun.
Mais la encore je me souviens plus precisement comment le code python
marche.


> Conclusion, je suis dans une impasse :)
>

Mais non mais non ... :)


> Sinon j'en profite pour signaler une erreur dans le kernel de tests je
> crois :
>
> void tests_usb(void) {
> U16 i;
> U32 lng = 0;
>
> char buffer[NX_USB_PACKET_SIZE];
>
> hello();
>
> while(1) {
> nx_display_cursor_set_pos(0, 0);
> nx_display_string("Waiting command ...");
>
> nx_usb_read((U8 *)&buffer, NX_USB_PACKET_SIZE * sizeof(char)); //
> <---------------- (U8*)buffer me semble plus approprié, mais
> apparement ca n'a pas d'influence, si quelqu'un sait pourquoi...
> ...
>

Parce-que le tableau 'buffer' est "alloue" sur la stack de la
fonction. Ce n'est donc pas un pointeur vers un tableau alloue
dynamiquement mais directement le tableau lui-meme. Et donc en
utilisant '&' tu obtiens un pointeur vers le debut de ce tableau.
Tu peux essayer sans '&' si tu veux : si ma theorie est juste, ca
devrait planter, parce-qu'il va alors considerer les 4 premiers octets
du tableau comme un pointeur.

> }
>
> ...
>
> }
>
> Merci d'avance pour votre aide !
>
> Alexandre H.

PS: Desole pour les accents manquants, mais je suis sur un clavier
qwerty actuellement.

Alexandre Haffner

unread,
Apr 2, 2008, 6:06:56 AM4/2/08
to Développement et utilisation de NxOS
Bonjour,
C'est ce à quoi j'ai pensé ce matin au réveil. J'étais un peu vert
hier ^^
Je devrais pouvoir m'en sortir meme si les octet en trop sont jeté,
par contre... faut pas que ca plante si y'en a trop !

>
> > Et si ce
> > n'est pas le cas je ne vois pas l'utilité de ce paramètre size.
>
> > Après ca arrive la seconde question... je me dis cool je vais
> > reprendre le script python de la console, l'adapter un peu et envoyer
> > 1 entier sur 4 octet donnant la taille du fichier puis ensuite
> > télécharger le fichier sur la brick après avoir alloué dynamiquement
> > la mémoire.
>
> > Mon problème est que je n'arrive pas à envouer un entier de 4 octet
> > depuis python.
>
> > J'utilise :
>
> > while not (brick.write(...)):
> > time.sleep(1)
>
> > La fonction write prend apparement comme paramètre une séquence. A
> > priori elle servait à envoyer les commandes, chaine de caractère donc.
> > Je me suis dit, aller j'envoi un tableau : [12] , ca marche. Mais la
> > fonction n'envoi qu'un octet. Je test [123456789] bien sur codé sur
> > largement plus d'un octet (4 je crois), et ma brick ne reçois qu'un
> > octet.
>
> Euf, je dirais, essaye un tableau de 4 éléments d'un octet chacun.
> Mais la encore je me souviens plus précisément comment le code python
> marche.
>

Alors un tableau de 4 éléments d'un octet ca marche, bien sur. Mais ca
sent la galère pour convertir un int en tableau de 4 octets, d'autant
qu'envoyer un entier devrait être quelque chose d'évident. Frustrant
^^

En fait j'ai plusieurs problème : je ne connais pas python et ses
subtilités, Alex M. non plus, donc on y est allé un peu violemment
pour commencer. Je serais tenté de faire une fonction qui prend un int
et qui le filtre avec 0x000F, 0x00F0 + décale 1 fois etc... mais je
vois pas trop comment faire en python.

> > Conclusion, je suis dans une impasse :)
>
> Mais non mais non ... :)
>
>
>
> > Sinon j'en profite pour signaler une erreur dans le kernel de tests je
> > crois :
>
> > void tests_usb(void) {
> > U16 i;
> > U32 lng = 0;
>
> > char buffer[NX_USB_PACKET_SIZE];
>
> > hello();
>
> > while(1) {
> > nx_display_cursor_set_pos(0, 0);
> > nx_display_string("Waiting command ...");
>
> > nx_usb_read((U8 *)&buffer, NX_USB_PACKET_SIZE * sizeof(char)); //
> > <---------------- (U8*)buffer me semble plus approprié, mais
> > apparement ca n'a pas d'influence, si quelqu'un sait pourquoi...
> > ...
>
> Parce-que le tableau 'buffer' est "alloue" sur la stack de la
> fonction. Ce n'est donc pas un pointeur vers un tableau alloue
> dynamiquement mais directement le tableau lui-meme. Et donc en
> utilisant '&' tu obtiens un pointeur vers le debut de ce tableau.
> Tu peux essayer sans '&' si tu veux : si ma theorie est juste, ca
> devrait planter, parce-qu'il va alors considerer les 4 premiers octets
> du tableau comme un pointeur.
>

J'ai des gros doutes la dessus. Un tableau est un pointeur sur son
premier élément.
Essaye de faire :

void func(char* t)
{

}

char tab[10];
func(&tab);

Tu auras un problème de typage car tu passes un char**
Cette erreur est masquée par le cast dans le code NxOS : (U8 *)&buffer

Ca doit marcher parceque, ... ne me demande pas pourquoi :), c'est un
détail d'implémentation dont je n'ai pas connaissance. Mais en tout
cas je ne crois pas que ce soit la notation correcte.


> > }
>
> > ...
>
> > }
>
> > Merci d'avance pour votre aide !
>
> > Alexandre H.
>
> PS: Desole pour les accents manquants, mais je suis sur un clavier
> qwerty actuellement.

Pas de problème, merci beaucoup pour ton aide ! En attendant une
nouvelle réponse, surtout concernant le plantage !

A bientôt !

David Anderson

unread,
Apr 2, 2008, 7:26:02 AM4/2/08
to nxos-di...@googlegroups.com
2008/4/2 Alexandre Haffner <haffne...@gmail.com>:

> Alors un tableau de 4 éléments d'un octet ca marche, bien sur. Mais ca
> sent la galère pour convertir un int en tableau de 4 octets, d'autant
> qu'envoyer un entier devrait être quelque chose d'évident. Frustrant
> ^^
>
> En fait j'ai plusieurs problème : je ne connais pas python et ses
> subtilités, Alex M. non plus, donc on y est allé un peu violemment
> pour commencer. Je serais tenté de faire une fonction qui prend un int
> et qui le filtre avec 0x000F, 0x00F0 + décale 1 fois etc... mais je
> vois pas trop comment faire en python.

Beaucoup plus simple: utilise le module struct. C'est un module qui
permet de sérialiser/désérialiser des types fondamentaux du C. Il est
utilisé pour parser des protocoles binaires (je m'en suis par exemple
déjà servi pour décortiquer des trames ethernet), et peut également
construire des messages binaires. Il sait encoder des entiers 32 bits,
et est même au courant des questions d'endianness.

http://docs.python.org/lib/module-struct.html

En gros:

import struct
bin = struct.pack('<L', 12345)

te donnera la séquence d'octets correspondant au nombre 12345, au
format unsigned long int (32 bits), au format little-endian. De même,
struct.unpack te permttra de faire l'opération inverse, et
struct.calcsize te dire combien d'octets fait une sérialisation
donnée.

> J'ai des gros doutes la dessus. Un tableau est un pointeur sur son
> premier élément.
> Essaye de faire :
>
> void func(char* t)
> {
>
> }
>
> char tab[10];
> func(&tab);
>
> Tu auras un problème de typage car tu passes un char**
> Cette erreur est masquée par le cast dans le code NxOS : (U8 *)&buffer
>
> Ca doit marcher parceque, ... ne me demande pas pourquoi :), c'est un
> détail d'implémentation dont je n'ai pas connaissance. Mais en tout
> cas je ne crois pas que ce soit la notation correcte.

Je n'ai pas le code sous la main, mais si buffer est effectivement un
tableau, et si la fonction prend un U8*, alors on a effectivement un
problème :-). Et, comme Jérôme, je ne suis pas sur de comprendre
comment ca a bien pu marcher jusqu'à présent s'il y a effectivement un
bug là. J'étudierai ça plus en détails ce soir.

Voila, mon humble contribution ici, mais pour les questions qui
touchent à l'USB, c'est Jérôme l'expert, pas moi :-).

- Dave

Alexandre Haffner

unread,
Apr 2, 2008, 10:27:42 AM4/2/08
to Développement et utilisation de NxOS
Ah ben merci pour l'aiguillage sur la struct c'est pile poil ce qu'il
me faut apparemment !

En ce qui concerne le pointeur, c'est sur et certain qu'il y a un
problème.
Le fait que le tableau soit alloué sur la pile ne change rien au fait
qu'on y accède via l'adresse de son premier élément.
Le cast masque l'erreur de compilation et le & ne doit avoir aucun
effet pour une raison obscure dépendante de la façon dont cela est
geré par le compilo je suppose.

Une idée pour éviter le débordement lors de l'envoi de plus de size
octets ?

Alexandre

On 2 avr, 13:26, "David Anderson" <d...@natulte.net> wrote:
> 2008/4/2 Alexandre Haffner <haffner.a...@gmail.com>:

David Anderson

unread,
Apr 2, 2008, 11:45:51 AM4/2/08
to nxos-di...@googlegroups.com
2008/4/2 Alexandre Haffner <haffne...@gmail.com>:

>
> Ah ben merci pour l'aiguillage sur la struct c'est pile poil ce qu'il
> me faut apparemment !
>
> En ce qui concerne le pointeur, c'est sur et certain qu'il y a un
> problème.
> Le fait que le tableau soit alloué sur la pile ne change rien au fait
> qu'on y accède via l'adresse de son premier élément.
> Le cast masque l'erreur de compilation et le & ne doit avoir aucun
> effet pour une raison obscure dépendante de la façon dont cela est
> geré par le compilo je suppose.

Je vais me pencher la dessus, c'est vraiment pas normal que ca puisse
marcher. Et comme je suis à la recherche de possibles corruptions de
mémoire dans les pilotes, qui entraineraient un plantage de mon
scheduler, ce genre de bug m'intéresse fortement :P

> Une idée pour éviter le débordement lors de l'envoi de plus de size
> octets ?

Jérôme? Je n'ai pas trop suivi ce qui se passe la avec le driver USB.

- Dave

Alexandre Haffner

unread,
Apr 2, 2008, 12:15:11 PM4/2/08
to Développement et utilisation de NxOS
Franchement j'ai du mal avec l'usb ^^

Impossible de recevoir plus de 64 octet avec la fonction read, ce qui
peut paraitre logique si elle ne lit qu'un paquet (ce qui est
apparement le cas au vu du code). Ce serait peut être bien de le
documenter si c'est le cas.

Sinon le débordement je sais pas... parcequ'il y a bien apparement un
test qui vérifie si on ne dépasse pas.

Je coince un peu.

Alex
Reply all
Reply to author
Forward
0 new messages