Comment ça marche une clé Dallas (iButton) ?

4.8
(5)

Vous avez certainement déjà remarqué que les vendeurs ou serveurs utilisent ce type de clé sur leurs caisses enregistreuses. Il suffit de poser la clé Dallas sur son lecteur pour identifier automatiquement le porteur de la clé.

Caisse enregistreuse avec lecteur de clé Dallas

Les clés Dallas sont simplement constituées d’un iButton qui contient un numéro de série unique permettant d’identifier automatiquement son utilisateur. Le iButton communique avec le lecteur de clé Dallas via le bus 1-Wire.

Une clé Dallas avec son iButton

Le bus 1-Wire

1-Wire est un bus de communication conçu par Dallas Semiconductor qui permet de véhiculer des données et une alimentation sur un seul conducteur. Le second conducteur est tout simplement le fil de masse.

L’alimentation du iButton est fournie via le bus 1-Wire par le lecteur de clé Dallas, il n’a donc pas besoin d’intégrer de pile ou de batterie.

Le bus 1-Wire nécessite d’utiliser une résistance de rappel “pull-up” (voir mon article à ce sujet) de 4,7 kΩ.

Le schéma est très simple, il suffit de relier la sortie du lecteur de clé Dallas à la broche 2 de l’Arduino Uno en s’assurant que la résistance de rappel soit reliée au 5V de l’Arduino.

Schéma électrique du lecteur de clé Dallas

iButton

Un iButton (e.g. DS1990A) contient un composant électronique qui stocke dans sa ROM un numéro de série unique et qui communique avec le lecteur de clé Dallas via le bus 1-Wire. Le numéro de série est également gravé sur le iButton.

iButton DS1990A ayant le numéro de série 0001393E0F8

Les iButton existent en deux dimensions (F3 et F5) et nous voyons sur l’image suivante l’emplacement des broches IO (alimentation et échange de données) et GND (masse).

Dimensions d’un iButton et emplacement des broches

La ROM du iButton a une taille de 64 bits (8 octets), elle contient :

  • Un “Family Code” de 1 octet (0x01 pour un iButton)
  • Le numéro de série unique sur 6 octets
  • Le CRC des 7 premiers octets (Family Code + Serial Number) codé sur 1 octet.

Programme Arduino pour lire la ROM d’un iButton

Voici le code Arduino qui permet de lire la ROM du iButton et afficher son numéro de série unique.

/*
  iButton Reader
  
  Created March 2022
  by Tutoduino
*/
 
// For Dallas iButton reader
#include <OneWire.h>
#define PIN 2               // iButton is connected to PIN 2
OneWire iButton(PIN);       
/* Print iButton ROM buffer */
void printBuffer(byte* buf) {
  char serialNumber[16 + 1];  // Printable 8 hex bytes buffer (+1 for '\0') 
  sprintf(serialNumber,
          "%02X%02X%02X%02X%02X%02X",
          buf[6],
          buf[5],
          buf[4],
          buf[3],
          buf[2],
          buf[1]);
          
  Serial.print("Family code: ");
  Serial.print(buf[0], HEX);
  Serial.print(", Serial number: ");
  Serial.print(serialNumber);
  Serial.print(", CRC: ");
  Serial.println(buf[7],HEX);
}
bool checkCrc8(byte* buf) {
  // Compare the received CRC (8-BIT CRC CODE is byte 7 of the buffer)
  // against the computed CRC on the first 7 bytes of the buffer
  byte crc8 = iButton.crc8(buf, 7);
  if (buf[7] != crc8) { 
    Serial.print("Invalid CRC: Received=");
    Serial.print(buf[7],HEX);
    Serial.print(" Expected=");
    Serial.println(crc8, HEX);
    printBuffer(buf);
    return false;
  }
  return true;
}
void readButton(byte* buf) {
  // Send Read ROM [0x33] Function Command to iButton
  iButton.write(0x33);
  // Read the 8 bytes of the ROM
  iButton.read_bytes(buf,8);
  printBuffer(buf);
  // Check of CRC is ok
  if (checkCrc8(buf) == true) {
    // Check if the family code is iButton [0x01]
    if (buf[0] != 0x01) {
      Serial.println("Not iButton family code");
      }
  }   
}
void setup() {
  Serial.begin(115200);
  Serial.println("Put iButton on reader");
  iButton.reset();
}
void loop() {  
  byte oneWireBuffer[8];      // 64-Bit Unique ROM buffer
  
  // Send a reset pulse and check presence pulse
  if ( iButton.reset() != 0) {
    readButton(oneWireBuffer);
  }
  delay(200);
}

Voici ci-dessous l’affichage dans le moniteur série de l’IDE Arduino des numéros de série de 2 iButton différents.

Affichage des informations contenues dans le iButton dans le moniteur série de l’Arduino

Changer le numéro de série d’une clé Dallas réinscriptible

Il est possible de modifier le numéro de série des clés Dallas réinscriptibles (RW1990). Le montage est identique au précédent mais le programme est un peu plus compliqué. En effet la séquence d’écriture des boutons RW1990 ne permet pas d’utiliser la librairie OneWire telle quelle. Je me suis inspiré du code de swiftgeek pour réaliser mon programme.

