Partie 2: Lecture de notre carte à puce

Sommaire
Partie 1: Création d'un boite de dialogue
Partie 2: Lecture de notre carte à puce

Lecture de notre carte à puce

Voici le circuit pour lire les données de la puce. La petite animation vous montre les données que le programme doit définir et la réponse de puce. Remarquez que le port parallèle et la puce sont compatibles TTL. Cela signifie qu'un bit 0=0V et 1=+5V. Donc pas besoins de composants.

Download Flash and ShockWave

Il faut dans l'ordre:

  1. Récupérer les informations entrées dans la boite de dialogue.
  2. Lire la puce et enregistrer ses données.
  3. Interpréter les données pour en tirer des informations.
  4. Afficher ces informations dans la boite de dialogue.

Nous commençons par déclarer toutes nos variables. Comme il n'existe pas de CString ou autre classe/variable pour gérer facilement les chaînes, il s'agit de gérer ça sois même. On prévois donc un buffer pour enregistrer les données de la puce brute (binaire), et un pour les enregistrer en texte formaté. Les cartes téléphone nouvelles (T2G) contiennent 512 bits soit 64 octets.

bool	bData[512];		// 512 bits, soit la taille de la mémoire d'un T2G
char	lzDataText[600];	// On prévois plus de 512 pour les espaces etc.

ATTENTION: Si vous prévoyez un buffer pour le texte, n'oubliez jamais qu'il doit y avoir un caractère vide à la fin.

Pour récupérer l'adresse physique du port ainsi que le bit à modifier pour accéder aux données voulues j'ai créé une petite fonction. Elle donne pour un texte (ex: "D1") le port et le bit à modifier: GetPortAndBit(...). Cette fonction va comparer deux chaînes de caractère à l'aide de la fonction stricmp(a,b) qui compare sans prendre en compte la case. Je vous invite à voir le code source complet pour cette fonction.

Toutes données en main, il faut s'occuper de gérer le port parallèle pour envoyer et recevoir les données de la puce. La fonction _outp(port, valeur) permet d'écrire à un port donnée une série de 8 bits. Il nous faudra donc modifier souvent que un bit et laisser les 7 autres bits intact (cf.: Cours sur les système numériques). De même _inp(port) revois la valeur des 8 bits de ce port.

On comment par tout mettre à 0, pas de courant nulle part. Si on met à 1 l'un des bits, l'une des broches du port parallèle aura un potentiel de +5V par rapport à la masse (cf: PC-Team, cours sur le port parallèle, ...).

// Initiatise
GetPort(sPortDonnees);	// Va récupérer l'adresse du port parallèle
_outp(sPortDonnees, 0x00);	// 0x00 (hexadécimal) = 0 (décimal)

Si une alimentation de la puce par le port parallèle est demandée, nous mettons le bit correspondant à 1.

// Alimentation
if (sPortVcc)
	_outp(sPortVcc, _inp(sPortVcc) | cBitVcc);
if (sPortVpp)
	_outp(sPortVpp, _inp(sPortVpp) | cBitVpp);
Sleep(20);	// Attend 20 ms

Bits initialisés à 0, puce alimentée, voila reste à initialiser le pointeur interne de la puce pour lire tout ce qu'elle contient depuis le début. Il donc faut dire à la puce que nous voulons faire un reset (du pointeur pas de la mémoire). Pour cela mettre le bit "Reset/Up" (qui correspond à une branche de la puce) à 0. En effet "Reset/Up" signifit: bit à 0 fait un reset, bit à 1 fait "Up", soit un déplacement du pointeur d'un cran. C'est déjà fait. Ensuite il faut dire à la puce d'agir. Pour cela il faut mettre la branche "Clock" (ou "Horloge") de 0 à 1. Le passage de 1 à 0 ne fait rien du tout.

// Reset le pointeur
_outp(sPortClk, _inp(sPortClk) | cBitClk);		// Clock 1 -> Reset pointer
_outp(sPortClk, _inp(sPortClk) & ~cBitClk);		// Clock 0
// Reset 1 -> Déplace le pointeur au prochain clock up
_outp(sPortReset, _inp(sPortReset) | cBitReset);	// Reset 1

