Page 1 sur 2

Ecrire une chaîne de caractère dans une zone mémoire

Publié : dim. 30/oct./2016 11:57
par totorcalais
Salut,

Comme je l'écrivais dans mon post sur l'ACR122 (lecteur de carte rfid), je ne suis pas un spécialiste des pointeurs.

J’ouvre ce post distinct car ma demande est un peu générale par rapport à la spécificité des accès au lecteur RFID (même si c'est intimement lié).

Voilà mon problème:

je commence à solutionner les commandes (ADPU) pour lire et écrire dans mon lecteur de cartes.

Lire pas de problème, ça tourne désormais.

C'est écrire qui me pose problème :

En effet, je dois entrer dans une chaîne les commandes en Hexa et dans cette même chaîne le contenu de ce que je veux écrire :

exemple : FFD6000210
jusque là, le programme utilise un pointeur *IN

Code : Tout sélectionner

PokeB(*IN,$ff)
PokeB(*IN+1,$d6)
PokeB(*IN+2,$00)
PokeB(*IN+3,$02)
PokeB(*IN+4,$10)
Mon souci vient du fait que lorsque je veux ajouter une chaîne de caractère derrière cette première partie.
J'obtiens du "chinois"...

Ce que je cherche à faire c'est avoir FFD6000210+"chaîne de 16 octets" à partir d'une même adresse et formant une chaîne que j'injecte ensuite ne commande dans mon lecteur en attendant le retour (soit une erreur soit une chaîne de caractère que je cherche également à lire autrement qu'en caractère chinois).

En effet, j'ai le même problème de conversion lorsque je veux lire cette chaîne écrite (ou toute autre chaîne ASCII) contenue dans le block XX.

Je dois avouer que les pointeurs (et les problèmes de table de conversion) ne sont pas mon fort. J'ai besoin d'une leçon et d'un peu d'aide.

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : dim. 30/oct./2016 12:18
par JohnJohnsonSHERMAN
Si ton programme est compilé en mode Unicode (ce qui est le cas systématiquement dans la derniére version de PB), quand tu essaie d'écrire en mémoire ou d'y lire, il va le faire en Unicode.

Pour écrire en mémoire une chaine en ASCII, il faut utiliser Ascii(ChaineAEcrire$). Comme la fonction Ascii() renvoie un pointeur vers la chaine traduite, on utilise ensuite PeekS pour récupérer cette chaine.
Par exemple :

Code : Tout sélectionner

PokeS(*IN+6,PeekS(Ascii("Hello World")))
Je ne sais pas si j'ai bien répondu a ta demande, puisque les pointeurs et la mémoire c'est pas trop mon truc non plus, mais j'espére que ca t'aidera. :)


Edit : Un petit exemple didactique sur la gestion des chaines en mémoire :

Code : Tout sélectionner

Chaine$ = "Sherman"        ;On met la chaine Sherman dans cette variable
*ptrChaine = @Chaine$      ;On affecte au pointeur l'adresse de la chaine "Sherman"
Debug PeekS(*ptrChaine)    ;On prend cette chaine dans la mémoire et on l'affiche

PokeS(*ptrChaine,"Panzer") ;Maintenant, on écrit "Panzer" à la place.
Debug PeekS(*ptrChaine)    ;Quand on la lit, on obtient bien "Panzer"


