I2L 2025 Groupe8

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche

Proposition de système (étudiants)

Notre projet consiste à mettre en place un système d’authentification pour une application utilisant un badge électronique NFC. L’objectif est de permettre à un utilisateur de se connecter rapidement et de manière sécurisée sans saisir de mot de passe. L’utilisateur présente son badge au lecteur, si l’identification est valide, l’application se débloque et une LED verte ou un message indique le succès, si l’identification est invalide, l’accès est refusé et une LED rouge ou un message indique l’échec. Chaque tentative peut être enregistrée pour un suivi des accès.

Contre-proposition (intervenant)

Proposez un mode autonome et un mode connecté via USB. Le lecteur NFC PN532 semble pouvoir fonctionner en 3.3V (avec la batterie) ou en 5V (connexion USB).

En mode autonome, vous pouvez par exemple afficher des informations sur la carte ou le badge identifié. En mode connecté vous pouvez effectivement débloquer une application. L'application communiquera avec la carte via la classe USB "vendeur" (spécifique). Il suffit d'une interruption IN pour savoir si une carte a été identifiée.

Une bibliothèque C pour gérer un lecteur PN532 semble disponible [1].

Une bibliothèque pour gérer le contrôleur graphique SDD1306 est aussi disponible [2].

Proposition définitive (étudiants)

Mise en place d’un système d’authentification pour une application reposant sur l’utilisation d’un badge électronique NFC.

Après le scan du badge, l’utilisateur accède à un menu permettant :

  • d’authentifier et de déverrouiller l’application,
  • d’écrire ou de mettre à jour les informations stockées sur le badge.
  • de lire les données présentes sur le badge (nom, prénom, mot de passe, etc.),

L’application propose deux modes de fonctionnement :

  • un mode autonome,
  • un mode connecté via USB.

Une interface dédiée est également disponible pour les besoins de test et de validation du système.

Répartition du travail (étudiants)

Concernant la répartition des tâches, l’un a travaillé sur le mode autonome tandis que l’autre s’est concentré sur le mode connecté via USB. Toutefois, nous avons constamment collaboré et nous nous sommes mutuellement aidés tout au long du projet.

Carte

Schéma initial (étudiants)

Schéma de la carte

Carte routée (intervenant)

Vous utiliserez la carte avec l'écran OLED. Vous avez deux exemplaires de la carte suivant que vous souhaitez utiliser une connexion I2C ou série avec le lecteur NFC.

Composants (intervenant)

Carte réalisée (intervenant)

Photo de la carte

La carte est entiérement soudée. Eventuellement vous pouvez demander l'ajout d'un buzzer.

Travaux (étudiants)

Carte au 13/10/2025

Voici ce qu'on a pu tester :

- Clignotement des LEDs avec des boutons respectifs

- Mise en place de l'horloge (1000ms)

Carte au 16/10/2025

Voici ce qu'on a pu tester :

- Test de l'écran OLED : problème avec l'écran

- Test du NFC I2C en cours

- Test du NFC SPI en cours

Carte au 13/11/2025

- Écran OLED