Il nous reste plus qu'à lire les données. Le bit de reset/up est placé à 1 donc dès que nous faisons un passage de Clock 0 à 1, nous lirons le bit suivant sur la branche du port parallèle branchée à R/W (I/O permet de dire si nous voulons lire ou écrire).

for (i=0; i<512; i++)
{
	// Lis les données
	if (_inp(sPortES) & cBitES)
		bData[i] = false;
	else
		bData[i] = true;

	// Déplace le pointeur
	_outp(sPortClk, _inp(sPortClk) | cBitClk); // Clock 1
	_outp(sPortClk, _inp(sPortClk) & ~cBitClk); // Clock 0
}

Cette fonction de base doit être améliorée pour mettre les données en texte. Texte qui doit avoir un espace tous les 8 bits et des retours à la ligne tous les 8 octets (64 bits).

// Lis toutes les données
nBits = 0;
nOctets = 0;
nDataText = 0;
for (i=0; i<512; i++)
{
	// Lis les données
	if (_inp(sPortES) & cBitES)
	{
		lzDataText[nDataText++] = '0';
		bData[i] = false;
	}
	else
	{
		lzDataText[nDataText++] = '1';
		bData[i] = true;
	}

	// Met un peu en forme les données
	nBits++;	// Nombre de bits dans le bloc actuel
	if (nBits == 8)	// 8 bits par bloc
	{
		nBits = 0;	// Nouveau bloc, avec donc 0 bits
		nOctets++;	// Un octet de plus
		lzDataText[nDataText++] = ' ';	// Ajoute un espace
	}
	if (nOctets == 8)	// 8 octects par ligne
	{
		nOctets = 0;	// Nouvelle ligne, avec donc 0 octects
		lzDataText[nDataText++] = '\r';	// Place un saut de line (1)
		lzDataText[nDataText++] = '\n';	// Place un saut de line (2)
	}

	// Déplace le pointeur
	_outp(sPortClk, _inp(sPortClk) | cBitClk);	// Clock 1
	_outp(sPortClk, _inp(sPortClk) & ~cBitClk);	// Clock 0
}

REMARQUE: Nous ne nous préoccupons pas du format de la puce ici. Même si la T1G ne contient que 256 bits, elle renverra 2 fois les même données dans les 512 bits lus. Ainsi nous testons d'ailleurs après le format de la carte.

Un fois les données lues et le type de carte récupéré, nous affichons déjà ces premières informations.

// Affiche les données brutes
SetDlgItemText(g_hDlg, IDC_DATA_EDIT, lzDataText);

// Version
if (bT2G)
	SetDlgItemText(g_hDlg, IDC_VERSION_EDIT, "T2G");
else
	SetDlgItemText(g_hDlg, IDC_VERSION_EDIT, "T1G");

Il nous faut convertir une série de bits d'une base en une autre. Binaire, décimal, hexadécimal, octal, sont des bases. Par exemple 110 en binaire (base 2) se calcule: 1x2^2 + 1x2^1 + 0x2^0 = 6. En octal (base 8) 123 se calcule: 1x8^2 + 2x8^1 + 3x8^0 = 83. (Le symbole ^ veut dire "puissance").

// Conversion binaire en décimal
nPuissance = 1;
for (i=63; i>=52; i--)
{
	if (bData[i])
		nUnitTotal += nPuissance;
	nPuissance *= 2;
}

Un peu plus loin dans le code source vous remarquerez une conversion d'octal en décimal pour les unités utilisées. Il reste donc nUnitésRestantes = nUnitésTotales - nUnitésUtilisées. Pour transformer notre valeur numérique en chaîne nous utiliserons sprint(...). Nous affichons les dernières informations et nous avons le contenu de notre puce. Et nous voila avec les informations de cette petite merveille.

ATTENTION: Ne pas oublier de d'inclure les headers des fonctions utilisées: "#include // sprintf(...)" et "#include // _inp(..) _outp(...)".

Je remercies Anthony Rabine pour son article dans PC-Team.

J'espère que aurez apprécié cet mini application. Je vous conseil de regarde le code source complet qui est commenté. Les parties du code source ici présentées ont été parfois un peu raccourcis par rapport au code complet. Vous remarquerez que certains fonctionnalités n'ont pas été implémentées. Ainsi la fonction de détection d'insertion. Vous avez du pain sur la planche.

Open Source

Code source sur GitHub

Parties : Précédente1, 2