*ptrChaine = Ascii("Paris")           ;La fonction Ascii() n'a pas besoin d'une variable, elle renvoie directement l'adresse de la chaine traduite.
Debug PeekS(*ptrChaine)               ;Et là? On a du chinois...
Debug PeekS(*ptrChaine,-1,#PB_Ascii)  ;Cette fois on indique à PeekS() que la chaine est en asciiet ca marche.

PokeS(*ptrChaine,PeekS(Ascii("Tahiti"))) ;Le petit probléme de Ascii() c'est qu'elle renvoie un pointeur. Pour récupérer le texte Ascii, on va le chercher avec PeekS().
Debug PeekS(*ptrChaine,-1,#PB_Ascii)     ;Et là... la chaine lue est bien celle qu'on a écrit en ascii...
Voila, c'est tout ;)

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : dim. 30/oct./2016 18:36
par Fig
Si tu ne veux pas te gourer avec les formats en mémoire et que la vitesse n'est pas cruciale, écris tout octet par octet à chaque adresse et relis de la même façon, comme ça tu es sûr de ce que tu fais. (emploi de l'ascii et pas de l'unicode du coup)
Sinon tu fais des tests jusqu'a ce que tu aies compris ce qui est écrit et dans quel ordre (Little-Endian et Big-Endian)

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : lun. 31/oct./2016 14:37
par totorcalais
merci pour vos réponses.

Je suis toutefois confronté à un petit probleme qui, je pense, pour vous sera très simple.

Toujours avec mes pointeurs, je veux faire une boucle de test où je récupère une valeur de bloc de données (exemple, 0,1,2,3,...,15).

Je fais une boucle qui (en fonction de la valeur obtenue pour le block) :

Le problème que je rencontre est très simple

Je veux convertir la valeur exemple 4 en $04 pour qu'elle puisse rentrer dans ce Poke

PokeB(*IN+3,$valeur)

Comment peut on faire apparaître une variable sur 2(ou voire plus) digits en hexadécimal pour réutilisation avec des pointeurs?

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : lun. 31/oct./2016 15:20
par JohnJohnsonSHERMAN
Il n'y a pas de différence quand tu fais PokeB(*IN,4) ou PokeB(*IN,$04) il me semble.

Code : Tout sélectionner

*ptr = AllocateMemory(1)
PokeB(*ptr,4)
Debug PeekB(*ptr)

PokeB(*ptr,$04)
Debug PeekB(*ptr)

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : lun. 31/oct./2016 15:33
par Mesa
En effet, comme le dit sherman, pokeB réclame un byte, quelque soit sa forme:

Code : Tout sélectionner

*MemoireID = AllocateMemory(10)
; Rappel 65 en décimal = $41 en hexadecimal = %1000001 en binaire = 'A' en ASCII
Byte.b=65;Représente 1 octet signé de -128 à +127. 

If *MemoireID; PokeB réclame un Byte quelque soit sa forme
  PokeB(*MemoireID, 65)       ; 65 en mémoire ou 41 en hexadecimal
  PokeB(*MemoireID + 1, $41)  ; 65 en mémoire ou 41 en hexadecimal
  PokeB(*MemoireID + 2, %1000001); 65 en mémoire ou 41 en hexadecimal
  PokeB(*MemoireID + 3, Byte)    ; 65 en mémoire ou 41 en hexadecimal
  PokeB(*MemoireID + 4, Val(Hex(Byte,#PB_Byte))); 41 en mémoire ou 29 en hexadecimal
  PokeB(*MemoireID + 5, Val(Bin(Byte,#PB_Byte))); 65 en mémoire ou 41 en hexadecimal
  PokeB(*MemoireID + 6, 'A')  ; 65 en mémoire ou 41 en hexadecimal
  ShowMemoryViewer(*MemoireID, MemorySize(*MemoireID)) ; Affiche l'adresse du tampon suivi de 41 41 41 41 29 41 41
  
  For i=0 To 6
    Debug PeekB(*MemoireID+i)   
  Next i  
  FreeMemory(*MemoireID)  
Else
  Debug "Impossible d'allouer la mémoire demandée !"
EndIf

Mesa.

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mar. 01/nov./2016 18:54
par totorcalais
Merci pour ton aide toutefois ma demande est un peu plus compliquée en ce sens que j'ai besoin de mettre une chaine ASCII en mémoire et la récupérer par un pointeur.

Exemple : Je veux mettre cette chaine dans une zone mémoire pointée sur valeur, l'utiliser et la relire.

Sur ce point, la doc donne ceci :

Code : Tout sélectionner

Texte$ = "Bonjour"
  *Texte = @Texte$ ;*Texte a pour valeur l'adresse où réside la chaîne de caractères en mémoire
  *Pointeur.String = @*Texte ; *Pointeur pointe sur *Texte
  Debug *Pointeur\s ; Lit la chaîne de caractères qui réside à l'adresse écrite en *Pointeur (c-a-d @Texte$)
J'essaie cela (avec mes variables) et cela ne fonctionne pas. Quelqu'un pourrait m'aider?

Code : Tout sélectionner

*IN = AllocateMemory(1000)


If *IN
  essai$="ceci est un essai"

  *essai = @essai$ 
  *IN=@*essai      
  ShowMemoryViewer(*IN, 16) 

  Debug PeekS(*IN,-1,#PB_Ascii)   

  FreeMemory(*IN)  
Else
  Debug "Impossible d'allouer la mémoire demandée !"
EndIf
le débogueur me donne dans le visualiseur mémoire : 004341CC D8 05 35 02 08 00 00 00 08 07 1C 02 01 00 00 00 Ø.5.............

Bref ce charabia:
Ø5
Où est ce que cela coince?

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mar. 01/nov./2016 21:21
par Zorro
ben MOA, j'frais comme ça :Image

Code : Tout sélectionner

*IN = AllocateMemory(1000) ; on creer un espace Ram


If *IN
		essai$="ceci est un essai" ; on initialise la variable chaine
		*ess= ascii(essai$)
		pokeS(*IN,peekS(*ess))    ; on pose dans l'espace memoire le contenue de la variable chaine      
		
		ShowMemoryViewer(*IN, 17) ; on montre le resultat du poke() (poke on ecrit dans un espace memoire, alors que Peek , on lit l'espace memoire )
		
		For i=0 to len( essai$)-1
				a=PeekA(*IN+i)  ; je lis le contenu de l'espace memoire
				sortie$=sortie$+chr(a)
		Next i
		debug sortie$
		FreeMemory(*IN)  ; on libere l'espace memoire
Else
		Debug "Impossible d'allouer la mémoire demandée !"
EndIf










Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mar. 01/nov./2016 22:30
par Ollivier
@ToutOuRien

Ton écriture tampon semble bonne. C'est ta vérif avec Debug (ou n'importe quoi d'autre) qui n'est pas bonne.

Pour vérifier (ou relire), il faut dumper (ça se prononce "deume pé" !)

Code : Tout sélectionner

Procedure.S DumpGet(*A, S)
Define Dump$
For i = 0 To (S - 1)
Char = PeekA(*A + i)
If Char
Char$ = Chr(Char)
Else
Char$ = CharFault$
EndIf
Dump$ + Char$
Next
ProcedureReturn Dump$
EndProcedure
Dumper, ça consiste à lire un tampon mémoire en tant que chaîne possible et en tant qu'ensemble de caractères, en ayant une priorité de lecture basée sur la taille tampon et non sur un quelconque code de fin de chaîne usuel (Chr(0) est ignoré et remplacé par un point.

Teste

Code : Tout sélectionner

Debug DumpGet(*Address, 10)
...pour lire les 10 caractères ASCII localisés à *Address.


Pour le charabia de départ, c'est normal puisque tu as enregistré un charabia qui précède ta chaîne "lisible".

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mer. 02/nov./2016 0:26
par totorcalais
Merci.

Mais je rencontre toujours un écueil car maintenant que l'on arrive à mettre de l'ASCII en mémoire pointée, le problème auquel je suis confronté réside en celui-ci:

Je dois mettre une chaîne de commande (ADPU) comme tel

Byte1 byte2 byte3 byte4 byte5 _________ byte6 .....ByteX
données définies en HEXA-----------|-------- datas à transmettre (ASCII)

Je dois remplir mon pointeur IN avec tout ça.

Je fais donc
PokeB(*IN,$FF)
PokeB(*IN+1,$D6)
PokeB(*IN+2,$00)
PokeB(*IN+3,Byte)
PokeB(*IN+4,$10)
pour les commandes définies (byte étant une valeur récupérée par ailleurs)
et je dois compléter avec une chaîne de 16 caractères.

1. Si je fais des pokeb à la suite, cela s'inscrit bien et apparaît dans la chaine finale (et je peux retrouver ce qui est écrit en lecteur en retour)

2. Si je mets une chaîne à IN+5, ça met un point entre chaque caractère et ça passe pas (le pokeS est il a l'origine de cela?).

A moins de décomposer une chaine ascII en 1 caractère que je pokeB l'un après l'autre (et là, j'ai beau chercher, je ne trouve pas de commandes aisées pour ce faire (j'ai bien une idée mais elle me semble fastidieuse à coup de lset)).

Qu'en pensez vous?

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mer. 02/nov./2016 10:03
par Zorro
totorcalais a écrit : A moins de décomposer une chaine ascII en 1 caractère que je pokeB l'un après l'autre (et là, j'ai beau chercher, je ne trouve pas de commandes aisées pour ce faire (j'ai bien une idée mais elle me semble fastidieuse à coup de lset)).

Qu'en pensez vous?
pfffff. je dois reconnaitre, que je ne saisi pas vraiment ce que tu veux .....

mais je réagit a ta reflexion citée ci dessus !


en Pure basic, travailler avec des chaines, c'est super simple !
deja , il serai peut etre bien, que tu lise la Doc de Purebasic !! (Touche F1 lorsque tu est dans l'editeur )
je te precise ça , car dans la Doc , tu as une partie consacré a la librairie "String"

et dedans , tu aurai trouvé la fonction "StringField() "
cette fonction permet d'extraire ce que tu veux d'une chaine séparé par un caractere

tu aurai trouvé la fonction Mid() , un standard du Basic , qui permet d'extraire une chaine dans une chaine
a n'importe quelle position , et de n'importe qu'elle taille


autre chose, pour finir, l'hexadecimal en Purebasic c'est une Chaine de caractere !!!

donc puisque tu tiens a travailler en Hexa, alors, reste en mode String() , utilise PokeS() et PeekS()
comme ça tu restes dans la meme reference (le String)


si tu commences a melanger les valeurs de l'hexa (avec PokeB() ou PeekB() , et le mode String (PeekS) , tu risques de galerer
soit tu passes tout en numérique (donc avec les PokeB() PeekB() etc .. et la conversion de Hexa$ en numerique (decimal par ex)

soit tu restes en mode String, et tu prepares ta chaine a envoyer (tout en String) avec les fonctions qi vont bien (mid() ,Left(),Right() , ReverseString() StringField() etc ... , avant de l'envoyer


perso je prendrai la deuxieme solution , car meme si le mode String est réputé plus lent
c'est quand meme vachement plus "humain" :)


Code : Tout sélectionner

chaine$="Zorro est arrivé" ; notre chaine

For i=1 to len(chaine$)
		car$=mid(chaine$,i,1) ; on isole chaque caractere de la chaine
		ascii=asc(car$) ; on recup le code ascii de chaque caractere
		Debug "le code ascii de :"+car$+" c'est :"+str(ascii) +" soit en hexa: "+hex(ascii) ; on affiche la ligne qui donne le caractere + son code ascii
		hexa_cumule$=hexa_cumule$+" "+hex(ascii) ; ici on cumule dans une chaine les codes ascii trouvé séparé par un espace
Next i

debug "voici ta chaine en hexa cumulé" +hexa_cumule$ ; <<<--- ceci prouve que l'hexa c'est en fait un string

debug "voici le 5em em code hexa de la chaine cumulé :" +StringField(trim(hexa_cumule$),5," ")

debug ""
debug ""
; et si toutefois, tu veux utiliser les valeur de ces codes ascii 
For i=1 to countstring(Trim(hexa_cumule$)," ")+1 ; je compte le nombre d'espace dans la chaine cumulé
		car$ =StringField(trim(hexa_cumule$),i," ")		; je recup chaque sous-chaine se trouvant entre les espaces
		code=val("$"+car$) ; je transforme la sous chaine recupéré en valeur Decimale , et je colle ça dans la vairable "Code"
		debug "le caractere :"+chr(code)+"  en decimal :"+str(code)+" en binaire :"+bin(code) +" et encore en hexa string : "+hex(code) 		; plus qu'a afficher (ou envoyer ) comme on veux !
Next i

comme tu peux voir, passer d'une string a sa correspondance numérique, n'est vraiment pas compliqué
perso ,j'aime bien manipuler les chaines, parcequ'en Purebasic, c'est quand meme vachement simple !

apres, tu peux extraire ce que tu veux, et en faire une valeur numérique

le truc a savoir c'est que pour convertire de l'hexa en sa valeur numérique, il faut ajouter le caractere "$"

exemple :

Code : Tout sélectionner

car_hexa$="FF"

en_decimal=Val("$"+car_hexa$); <<<<< le caractere "$" a pour effet que Purebasic considere la variable car_hexa$ comme etant de l'hexa !
debug  en_decimal ; 255 en principe
pareil pour le binaire , le transformer en decimal , il faut ajouter le caractere "%"

Code : Tout sélectionner

car_binaire$="11111111"

en_decimal=Val("%"+car_binaire$) ; <<<<< le caractere "%" a pour effet que Purebasic considere la variable car_binaire$ comme etant du binaire !
debug  en_decimal ; 255 en principe

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mer. 02/nov./2016 11:23
par Mesa
2. Si je mets une chaîne à IN+5, ça met un point entre chaque caractère et ça passe pas (le pokeS est il a l'origine de cela?).
Attention avec pb550, les chaînes sont créées en Unicode par défaut pas en ascii. Dans le code de zorro, on voit bien les "00" qui traînent partout. 'c' a pour code 6300 (en fait c'est 0063) en unicode et 63 en ascii.

Il faut donc transformer la chaîne en ascii avec la fonction ascii()

Code : Tout sélectionner

*IN = AllocateMemory(1000)


If *IN
  essai$="AAA AAA AAA AAAB" ; en unicode par défaut avec pb550
  
  *essai = Ascii(essai$) ; elle est en ascii maintenant
  *IN=*essai      
  ShowMemoryViewer(*IN, 16) 
  
  Debug PeekS(*IN,-1,#PB_Ascii)   
  
  FreeMemory(*IN)  
Else
  Debug "Impossible d'allouer la mémoire demandée !"
EndIf

;==================ON PEUT SIMPLIFIER

essai$="AAA AAA AAA AAAB" ; en unicode par défaut avec pb550
*essai = Ascii(essai$) ; elle est en ascii maintenant

ShowMemoryViewer(*essai, 16) 
Debug PeekS(*essai,-1,#PB_Ascii)   

FreeMemory(*essai)  
Mesa.

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mer. 02/nov./2016 11:36
par Marc56
Si tu veux absolument utiliser l’accès direct à la mémoire et lire/écrire de l'ascii, autant utiliser PeekA() et PokeA()
(Relire la doc sur memory plutôt que de faire des déductions à partir de codes de forums vieux de plus de 10 ans)

Ne pas oublier aussi que l'utilisation de chaine directe PeekS() PokeS() considère que les chaines sont à zéro terminal (pas le chiffre '0', mais le code ascii zéro (Chr(0) ou #NULL))
Si la chaine n'a pas été initialisée correctement ou terminée par #Null et que la lecture se fait en continu (sans limite de taille), le programme va lire tout ce qu'il trouve de contigu en mémoire jusqu'à trouver un #NULL et ça peut faire des choses bizarres :roll:

Je sais pas si j'exprime bien :|

Mais comme conseille Zorro, utilises plutôt les fonctions standard de la bibliothèque String
Les accès direct en ram (peek, poke) c'est utile quand on on a des temps critiques ou une masse de donnée importante, là: non (à moins que la doc du lecteur le demande)

:wink:

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mer. 02/nov./2016 11:43
par Zorro
Mesa a écrit : Dans le code de zorro, on voit bien les "00" qui traînent partout. 'c' a pour code 6300 (en fait c'est 0063) en unicode et 63 en ascii.

plus maintenant, j'ai corrigé :)
j'ai fait le premier exemple pour montrer comment on pose une string dans un buffer
le fait qu'il veuille de l'ascii , franchement, je n'y ai meme pas pensé ,mais c'est corrigé maintenant !

dans mon deuxieme exemple, le probleme ne se pose plus de toute façons

Re: Ecrire une chaîne de caractère dans une zone mémoire

Publié : mer. 02/nov./2016 14:36
par totorcalais
Tout d'abord, merci à tous pour le temps passé sur mes questions.

En effet, perdu dans ma problématique multiple : Commande ADPU erronée ou problème de chaîne de caractère en unicode (illisible pour mon besoin)? J'en ai oublié de revoir les fondamentaux. Les types de données et les string (le pire est que je joue bcp avec ceux-ci sauf que là, aveuglé par le dysfonctionnement dont j'avais du mal à analyser la réelle cause, je n'avais même pas vu l'intérêt du Mid().

Un grand merci pour ce recyclage nécessaire (cela faisait plus d'un an que je n'avais pas codé en purebasic)... :oops:

C'est comme se remettre au vélo en oubliant de vérifier les serrages, c'est sur qu'on peut perdre une roue ;)

Ouf, j'ai été secondé par d'excellents "mécanos" avant tout "accident". Merci pour votre temps ;)

Je vais donc m'atteler à cette tâche d'écriture dans cette SmartCard RFID et, une fois cela fait, je vais pouvoir m'attaquer au gros du paquet (mon véritable projet).


EDIT : Grace à la technique du mid de Zorro, et l'utilisation du Pokeb, j'ai pu créer une chaîne homogène bien comprise par le lecteur comme une commande ADPU complète. J'ai ainsi pu donc écrire dans le lecteur avec une chaine de caractère dans un bloc et relire ensuite. Tout cela grâce à vous, encore merci.