On a créé une librairie SSD1306 (inspirée d'une déjà existante) pour faire fonctionner notre écran avec le microcontrôleur.

- Mode autonome

On a réussi à communiquer le microcontrôleur avec le NFC via I2C, pour cela, on a créé une librairie PN532 (inspirée d'une déjà existante).

- Mode connecté USB

On a réussi à transformer le microcontrôleur en périphérique USB en utilisant LUFA. Alors, on a pu échanger des données de notre microcontrôleur vers le PC et a pu débloqué le site facilement.

On a réussi à écrire sur la carte (badge) pour stocker des informations.

- Remarque :

Pour le badge (bleu), on a constaté qu'il faudrait avoir une certaine distance pour que ça fonctionne, et le blanc (petit rectangle) il faut coller directement sur le lecteur NFC.

Extraits significatifs de code (étudiants)

1. Mode autonome

Ce mode permet d'utiliser le lecteur NFC de manière indépendante. Grâce à un menu interactif sur l'écran OLED, l'utilisateur peut lire et visualiser les informations des badges (UID, nom, prénom) directement sur le boîtier, sans nécessiter de connexion à un ordinateur.


b) Librairie PN532

Cette nouvelle librairie PN532 permet d’assurer un fonctionnement fiable du module NFC en utilisant le protocole de communication I2C, et de lire correctement les données contenues dans le badge.

Les principaux objectifs de cette adaptation étaient :

  • garantir une communication I2C stable avec le PN532,
  • assurer une lecture fiable des éléments du badge,
  • simplifier l’intégration avec le microcontrôleur,
  • mieux maîtriser les échanges bas niveau avec le module NFC.
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#ifndef PN532_LIB_ATMEGA32U4_PN532_H
#define PN532_LIB_ATMEGA32U4_PN532_H


#define MIFARE_UID_MAX_LENGTH               MIFARE_UID_TRIPLE_LENGTH
#define MIFARE_UID_TRIPLE_LENGTH            (10)
#define MIFARE_CMD_AUTH_A                   (0x60)
#define MIFARE_CMD_AUTH_B                   (0x61)
#define MIFARE_CMD_READ                     (0x30)
#define MIFARE_CMD_WRITE                    (0xA0)
#define MIFARE_CMD_TRANSFER                 (0xB0)
#define MIFARE_CMD_DECREMENT                (0xC0)
#define MIFARE_CMD_INCREMENT                (0xC1)
#define MIFARE_CMD_STORE                    (0xC2)
#define MIFARE_ULTRALIGHT_CMD_WRITE         (0xA2)
#define MIFARE_UID_SINGLE_LENGTH            (4)
#define MIFARE_UID_DOUBLE_LENGTH            (7)
#define MIFARE_KEY_LENGTH                   (6)
#define MIFARE_BLOCK_LENGTH                 (16)


#define PN532_COMMAND_READGPIO              (0x0C)
#define PN532_COMMAND_WRITEGPIO             (0x0E)
#define PN532_COMMAND_INDATAEXCHANGE        (0x40)
#define PN532_COMMAND_DIAGNOSE              (0x00)
#define PN532_COMMAND_GETFIRMWAREVERSION    (0x02)
#define PN532_COMMAND_GETGENERALSTATUS      (0x04)
#define PN532_COMMAND_READREGISTER          (0x06)
#define PN532_COMMAND_WRITEREGISTER         (0x08)
#define PN532_COMMAND_SETSERIALBAUDRATE     (0x10)
#define PN532_COMMAND_SETPARAMETERS         (0x12)
#define PN532_COMMAND_SAMCONFIGURATION      (0x14)
#define PN532_COMMAND_POWERDOWN             (0x16)
#define PN532_COMMAND_RFCONFIGURATION       (0x32)
#define PN532_COMMAND_RFREGULATIONTEST      (0x58)
#define PN532_COMMAND_INJUMPFORDEP          (0x56)
#define PN532_COMMAND_INJUMPFORPSL          (0x46)
#define PN532_COMMAND_INLISTPASSIVETARGET   (0x4A)
#define PN532_COMMAND_INATR                 (0x50)
#define PN532_COMMAND_INPSL                 (0x4E)
#define PN532_COMMAND_INCOMMUNICATETHRU     (0x42)
#define PN532_COMMAND_INDESELECT            (0x44)
#define PN532_COMMAND_INRELEASE             (0x52)
#define PN532_COMMAND_INSELECT              (0x54)
#define PN532_COMMAND_INAUTOPOLL            (0x60)
#define PN532_COMMAND_TGINITASTARGET        (0x8C)
#define PN532_COMMAND_TGSETGENERALBYTES     (0x92)
#define PN532_COMMAND_TGGETDATA             (0x86)
#define PN532_COMMAND_TGSETDATA             (0x8E)
#define PN532_COMMAND_TGSETMETADATA         (0x94)
#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88)
#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90)
#define PN532_COMMAND_TGGETTARGETSTATUS     (0x8A)
#define PN532_PREAMBLE                      (0x00)
#define PN532_STARTCODE1                    (0x00)
#define PN532_STARTCODE2                    (0xFF)
#define PN532_POSTAMBLE                     (0x00)
#define PN532_HOSTTOPN532                   (0xD4)
#define PN532_PN532TOHOST                   (0xD5)
#define PN532_ERROR_NONE                                                (0x00)


#define NTAG2XX_BLOCK_LENGTH                (4)


/* Define */
#define PN532_MIFARE_ISO14443A              (0x00)
#define PN532_STATUS_ERROR                                              (-1)
#define PN532_STATUS_OK                                                 (0)


typedef struct _PN532 {
    int (*reset)(void);
    int (*read_data)(uint8_t* data, uint16_t count);
    int (*write_data)(uint8_t *data, uint16_t count);
    bool (*wait_ready)(uint32_t timeout);
    int (*wakeup)(void);
    void (*log)(const char* log);
} PN532;

int PN532_WriteFrame(PN532* pn532, uint8_t* data, uint16_t length);
int PN532_ReadFrame(PN532* pn532, uint8_t* buff, uint16_t length);
int PN532_CallFunction(PN532* pn532, uint8_t command, uint8_t* response, uint16_t response_length, uint8_t* params, uint16_t params_length, uint32_t timeout);
int PN532_GetFirmwareVersion(PN532* pn532, uint8_t* version);
int PN532_SamConfiguration(PN532* pn532);
int PN532_ReadPassiveTarget(PN532* pn532, uint8_t* response, uint8_t card_baud, uint32_t timeout);
int PN532_MifareClassicAuthenticateBlock(PN532* pn532, uint8_t* uid, uint8_t uid_length, uint16_t block_number, uint16_t key_number, uint8_t* key);
int PN532_MifareClassicReadBlock(PN532* pn532, uint8_t* response, uint16_t block_number);
int PN532_MifareClassicWriteBlock(PN532* pn532, uint8_t* data, uint16_t block_number);
int PN532_Ntag2xxReadBlock(PN532* pn532, uint8_t* response, uint16_t block_number);
int PN532_Ntag2xxWriteBlock(PN532* pn532, uint8_t* data, uint16_t block_number);
int PN532_ReadGpio(PN532* pn532, uint8_t* pins_state);
bool PN532_ReadGpioP(PN532* pn532, uint8_t pin_number);
bool PN532_ReadGpioI(PN532* pn532, uint8_t pin_number);
int PN532_WriteGpio(PN532* pn532, uint8_t* pins_state);
int PN532_WriteGpioP(PN532* pn532, uint8_t pin_number, bool pin_state);


#endif //PN532_LIB_ATMEGA32U4_PN532_H

2. Mode connecté USB

On propose aussi un mode connecté USB sur PC pour pouvoir gérer les informations présentes sur le badge :

a) Communication avec le périphérique USB : libusb

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <libusb-1.0/libusb.h>

