Obj-C code hexadecimal d'une string

obi wan

Membre expert
Club iGen
19 Mars 2003
1 634
86
Bonjour,

Je débute en objective-C, et je m'arrache le peu de cheveux que j'ai depuis 2 heures sur un problème qui paraitra surement tout bête aux spécialistes... Je veux récupérer les codes hexadécimaux des caractères d'une chaine pour pouvoir envoyer une requete à un périphérique bluetooth.

Donc j'ai une méthode :
Bloc de code:
- (void)envoiRequetePremierFichier:(NSString *)extension {
	if ( mRFCOMMChannel != nil ) {
		unsigned char lenPf = 3 + [extension length];
		unsigned char lenPfDeux = 5 + [extension length];
		const char *extensionPf = [extension UTF8String];
		RFCOMMChannel writeSync:[[NSString stringWithFormat:@"%c\x00\x01\x86%s\x00",lenPf,extensionPf] UTF8String] length:lenPfDeux];// ça ne fonctionne pas
		//RFCOMMChannel writeSync:"\x08\x00\x01\x86\x2a\x2e\x72\x78\x65\x00" length:10]; //ça fonctionne très bien quand je remplis 'à la main' comme ça
	}
}

que j'appelle comme ça :
Bloc de code:
NSString *extension = @"*.rxe";
[self envoiRequetePremierFichier:extension];

