# Obj-C code hexadecimal d'une string



## obi wan (28 Octobre 2007)

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 :

```
- (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 :

```
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...


----------



## mpergand (29 Octobre 2007)

Salut,

Selon ta description, ça devrait donner ça:


```
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
```


----------



## Céroce (29 Octobre 2007)

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 


```
char message[]={0x08, 0x00, 0x01, 0x86, 0x2A, 0x2E, 0x72, 0x78, 0x65, 0x00};
[RFCOMMchannel writeString:message length:sizeof(message)];
```


----------



## PA5CAL (29 Octobre 2007)

*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.


----------



## obi wan (29 Octobre 2007)

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...


----------



## mpergand (29 Octobre 2007)

> 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:

```
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 ...


----------



## obi wan (29 Octobre 2007)

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 !


----------



## Céroce (30 Octobre 2007)

obi wan a dit:


> 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.



obi wan a dit:


> 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.



obi wan a dit:


> 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.


----------



## obi wan (30 Octobre 2007)

Céroce a dit:


> 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.


----------



## Céroce (31 Octobre 2007)

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:


----------



## obi wan (31 Octobre 2007)

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...  (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  )


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


----------



## Céroce (5 Novembre 2007)

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).


----------



## obi wan (5 Novembre 2007)

Céroce a dit:


> 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.



Yipikai, Objective-C 2.0 a un garbage collector  ... je lirais ton lien quand même pour la culture générale ( :rateau:  ), mais vraiment le garbage collector ça me plait (ça me sauve ?) beaucoup


----------



## Gercofis (8 Février 2008)

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...


```
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:


```
[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 
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>.
> ...


Merci de votre aide....


----------



## Céroce (11 Février 2008)

Je te cite:


```
NSString * caractere = [message stringByAppendingString:@"\r\n"]; // 
    
    ret = [mChannel writeSync:[caractere UTF8String] length:[caractere length]+2];
```

Pourquoi +2 ?
caractere a déjà la taille de message + 2.


----------



## tatouille (12 Février 2008)

le retour "?" ton BAUD est donc mauvais


----------



## Gercofis (12 Février 2008)

```
- (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:


----------



## Céroce (12 Février 2008)

Bon déjà, tu pourrais faire simple pour essayer:



```
- (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[])


----------



## Gercofis (13 Février 2008)

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 ?


----------



## tatouille (13 Février 2008)

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 ? 



Gercofis a dit:


> 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...
> ...


----------



## Gercofis (13 Février 2008)

non non, si tu lis plus haut "?" c'est la réponse OK du laser, vu que c'est une commande dans ne nombreux cas il demande une réponse du Mac


----------