#define VENDOR_ID  0x4242
#define PRODUCT_ID 0x0001

#define EP_OUT 0x02   // MYOUT_EPADDR (OUT)
#define EP_IN  0x81   // MYIN_EPADDR  (IN)
#define EP_SIZE 8     // Taille des endpoints
#define TIMEOUT 100  // Timeout en ms
#define TIMEOUT 100  // Timeout en ms

int main(void)
{
    libusb_context *ctx = NULL;
    libusb_device_handle *dev_handle = NULL;
    int r;

    // Initialisation libusb
    r = libusb_init(&ctx);
    if (r < 0) {
        fprintf(stderr, "Erreur libusb_init: %d\n", r);
        return 1;
    }

    // Ouvrir le périphérique LUFA
    dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID);
    if (!dev_handle) {
        fprintf(stderr, "LUFA non trouvé\n");
        libusb_exit(ctx);
        return 1;
    }

    // Détacher driver kernel si attaché
    if (libusb_kernel_driver_active(dev_handle, 0))
        libusb_detach_kernel_driver(dev_handle, 0);

    // Claim de l'interface
    r = libusb_claim_interface(dev_handle, 0);
    if (r != 0) {
        fprintf(stderr, "Impossible de claim l'interface: %d\n", r);
        libusb_close(dev_handle);
        libusb_exit(ctx);
        return 1;
    }

    printf("=== Monitoring USB ===\n");
    printf("Appuyez sur Ctrl+C pour arrêter\n\n");

    // Boucle de monitoring continu
    while (1) {
        unsigned char in_msg[EP_SIZE] = {0};
        int transferred;
        r = libusb_interrupt_transfer(dev_handle, EP_IN, in_msg, EP_SIZE, &transferred, TIMEOUT);

        if (r == 0 && transferred > 0) {
            printf("[%ld] %.*s\n", time(NULL), transferred, in_msg);
            fflush(stdout);  // Force l'affichage immédiat
        }

        usleep(10000); // 10ms entre chaque lecture
    }

    // Libération (jamais atteint sauf si Ctrl+C)
    libusb_release_interface(dev_handle, 0);
    libusb_close(dev_handle);
    libusb_exit(ctx);

    return 0;
}