Pour comprendre un peu la structure de la chaine que je veux envoyer au périphérique, voilà ce que contient la chaine faite à la main qui fonctionne :
\x08 : octet 0 : LSB, pseudo-unités de long du message moins les 2 octets du début
\x00 : octet 1 : MSB, pseudo-dizaines de long du message moins les 2 octets du début
\x01 : octet 2 : code pour dire que c'est une requete
\x86 : octet 3 : code de la requete (ici requete sur le 1er element d'une liste de fichiers)
\x2a : octet 4 : caractere ascii *
\x2e : octet 5 : caractere ascii .
\x72 : octet 6 : caractere ascii r
\x78 : octet 7 : caractere ascii x
\x65 : octet 8 : caractere ascii e
\x00 : octet 9 : octet NULL

Je comprends toujours pas pourquoi les octets 0 et 1 sont inversés, ni ce que veulent dire LSB et MSB, rien dans la doc du protocole de communication du périphérique ne l'indique, comme si c'était un acronyme très très connu... si quelqu'un sait je veux bien une explication (d'ailleurs tous les octets qui concernent une taille sont inversés dans les communications c'est étrange, peut etre que ça a une utilité pratique).

Donc cette chaine, construite à la main, fonctionne, je reçois ce qu'il faut du périphérique.
Par contre quand j'utilise ma fonction, je ne reçois pas la bonne réponse, alors que la requête est censée être la même. Je pense que je me plante dans la construction de la chaine, mais j'ai beau chercher je vois pas trop où... et comme je débute complètement en objective-C je me dis qu'il y a peut être une grosse bourde ailleurs que j'ai pas vue...
 
Salut,

Selon ta description, ça devrait donner ça:

Bloc de code:
 NSString* strExt=@"*.rxe";
int longueurExt=[strExt length];
int longueurMsg=longueurExt+3;			
int longueurPoidsFort=longueurMsg/10;		// MSB
int longueurPoidsFaible=longueurMsg%10;		// LSB , %=modulo , google est ton ami :)
char msg[80];			// prévoir large !
msg[0]=longueurPoidsFaible;
msg[1]=longueurPoidsFort;
msg[2]=1;
msg[3]=0x86;
memcpy(msg+4,[strExt UTF8String],longueurExt);
msg[4+longueurExt]=0;

RFCOMMChannel writeSync:msg length:longeurMsg+2
 
  • J’aime
Réactions: obi wan
Ben si justement, LSB et MSB sont des acronymes très connus.

LSB: Least Significant Bit = Bit de poids faible
MSB: Most Siginificant Bit = Bit de poids fort.

Ca peut aussi vouloir dire MSByte ou LSByte, selon le contexte (mais c'est rare).

Pour le fait que les octets des longueurs sont inversés, il s'agit sans doute d'un problème d'endianness. Attention, tu as ici un risque d'incompatibilité de ton code des proc. Intel <> PowerPC.


Je n'ai pas le temps d'étudier RFCOMM, mais on dirait que writeSync: n'attend pas une une NSString mais une chaîne C (sans l'octet nul final, soit dit en passant, puisqu'on passe la longueur).

Essaie

Bloc de code:
char message[]={0x08, 0x00, 0x01, 0x86, 0x2A, 0x2E, 0x72, 0x78, 0x65, 0x00};
[RFCOMMchannel writeString:message length:sizeof(message)];
 
LSB = less significant byte (= octet de poids le plus faible)
MSB = most significant byte (= octet de poids le plus fort)

L'ordre dans lequel sont transmis ou stock&#233;s les octets d&#233;pend de la convention adopt&#233;e.

Historiquement, les processeurs Motorola/Freescale (68k, PowerPC) stockent le poids le plus fort d'abord. Le premier octet est le MSB, et le dernier est le LSB. Cette convention s'appelle big-endian ou big-end-first (= commen&#231;ant par le plus grand). On l'utilise dans certains protocoles r&#233;seau et certains formats de fichiers graphiques.

A contrario, les processeurs Intel stockent le poids le plus faible d'abord. Le premier octet est le LSB, et le dernier est le MSB. Cette convention s'appelle little-endian ou little-end-first (= commen&#231;ant par le plus petit). Elle pr&#233;sente l'avantage d'autoriser la lecture d'un nombre sans devoir tenir compte de la taille de la structure qui le contient : qu'on stocke 08 (byte), 0008 (short) ou 00000008 (long), on aura toujours la valeur 08 stock&#233;e &#224; la m&#234;me adresse, au d&#233;but de la structure.
 
Merci mpergand, ta solution fonctionne à merveille :)

Céroce a dit:
Je n'ai pas le temps d'étudier RFCOMM, mais on dirait que writeSync: n'attend pas une une NSString mais une chaîne C (sans l'octet nul final, soit dit en passant, puisqu'on passe la longueur).
C'est bien pour ça que j'essayais d'utiliser UTF8String ;)
L'octet nul final, soit dit en passant, m'est imposé par le protocole de communication de mon périphérique ;) si je le mets pas le periphérique considérera que le message est non conforme.

Par contre je vois pas pourquoi j'ai des risques d'incompatibilité... mon périphérique je lui envoie des octets mais toujours 'à la main', c'est moi qui choisit l'ordre. Et ce qu'il me renvoie je sais que c'est dans le sens LSB puis MSB. J'avoue que tout ça me perd un peu...
 
Merci mpergand, ta solution fonctionne à merveille

Mouais, j'suis pas certain à cause de ça:
\x08 : octet 0 : LSB, pseudo-unités de long du message moins les 2 octets du début
\x00 : octet 1 : MSB, pseudo-dizaines de long du message moins les 2 octets du début

La longueur est surement un entier de 16 bits au format little endian, ce qui donne plutôt:
Bloc de code:
int longueurPoidsFort=longueurMsg>>8;	// MSB
int longueurPoidsFaible=longueurMsg&0xff; // LSB

Je suis aussi sceptique sur l'utilité du zéro final, mais puisque tu dis que ça marche pas sans ...
 
Effectivement, j'avais corrigé ça tout seul ;) la longueur est bien codée sur deux octets, dans l'ordre LSB puis MSB.

C'est marrant que vous soyiez sceptiques sur l'octet nul final... parce que c'est écrit noir sur blanc dans la doc... lisez par vous même ici : sur cette page, suffit de télécharger le bluetooth developer kit, dedans il y a des PDF avec tout bien documenté.
Accessoirement, si j'envoie la commande sans octet nul à la fin, le périphérique me renvoit un code d'erreur. Si j'envoie la commande tout bien comme dit dans la doc, ça fonctionne. Donc je vais pas trop me poser la question plus que ça, je suis scrupuleusement octet par octet ce qu'il y a dans la doc de chaque requete possible...

Merci encore ! :up:
 
C'est bien pour ça que j'essayais d'utiliser UTF8String ;)
Oui, mais...
Quand tu déclares une chaine ainsi:
char maChaine[] = "Ceci n'est pas une chaîne";

Il s'agit déjà d'une chaîne UTF-8 si l'encodage de ton source est UTF-8. Il n'y a pas besoin d'utiliser une NSString. Par ailleurs créer ainsi une chaîne te met bien l'octet nul à la fin.

C'est marrant que vous soyiez sceptiques sur l'octet nul final...
L'octet nul final, soit dit en passant, m'est imposé par le protocole de communication de mon périphérique ;) si je le mets pas le periphérique considérera que le message est non conforme.

Non, ce n'est pas marrant, c'est une déduction logique de notre part. L'octet nul final sert à marquer la fin de la chaîne. Si tu fournis la longueur de la chaine dans le length:, alors il ne sert à rien. Mais si la doc dit qu'il faut mettre un octet nul, met-le.

Par contre je vois pas pourquoi j'ai des risques d'incompatibilité... mon périphérique je lui envoie des octets mais toujours 'à la main', c'est moi qui choisit l'ordre. Et ce qu'il me renvoie je sais que c'est dans le sens LSB puis MSB. J'avoue que tout ça me perd un peu...

En effet, tu n'as pas de risque d'incompatibilité tant que tu travailles avec des octets.
 
  • J’aime
Réactions: obi wan
Oui, mais...
Quand tu déclares une chaine ainsi:
char maChaine[] = "Ceci n'est pas une chaîne";
Il s'agit déjà d'une chaîne UTF-8 si l'encodage de ton source est UTF-8. Il n'y a pas besoin d'utiliser une NSString. Par ailleurs créer ainsi une chaîne te met bien l'octet nul à la fin.
Aaaaaah :) ! précision utile effectivement ;) merci beaucoup.
Petit à petit j'avance, mais ça fait bizarre l'objective-C quand on vient d'autres langages.
 