/*
  iButton Writer
  
  Created March 2022
  by Tutoduino
  Based on https://gist.github.com/swiftgeek/0ccfb7f87918b56b2259
*/
#include <OneWire.h>
#define PIN 2
OneWire iButton (PIN); // I button connected on PIN 2.
void sendLogical0() {
  // Send logical 0
  digitalWrite(PIN, LOW); pinMode(PIN, OUTPUT); delayMicroseconds(60);
  pinMode(PIN, INPUT); digitalWrite(PIN, HIGH); delay(10);  
}
void sendLogical1() {
  digitalWrite(PIN, LOW); pinMode(PIN, OUTPUT); delayMicroseconds(10);
  pinMode(PIN, INPUT); digitalWrite(PIN, HIGH); delay(10);
}
/* Write a byte to iButton ROM */
int writeByte(byte data){
  for(byte data_bit=0; data_bit<8; data_bit++){
    if (data & 1){
      sendLogical0();
    } else {
      sendLogical1();
    }
    data = data >> 1;
  }
  return 0;
}
/* Print iButton ROM buffer */
void printBuffer(byte* buf) {
  char serialNumber[16 + 1];  // Printable 8 hex bytes buffer (+1 for '\0') 
  sprintf(serialNumber,
          "%02X%02X%02X%02X%02X%02X",
          buf[6],
          buf[5],
          buf[4],
          buf[3],
          buf[2],
          buf[1]);
          
  Serial.print("Family code: ");
  Serial.print(buf[0], HEX);
  Serial.print(", Serial number: ");
  Serial.print(serialNumber);
  Serial.print(", CRC: ");
  Serial.println(buf[7],HEX);
}
bool checkCrc8(byte* buf) {
  // Compare the received CRC (8-BIT CRC CODE is byte 7 of the buffer)
  // against the computed CRC on the first 7 bytes of the buffer
  byte crc8 = iButton.crc8(buf, 7);
  if (buf[7] != crc8) { 
    Serial.print("Invalid CRC: Received=");
    Serial.print(buf[7],HEX);
    Serial.print(" Expected=");
    Serial.println(crc8, HEX);
    printBuffer(buf);
    return false;
  } else {
    return true;
  }
}
void setNewBuffer(byte* newBuffer, byte* serialNumber) {
  // Family Code = 0x01 (iButton)
  newBuffer[0] = 0x01;
  // SerialNumber
  memcpy(newBuffer+1, serialNumber, 6);
  // CRC
  newBuffer[7] = iButton.crc8(newBuffer, 7);
}
void readButton(byte *buf) {
  // Send Read ROM [0x33] Function Command to iButton
  iButton.write(0x33);
  // Read the 8 bytes of the ROM
  iButton.read_bytes(buf,8);
  printBuffer(buf);
  // Check of CRC is ok
  if (checkCrc8(buf) == true) {
    // Check if the family code is iButton [0x01]
    if (buf[0] != 0x01) {
      Serial.println("Not iButton family code");
      }
  }   
}
  
void setup(){
 Serial.begin(115200); 
 Serial.println("Put iButton on reader");
}
void loop(){
  byte oneWireBuffer[8];    //array to store the Ibutton ID.
  byte newOneWireBuffer[8]; //array to store the new Ibutton ID.
  byte newSerialNumber[6] = {0xBB, 0xAA, 0xCC, 0x01, 0x00, 0x00};
  // Send a reset pulse and check presence pulse
  if ( iButton.reset() != 0) {
    // Read serial number
    readButton(oneWireBuffer);
    delay(500);
    
    // Set new serial number in new buffer 
    setNewBuffer(newOneWireBuffer, newSerialNumber);
  
    // Check if new serial number if already set
    if (memcmp(oneWireBuffer, newOneWireBuffer, 8) == 0) {
      return;
    }
    
    // Write new serial number
  
    // Prepare to write
    iButton.skip();
    iButton.reset();
    iButton.write(0xD1);
    sendLogical0();
  
    // Write
    Serial.print("  Writing iButton ID:\n    ");
    iButton.skip();
    iButton.reset();
    iButton.write(0xD5);
    for (byte x = 0; x<8; x++){
      delay(10);
      writeByte(newOneWireBuffer[x]);
      Serial.print('*');
    }
    Serial.print('\n');
    iButton.reset();
    iButton.write(0xD1);
    sendLogical1();
  }
} 

Voici ci-dessous l’affichage dans le moniteur série de l’IDE Arduino du changement de numéro de série d’un iButton.

Le numéro de série du iButton a été modifié

Il faut donc noter qu’il est extrêmement facile de dupliquer une clé Dallas, et que ce type de clé n’est pas du tout sécurisé contrairement à ce que certains peuvent affirmer dans leurs arguments de vente. Une clé Dallas permet simplement d’identifier facilement et rapidement un utilisateur…

Attention la clé Dallas ne sécurise pas les accès, contrairement aux arguments mis en avant par certains sites marchands comme ci-dessus !

Avertissement : ce tutoriel est uniquement à but pédagogique et son contenu ne doit pas être utilisé pour des activités illicites !

Merci à GoTronic pour la fourniture du iButton Dallas DS1990A nécessaire à la rédaction de ce tutoriel.

Votre avis compte !

Note moyenne : 4.8 / 5. Nombre de votes : 5

Pas encore de vote pour ce tutoriel

Désolé si cet article ne vous a pas intéressé

Merci de commenter afin que je puisse l’améliorer.

Dites-moi comment améliorer cette page.