a) Code LUFA

Voici les codes permettant à notre microcontrôleur de se comporter comme un périphérique USB lorsqu’il est connecté à un ordinateur.

4. Librairies

a) Librairie SSD1306

Après avoir testé plusieurs codes et bibliothèques existantes (dont le fonctionnement n’était pas satisfaisant), nous avons finalement choisi de créer et d’adapter notre propre version à partir des différentes implémentations étudiées.

Cette nouvelle version de la librairie SSD1306 permet :

  • un meilleur fonctionnement de l’écran OLED,
  • une affichage plus lisible et plus fluide,
  • une meilleure maîtrise des fonctions utilisées, adaptées à notre matériel et à nos besoins.

Ci-dessous figurent les en-têtes des méthodes utilisées dans cette librairie améliorée :

#ifndef SSD1306_AVR_SSD1306_H
#define SSD1306_AVR_SSD1306_H

#pragma once
#include <stdint.h>
#include <stddef.h>

#define SSD1306_I2C_ADDR 0x3C
#define SSD1306_CTRL_CMD 0x00
#define SSD1306_CTRL_DATA 0x40

#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64
#define SSD1306_PAGES (SSD1306_HEIGHT/8)

void ssd1306_init(void);
void ssd1306_send_command(uint8_t cmd);
void ssd1306_send_data_byte(uint8_t data);
void ssd1306_send_data(const uint8_t *buf, size_t len);
void ssd1306_set_cursor(uint8_t page, uint8_t col); // page: 0..7, col: 0..127
void ssd1306_clear(void);
void ssd1306_clear_page(uint8_t page);

#endif //SSD1306_AVR_SSD1306_H

Voici le code permettant de bien positionner le bloc de texte :

#ifndef SSD1306_AVR_SSD1306_TEXT_H
#define SSD1306_AVR_SSD1306_TEXT_H
#pragma once
#include <stdint.h>

// Print UTF-8 string with optional max width and optional scroll offset
void ssd1306_print_utf8_with_max_width_scroll(const char *s, uint8_t start_page, uint8_t start_col,
                                              uint8_t max_width_px, uint16_t scroll_px);

// Print UTF-8 string across the full width
void ssd1306_print_utf8(const char *s, uint8_t start_page, uint8_t start_col);

// Print UTF-8 string with optional max width
void ssd1306_print_utf8_with_max_width(const char *s, uint8_t start_page, uint8_t start_col, uint8_t max_width_px);

// Print UTF-8 string centered on the page
void ssd1306_print_utf8_center(const char *s, uint8_t page) ;
// Print a single character at a specific page/column
void ssd1306_putc(char c, uint8_t page, uint8_t col);

void ssd1306_print_utf8_scroll(const char *s, uint8_t page, uint8_t start_col,
                               uint8_t max_width_px, uint16_t scroll_offset);
uint16_t measure_string_px(const char *s);

#endif //SSD1306_AVR_SSD1306_TEXT_H

Voici le code permettant de formater les caractères affichés à l'écran :

#ifndef SSD1306_AVR_FONT5X7_H
#define SSD1306_AVR_FONT5X7_H

#pragma once
#include <stdint.h>

extern const uint8_t font5x7[][5];
extern const uint8_t font_accent[][5];

// Optional helpers to know counts (adjust if needed)
#define FONT5X7_FIRST 32
#define FONT5X7_LAST  126
#define FONT5X7_COLS  5

#endif //SSD1306_AVR_FONT5X7_H


Lien Github du librairie : https://github.com/laurrnci22/AccessBadge/tree/main/lufa-LUFA-210130-NSI/I2L/Minimal/libs/libssd1306-atmega328p

Démonstrations


Affichage des informations sur le badge


Rendus (étudiants)

Projet KiCAD : Fichier:I2L-2025-Carte-G8-final.zip

Programmes :