Disons qu'il y a beaucoup à apprendre.
Il faut déjà bien connaître le C (c'est le problème sur lequel tu butais), ensuite les classes de Cocoa et la syntaxe particulière d'ObjC.

Personnellement, j'ai toujours pas compris comment fonctionnaient les Cocoa Bindings. La doc d'Apple mélange tout, et cette partie d'Interface Builder est très mal faite, avec des dénominations qui me paraissent incompréhensibles.:mouais:
 
C&#233;roce;4457391 a dit:
Disons qu'il y a beaucoup &#224; apprendre.
Il faut d&#233;j&#224; bien conna&#238;tre le C (c'est le probl&#232;me sur lequel tu butais), ensuite les classes de Cocoa et la syntaxe particuli&#232;re d'ObjC.
Exactement ;) En fait je d&#233;bute complet en "vrai" C, le seul C que j'ai jamais utilis&#233; c'est celui de mon robot et c'est... comment dire ? primitif... :D (j'en ai fait en cours un peu aussi mais c'est vieux maintenant ).
Par contre je connais tr&#232;s bien la programmation objet et ses m&#233;canismes. La syntaxe obj-C m'a paru &#233;trange au d&#233;but mais finalement on s'y fait, comme tout. Malgr&#233; tout je trouve &#231;a assez lourd (je suis tr&#232;s habitu&#233; &#224; la syntaxe point&#233;e alors tous ces crochets je trouve &#231;a moche et illisible :rateau: ).
Il me manque encore des base sur les classes obj-C comme une vraie explication compl&#232;te de ce que doivent faire les m&#233;thodes alloc/dealloc d'une classe et comment / pourquoi / quand on doit les overrider. Que sont ces "release" sur les instances de classes ? (en fait je lis des sources &#224; droite &#224; gauche pour voir alors je pige pas tout forc&#233;ment... :) )
Les pointeurs... bien compris, assez pour voir que au d&#233;but les pointeurs de variable vont me servir, mais allouer des blocs de m&#233;moire et les parcourir &#224; la main je pense que je ferai pas &#231;a tout de suite, va ptetre falloir un bout de temps avant que j'aie besoin de &#231;a :D )


Pour ceux qui savent programmer correctement dans un autre langage et veulent d&#233;buter objective-C sans bases de C, voil&#224; quels tutos j'ai lu et dans quel ordre, si &#231;a peut aider... (&#231;a va douuuuucement hein mais c'est bien de tout lire) :

- Un peu de Interface builder et de xcode, prise en main...
- Un peu de d&#233;but de C pour cocoa
- du plus de C pour cocoa
- et encore un peu du plus de C pour cocoa
- Retour &#224; xcode / cocoa / objective-C

- Conventions / style : p1 / p2

&#192; partir de l&#224; on peut un peu aller dans tous les sens, mais globalement cet ordre de lecture me parait chouette quand on a jamais trop touch&#233; &#224; C/obj-C.



Edit : les bindings
 
Pour la gestion mémoire en objC:
http://www.stepwise.com/Articles/Technical/HoldMe.html

Mais le meilleur texte sur le sujet, reste celui d'Aaron Hillegass dans Cocoa par la pratique.


Et sinon, j'ai déjà lu cet article sur les bindings, et celui-ci a le même problème que tous les autres: pas foutu d'expliquer clairement comment on remplace l'écriture des getters & setters par des bindings; parce que c'est quand même à ça que ça sert avant tout (pas à faire joujou avec un fichier de préférences, ou gérer des listes automatiquement).
 
Je réalise la connexion d'un laser-metre en BT de façon a recevoir les mesures.
La réception de celles-ci ne pose plus de problème, il est possible de le commander par l'envoi de caractère que je fais comme ça:

message étant une NSString avec @"p" par exemple...

Bloc de code:
NSString * caractere = [message stringByAppendingString:@"\r\n"]; // 
	
	ret = [mChannel writeSync:[caractere UTF8String] length:[caractere length]+2];
	NSLog(@"apres writeSync : %@",caractere);
	[caractere autorelease];
après avoir fait ça a l'ouverture du Channel:

Bloc de code:
[mChannel setSerialParameters:9600 dataBits:8 parity:kBluetoothRFCOMMParityTypeNoParity stopBits:1];

Il est demandé
9600 Baud, none parity, 8 databits, 1 stopbit

Dans un premier temps le premier envoi se passait bien et c'était signifié par le retour "?" prévu et au 2eme envoi il y avait blocage...:(

Maintenant il y a blocage au premier envoi :mad:
Voici ce qui est demandé:
All characters of the ASCII-Code from 32 (0x20) up to 127 (0x7F) are permitted.
A command is terminated with the control character <cr><lf> Carriage Return, Line Feed -> 13,10 (0x0D, 0x0A).

The DISTOTM plus5 also terminates the response with <cr><lf>.

Definition: terminator <trm> = <cr><lf>.

Input
Every command consists of one or more characters and the terminator
Examples:

a<trm>
N00N<trm>
Merci de votre aide....
 
Bloc de code:
- (BOOL)envoiSurDisto:(NSString *) message
{
	NSLog(@"le message en NSString : %@, taille %d, channel MTU = %i",message,[message length],(int)[mChannel getMTU]);
	BOOL ret ;
	unsigned longueur ;
	NSString * caractere = [[message stringByAppendingString:@"\r\n"]retain]; // 
	NSData * Commande = [NSData dataWithData:[caractere dataUsingEncoding:NSASCIIStringEncoding]];
	longueur = [Commande length];
	ret = [mChannel writeSync:[Commande bytes] length:longueur];
	
	NSLog(@"apres writeSync caractere = %@",caractere);
	NSLog(@"Resultat %d",ret);
	[Commande release];
	return ret ;
Les Logs
2008-02-12 12:08:57.927 distotest[1117] le message en NSString : o, taille 1, channel MTU = 667
2008-02-12 12:08:57.935 distotest[1117] apres writeSync caractere = o
2008-02-12 12:08:57.935 distotest[1117] Resultat 0
2008-02-12 12:08:57.935 distotest[1117] Envoi o ca marche !

De cette façon la commande est exécutée, mais ça plante avec le message :
warning : passing argument 1 of 'writeSync:lenght:' discard qualifiers from pointer target type

Pour les fois ou ça a fonctionné a la première commande, a l'envoi de la 2ème j'avais un MTU a Zéro ?
Je ne saisi pas tout, mais je pense qu'on avance...
:hein:
 
Bon déjà, tu pourrais faire simple pour essayer:


Bloc de code:
 - (BOOL)envoiSurDisto:(NSString *) message
{
char chaine[]="On essaye";

[mChannel writeSync:chaine length:sizeof(chaine)];

}


Si ça ne marche pas, alors ça vient d'ailleurs: c'est ton instance mChannel qui est mal configurée.
(toutefois, essaye aussi unsigned char pour le type de chaine[])
 
Cette fois le MTU est a 667 a la deuxième commande.

Sinon c'est pareil j'ai essayé le "o\r\n" qui allume le laser et le "p\r\n" bloque lamentablement.
LE disto reste Actif le problème est donc bien coté mac...
le Channel est paramétré comme ça:

[mChannel setSerialParameters:9600 dataBits:8 parity:kBluetoothRFCOMMParityTypeNoParity stopBits:1];

Par contre sur le COM1 est-ce que ça pourrait être ça ? si oui comment Je change ça ?
 
ok mais il y a un e chose que je n ai pas compris si tu recois une reponse avec des ???
c est que ton BAUD est mauvais, ton laser s allume peut etre avec n importe quelles infos si il est en attente

ta doc est elle open ?

Cette fois le MTU est a 667 a la deuxième commande.

Sinon c'est pareil j'ai essayé le "o\r\n" qui allume le laser et le "p\r\n" bloque lamentablement.
LE disto reste Actif le problème est donc bien coté mac...
le Channel est paramétré comme ça:

[mChannel setSerialParameters:9600 dataBits:8 parity:kBluetoothRFCOMMParityTypeNoParity stopBits:1];

Par contre sur le COM1 est-ce que ça pourrait être ça ? si oui comment Je change ça ?