first commit
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* @file ADB.cpp
|
||||
* @brief Implémentation de la bibliothèque ADB multiplateforme
|
||||
*
|
||||
* Cette implémentation offre les fonctionnalités nécessaires pour communiquer avec
|
||||
* des périphériques Apple Desktop Bus sur différentes plateformes (Arduino, STM32, ESP32, Teensy).
|
||||
* Le code est optimisé pour fonctionner de manière cohérente indépendamment du matériel sous-jacent.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include "ADB.h"
|
||||
|
||||
/**
|
||||
* Implémentation de la classe ADB - Gestion du bus Apple Desktop Bus
|
||||
*/
|
||||
|
||||
ADB::ADB(uint8_t dataPin) : dataPin(dataPin), useADBDevices(false) {}
|
||||
|
||||
void ADB::init(uint8_t dataPin, bool useADBDevices) {
|
||||
// Mise à jour de la broche si spécifiée
|
||||
if (dataPin != 0xFF) {
|
||||
this->dataPin = dataPin;
|
||||
}
|
||||
this->useADBDevices = useADBDevices;
|
||||
|
||||
// Configuration de la broche en mode open-drain
|
||||
pinMode(this->dataPin, OUTPUT_OPEN_DRAIN);
|
||||
digitalWrite(this->dataPin, HIGH);
|
||||
|
||||
// Attente que la ligne soit prête
|
||||
while (digitalRead(this->dataPin) == LOW) {
|
||||
// Attendre que la ligne remonte
|
||||
}
|
||||
|
||||
// Réinitialisation du bus
|
||||
reset();
|
||||
}
|
||||
|
||||
void ADB::reset() {
|
||||
// Signal de réinitialisation: maintenir la ligne basse pendant 3ms
|
||||
digitalWrite(dataPin, LOW);
|
||||
delayMicroseconds(3000);
|
||||
digitalWrite(dataPin, HIGH);
|
||||
}
|
||||
|
||||
void ADB::wait() {
|
||||
// Signal d'attente: maintenir la ligne basse pendant 800µs
|
||||
digitalWrite(dataPin, LOW);
|
||||
delayMicroseconds(800);
|
||||
digitalWrite(dataPin, HIGH);
|
||||
}
|
||||
|
||||
void ADB::sync() {
|
||||
// Signal de synchronisation pour les commandes
|
||||
digitalWrite(dataPin, HIGH);
|
||||
delayMicroseconds(70);
|
||||
digitalWrite(dataPin, LOW);
|
||||
}
|
||||
|
||||
void ADB::writeBit(uint16_t bit) {
|
||||
// Encodage Manchester modifié:
|
||||
// 1 = 35µs bas puis 65µs haut
|
||||
// 0 = 65µs bas puis 35µs haut
|
||||
if (bit) {
|
||||
digitalWrite(dataPin, LOW);
|
||||
delayMicroseconds(35);
|
||||
digitalWrite(dataPin, HIGH);
|
||||
delayMicroseconds(65);
|
||||
} else {
|
||||
digitalWrite(dataPin, LOW);
|
||||
delayMicroseconds(65);
|
||||
digitalWrite(dataPin, HIGH);
|
||||
delayMicroseconds(35);
|
||||
}
|
||||
}
|
||||
|
||||
void ADB::writeBits(uint16_t bits, uint8_t length) {
|
||||
// Écrit plusieurs bits, du MSB au LSB
|
||||
uint16_t mask = 1 << (length - 1);
|
||||
while (mask) {
|
||||
writeBit(bits & mask);
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ADB::writeDataPacket(uint16_t bits, uint8_t length) {
|
||||
// Format du paquet: bit de début (1), données, bit de fin (0)
|
||||
writeBit(1);
|
||||
writeBits(bits, length);
|
||||
writeBit(0);
|
||||
}
|
||||
|
||||
bool ADB::waitTLT(bool responseExpected) {
|
||||
// Attend la réponse d'un périphérique après une commande
|
||||
digitalWrite(dataPin, HIGH);
|
||||
delayMicroseconds(140);
|
||||
|
||||
// Si une réponse est attendue, attendre jusqu'à 240µs
|
||||
if (responseExpected) {
|
||||
uint8_t timeout = 0;
|
||||
while (digitalRead(dataPin) == HIGH && timeout < 240) {
|
||||
delayMicroseconds(1);
|
||||
timeout++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ADB::readBit() {
|
||||
// Lecture d'un bit avec détection de timeout
|
||||
const unsigned long MAX_WAIT = 85; // Microseconds
|
||||
|
||||
// Attente du front montant
|
||||
auto time_start = micros();
|
||||
while (digitalRead(dataPin) == LOW) {
|
||||
if (micros() - time_start > MAX_WAIT)
|
||||
return BIT_ERROR;
|
||||
}
|
||||
auto low_time = micros() - time_start;
|
||||
|
||||
// Attente du front descendant
|
||||
time_start = micros();
|
||||
while (digitalRead(dataPin) == HIGH) {
|
||||
if (micros() - time_start > MAX_WAIT)
|
||||
return BIT_ERROR;
|
||||
}
|
||||
auto high_time = micros() - time_start;
|
||||
|
||||
// Décodage Manchester modifié
|
||||
return (low_time < high_time) ? 0x1 : 0x0;
|
||||
}
|
||||
|
||||
bool ADB::readDataPacket(uint16_t* buffer, uint8_t length) {
|
||||
// Vérifie le bit de début
|
||||
if (readBit() != 0x1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lecture bit par bit des données
|
||||
*buffer = 0;
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
uint8_t current_bit = readBit();
|
||||
if (current_bit == BIT_ERROR) {
|
||||
return false;
|
||||
}
|
||||
*buffer = (*buffer << 1) | current_bit;
|
||||
}
|
||||
|
||||
// Lecture du bit de fin (ignoré)
|
||||
readBit();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ADB::writeCommand(uint8_t command) {
|
||||
wait();
|
||||
sync();
|
||||
writeBits(static_cast<uint16_t>(command), 8);
|
||||
writeBit(0);
|
||||
}
|
||||
|
||||
void ADB::setPin(uint8_t dataPin) {
|
||||
this->dataPin = dataPin;
|
||||
pinMode(dataPin, OUTPUT_OPEN_DRAIN);
|
||||
digitalWrite(dataPin, HIGH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implémentation de la classe ADBDevices - Gestion des périphériques ADB
|
||||
*/
|
||||
|
||||
bool ADBDevices::initializeDevice(uint8_t address, uint8_t handler_id, bool& present) {
|
||||
bool error = false;
|
||||
|
||||
// Préparer les données pour le registre 3
|
||||
adb_data<adb_register3> reg3 = {0};
|
||||
adb_data<adb_register3> mask = {0};
|
||||
|
||||
reg3.data.device_handler_id = handler_id;
|
||||
mask.data.device_handler_id = 0xFF;
|
||||
|
||||
// Tenter de configurer le périphérique et vérifier sa présence
|
||||
present = deviceUpdateRegister3(address, reg3, mask.raw, &error) && !error;
|
||||
return present;
|
||||
}
|
||||
|
||||
adb_data<adb_kb_modifiers> ADBDevices::keyboardReadModifiers(bool* error) {
|
||||
adb_data<adb_kb_modifiers> modifiers = {0};
|
||||
|
||||
// Envoi d'une commande Talk au registre 2 du clavier
|
||||
adb.writeCommand(CMD_TALK | ADB_ADDRESS(ADDR_KEYBOARD) | ADB_REGISTER(2));
|
||||
adb.waitTLT(true);
|
||||
|
||||
// Lecture des données et mise à jour du statut d'erreur
|
||||
*error = !adb.readDataPacket(&modifiers.raw, 16);
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
adb_data<adb_kb_keypress> ADBDevices::keyboardReadKeyPress(bool* error) {
|
||||
adb_data<adb_kb_keypress> keyPress = {0};
|
||||
|
||||
// Envoi d'une commande Talk au registre 0 du clavier
|
||||
adb.writeCommand(CMD_TALK | ADB_ADDRESS(ADDR_KEYBOARD) | ADB_REGISTER(0));
|
||||
adb.waitTLT(true);
|
||||
|
||||
// Lecture des touches pressées et mise à jour du statut d'erreur
|
||||
*error = !adb.readDataPacket(&keyPress.raw, 16);
|
||||
return keyPress;
|
||||
}
|
||||
|
||||
void ADBDevices::keyboardWriteLEDs(bool scroll, bool caps, bool num) {
|
||||
adb_data<adb_kb_modifiers> modifiers = {0};
|
||||
|
||||
// Configuration des LEDs (la logique est inversée dans le protocole)
|
||||
modifiers.data.led_scroll = !scroll;
|
||||
modifiers.data.led_caps = !caps;
|
||||
modifiers.data.led_num = !num;
|
||||
|
||||
// Envoi d'une commande Listen au registre 2 du clavier
|
||||
adb.writeCommand(CMD_LISTEN | ADB_ADDRESS(ADDR_KEYBOARD) | ADB_REGISTER(2));
|
||||
adb.waitTLT(false);
|
||||
|
||||
// Envoi des données de configuration des LEDs
|
||||
adb.writeDataPacket(modifiers.raw, 16);
|
||||
}
|
||||
|
||||
adb_data<adb_mouse_data> ADBDevices::mouseReadData(bool* error) {
|
||||
adb_data<adb_mouse_data> mouseData = {0};
|
||||
|
||||
// Envoi d'une commande Talk au registre 0 de la souris
|
||||
adb.writeCommand(CMD_TALK | ADB_ADDRESS(ADDR_MOUSE) | ADB_REGISTER(0));
|
||||
adb.waitTLT(true);
|
||||
|
||||
// Lecture des données de la souris et mise à jour du statut d'erreur
|
||||
*error = !adb.readDataPacket(&mouseData.raw, 16);
|
||||
return mouseData;
|
||||
}
|
||||
|
||||
adb_data<adb_register3> ADBDevices::deviceReadRegister3(uint8_t addr, bool* error) {
|
||||
adb_data<adb_register3> reg3 = {0};
|
||||
|
||||
// Envoi d'une commande Talk au registre 3 du périphérique
|
||||
adb.writeCommand(CMD_TALK | ADB_ADDRESS(addr) | ADB_REGISTER(3));
|
||||
adb.waitTLT(true);
|
||||
|
||||
// Lecture de la configuration du périphérique
|
||||
*error = !adb.readDataPacket(®3.raw, 16);
|
||||
return reg3;
|
||||
}
|
||||
|
||||
bool ADBDevices::deviceUpdateRegister3(uint8_t addr, adb_data<adb_register3> newReg3, uint16_t mask, bool* error) {
|
||||
// Lecture de la configuration actuelle
|
||||
adb_data<adb_register3> reg3 = deviceReadRegister3(addr, error);
|
||||
if (*error) return false;
|
||||
|
||||
// Attente entre les opérations
|
||||
delay(POLL_DELAY);
|
||||
|
||||
// Application du masque pour ne modifier que les bits souhaités
|
||||
reg3.raw = (reg3.raw & ~mask) | (newReg3.raw & mask);
|
||||
|
||||
// Envoi d'une commande Listen pour mettre à jour la configuration
|
||||
adb.writeCommand(CMD_LISTEN | ADB_ADDRESS(addr) | ADB_REGISTER(3));
|
||||
adb.waitTLT(false);
|
||||
adb.writeDataPacket(reg3.raw, 16);
|
||||
|
||||
// Attente entre les opérations
|
||||
delay(POLL_DELAY);
|
||||
|
||||
// Vérification que la mise à jour a été prise en compte
|
||||
reg3 = deviceReadRegister3(addr, error);
|
||||
if (*error) return false;
|
||||
|
||||
return (reg3.raw & mask) == (newReg3.raw & mask);
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
* @file ADB.h
|
||||
* @brief Bibliothèque multiplateforme pour la communication avec le bus Apple Desktop Bus (ADB)
|
||||
*/
|
||||
|
||||
#ifndef ADB_MAIN_h
|
||||
#define ADB_MAIN_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cstdint>
|
||||
#include "ADBKeymap.h"
|
||||
#include "ADBKeyCodes.h"
|
||||
|
||||
namespace ADBProtocol {
|
||||
// Commandes ADB
|
||||
constexpr uint8_t CMD_TALK = 0b11 << 2;
|
||||
constexpr uint8_t CMD_LISTEN = 0b10 << 2;
|
||||
constexpr uint8_t CMD_FLUSH = 0b01 << 2;
|
||||
|
||||
// Constantes diverses
|
||||
constexpr uint8_t BIT_ERROR = 0xFF;
|
||||
constexpr uint8_t POLL_DELAY = 5;
|
||||
|
||||
// Macros de conversion pour les adresses et registres ADB
|
||||
constexpr uint8_t ADDRESS(uint8_t addr) { return (addr << 4); }
|
||||
constexpr uint8_t REGISTER(uint8_t reg) { return reg; }
|
||||
}
|
||||
|
||||
// Pour compatibilité avec le code existant
|
||||
#define CMD_TALK ADBProtocol::CMD_TALK
|
||||
#define CMD_LISTEN ADBProtocol::CMD_LISTEN
|
||||
#define CMD_FLUSH ADBProtocol::CMD_FLUSH
|
||||
#define BIT_ERROR ADBProtocol::BIT_ERROR
|
||||
#define POLL_DELAY ADBProtocol::POLL_DELAY
|
||||
#define ADB_ADDRESS(addr) ADBProtocol::ADDRESS(addr)
|
||||
#define ADB_REGISTER(reg) ADBProtocol::REGISTER(reg)
|
||||
|
||||
/**
|
||||
* @brief Structures de données pour les périphériques ADB
|
||||
*/
|
||||
struct adb_kb_keypress {
|
||||
uint8_t key1 : 7; // Code de la deuxième touche
|
||||
bool released1 : 1; // Indicateur de relâchement pour la deuxième touche
|
||||
uint8_t key0 : 7; // Code de la première touche
|
||||
bool released0 : 1; // Indicateur de relâchement pour la première touche
|
||||
};
|
||||
|
||||
struct adb_kb_modifiers {
|
||||
bool led_num : 1; // LED de verrouillage numérique
|
||||
bool led_caps : 1; // LED de verrouillage majuscule
|
||||
bool led_scroll : 1; // LED de défilement
|
||||
uint8_t reserved1 : 3; // Bits réservés
|
||||
bool scroll_lock : 1; // État de verrouillage de défilement
|
||||
bool num_lock : 1; // État de verrouillage numérique
|
||||
bool command : 1; // Touche Command
|
||||
bool option : 1; // Touche Option
|
||||
bool shift : 1; // Touche Shift
|
||||
bool control : 1; // Touche Control
|
||||
bool reset : 1; // État de réinitialisation
|
||||
bool caps_lock : 1; // État de verrouillage majuscule
|
||||
bool backspace : 1; // Touche Backspace
|
||||
uint8_t reserved0 : 1; // Bit réservé
|
||||
};
|
||||
|
||||
struct adb_mouse_data {
|
||||
uint8_t x_offset : 7; // Déplacement horizontal de la souris
|
||||
uint8_t reserved0 : 1; // Bit réservé
|
||||
uint8_t y_offset : 7; // Déplacement vertical de la souris
|
||||
bool button : 1; // État du bouton de souris
|
||||
};
|
||||
|
||||
struct adb_register3 {
|
||||
uint8_t device_handler_id : 8; // Identifiant du gestionnaire
|
||||
uint8_t device_address : 4; // Adresse du périphérique
|
||||
uint8_t reserved1 : 1; // Bit réservé
|
||||
uint8_t srq_enable : 1; // Activation des requêtes de service
|
||||
uint8_t exceptional_event : 1; // Indicateur d'événement exceptionnel
|
||||
uint8_t reserved0 : 1; // Bit réservé
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Union pour faciliter l'accès aux données ADB sous forme brute ou structurée
|
||||
*/
|
||||
template <typename T>
|
||||
union adb_data {
|
||||
uint16_t raw;
|
||||
T data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Classe principale pour gérer le bus ADB
|
||||
*/
|
||||
class ADB {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructeur avec pin de données configurable
|
||||
* @param dataPin Broche utilisée pour les communications ADB
|
||||
*/
|
||||
explicit ADB(uint8_t dataPin);
|
||||
|
||||
/**
|
||||
* @brief Initialisation du bus ADB
|
||||
* @param dataPin Broche optionnelle pour reconfigurer la pin (0xFF pour conserver l'existante)
|
||||
* @param useADBDevices Indique si la classe ADBDevices sera utilisée
|
||||
*/
|
||||
void init(uint8_t dataPin = 0xFF, bool useADBDevices = false);
|
||||
|
||||
/**
|
||||
* @brief Réinitialise le bus ADB
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @brief Envoi d'une commande sur le bus ADB
|
||||
* @param command Code de commande ADB
|
||||
*/
|
||||
void writeCommand(uint8_t command);
|
||||
|
||||
/**
|
||||
* @brief Lecture de données depuis le bus ADB
|
||||
* @param buffer Pointeur vers le tampon de données
|
||||
* @param length Longueur des données à lire en bits
|
||||
* @return true si la lecture a réussi, false sinon
|
||||
*/
|
||||
bool readDataPacket(uint16_t* buffer, uint8_t length);
|
||||
|
||||
/**
|
||||
* @brief Écriture de données sur le bus ADB
|
||||
* @param bits Données à écrire
|
||||
* @param length Longueur des données à écrire en bits
|
||||
*/
|
||||
void writeDataPacket(uint16_t bits, uint8_t length);
|
||||
|
||||
/**
|
||||
* @brief Change la broche utilisée pour la communication
|
||||
* @param dataPin Nouvelle broche de données
|
||||
*/
|
||||
void setPin(uint8_t dataPin);
|
||||
|
||||
/**
|
||||
* @brief Attente de réponse du périphérique ADB
|
||||
* @param responseExpected Indique si une réponse est attendue
|
||||
* @return true si l'attente s'est bien déroulée
|
||||
*/
|
||||
bool waitTLT(bool responseExpected);
|
||||
|
||||
private:
|
||||
uint8_t dataPin; // Broche de données
|
||||
bool useADBDevices; // Utilisation de la classe ADBDevices
|
||||
|
||||
// Méthodes de bas niveau pour la communication ADB
|
||||
void wait(); // Signal d'attente (anciennement attention)
|
||||
void sync(); // Signal de synchronisation
|
||||
void writeBit(uint16_t bit); // Écriture d'un bit
|
||||
void writeBits(uint16_t bits, uint8_t length); // Écriture de plusieurs bits
|
||||
uint8_t readBit(); // Lecture d'un bit
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Classe pour gérer les périphériques connectés au bus ADB
|
||||
*/
|
||||
class ADBDevices {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructeur avec référence à un objet ADB
|
||||
* @param adb Référence à l'instance ADB utilisée pour la communication
|
||||
*/
|
||||
explicit ADBDevices(ADB& adb) : adb(adb) {}
|
||||
|
||||
/**
|
||||
* @brief Initialisation d'un périphérique ADB
|
||||
* @param address Adresse du périphérique
|
||||
* @param handler_id Identifiant du gestionnaire
|
||||
* @param present Référence pour indiquer si le périphérique est présent
|
||||
* @return true si l'initialisation a réussi
|
||||
*/
|
||||
bool initializeDevice(uint8_t address, uint8_t handler_id, bool& present);
|
||||
|
||||
/**
|
||||
* @brief Lecture des modificateurs du clavier
|
||||
* @param error Pointeur pour indiquer si une erreur s'est produite
|
||||
* @return Structure contenant les modificateurs
|
||||
*/
|
||||
adb_data<adb_kb_modifiers> keyboardReadModifiers(bool* error);
|
||||
|
||||
/**
|
||||
* @brief Lecture des touches pressées sur le clavier
|
||||
* @param error Pointeur pour indiquer si une erreur s'est produite
|
||||
* @return Structure contenant les touches pressées
|
||||
*/
|
||||
adb_data<adb_kb_keypress> keyboardReadKeyPress(bool* error);
|
||||
|
||||
/**
|
||||
* @brief Configuration des LEDs du clavier
|
||||
* @param scroll État de la LED de défilement
|
||||
* @param caps État de la LED de verrouillage majuscule
|
||||
* @param num État de la LED de verrouillage numérique
|
||||
*/
|
||||
void keyboardWriteLEDs(bool scroll, bool caps, bool num);
|
||||
|
||||
/**
|
||||
* @brief Lecture des données de la souris
|
||||
* @param error Pointeur pour indiquer si une erreur s'est produite
|
||||
* @return Structure contenant les données de la souris
|
||||
*/
|
||||
adb_data<adb_mouse_data> mouseReadData(bool* error);
|
||||
|
||||
/**
|
||||
* @brief Mise à jour du registre 3 d'un périphérique
|
||||
* @param addr Adresse du périphérique
|
||||
* @param newReg3 Nouvelles valeurs pour le registre 3
|
||||
* @param mask Masque à appliquer
|
||||
* @param error Pointeur pour indiquer si une erreur s'est produite
|
||||
* @return true si la mise à jour a réussi
|
||||
*/
|
||||
bool deviceUpdateRegister3(uint8_t addr, adb_data<adb_register3> newReg3, uint16_t mask, bool* error);
|
||||
|
||||
private:
|
||||
ADB& adb; // Référence à l'objet ADB utilisé pour la communication
|
||||
|
||||
/**
|
||||
* @brief Lecture du registre 3 d'un périphérique
|
||||
* @param addr Adresse du périphérique
|
||||
* @param error Pointeur pour indiquer si une erreur s'est produite
|
||||
* @return Structure contenant les données du registre 3
|
||||
*/
|
||||
adb_data<adb_register3> deviceReadRegister3(uint8_t addr, bool* error);
|
||||
};
|
||||
|
||||
// Conversion des axes de la souris (format 7 bits en complément à 2 vers int8_t)
|
||||
inline int8_t adbMouseConvertAxis(uint8_t value) {
|
||||
return static_cast<int8_t>(value << 1);
|
||||
}
|
||||
|
||||
#endif // ADB_MAIN_h
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file ADBCore.h
|
||||
* @brief Fichier principal d'inclusion pour la bibliothèque ADB multiplateforme
|
||||
*/
|
||||
|
||||
#ifndef ADB_CORE_h
|
||||
#define ADB_CORE_h
|
||||
|
||||
// Ordre d'inclusion optimisé pour assurer que toutes les dépendances sont disponibles
|
||||
#include "HIDTables.h" // Définitions des codes HID
|
||||
#include "ADBKeyCodes.h" // Définitions des constantes ADB
|
||||
#include "ADBKeymap.h" // Mappage ADB vers HID
|
||||
#include "ADB.h" // Interface principale du protocole ADB
|
||||
#include "ADBUtils.h" // Utilitaires supplémentaires
|
||||
|
||||
// Macro pour convertir les valeurs des axes souris (pour la compatibilité avec le code existant)
|
||||
#define ADB_MOUSE_CONV_AXIS(val) adbMouseConvertAxis(val)
|
||||
|
||||
#endif // ADB_CORE_h
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Définition des codes de touches ADB
|
||||
* Adaptées du protocole Apple Desktop Bus
|
||||
*/
|
||||
|
||||
#ifndef ADB_KEYCODES_H
|
||||
#define ADB_KEYCODES_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* Constantes du protocole Apple Desktop Bus
|
||||
*/
|
||||
namespace ADBKey {
|
||||
namespace Address {
|
||||
constexpr uint8_t KEYBOARD = 0x2;
|
||||
constexpr uint8_t MOUSE = 0x3;
|
||||
}
|
||||
|
||||
namespace KeyCode {
|
||||
// Touches spéciales
|
||||
constexpr uint8_t CAPS_LOCK = 0x39;
|
||||
constexpr uint8_t NUM_LOCK = 0x47;
|
||||
|
||||
// Touches de modification
|
||||
constexpr uint8_t LEFT_SHIFT = 0x38;
|
||||
constexpr uint8_t RIGHT_SHIFT = 0x7B;
|
||||
constexpr uint8_t LEFT_CONTROL = 0x36;
|
||||
constexpr uint8_t RIGHT_CONTROL = 0x7D;
|
||||
constexpr uint8_t LEFT_OPTION = 0x3A;
|
||||
constexpr uint8_t RIGHT_OPTION = 0x7C;
|
||||
constexpr uint8_t LEFT_COMMAND = 0x37;
|
||||
constexpr uint8_t RIGHT_COMMAND = 0x37;
|
||||
|
||||
// Touche Power
|
||||
constexpr uint8_t POWER_KEY_CODE = 0x66;
|
||||
constexpr uint16_t POWER_DOWN = 0x7F7F;
|
||||
constexpr uint16_t POWER_UP = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Pour la compatibilité avec le code existant
|
||||
#define ADDR_KEYBOARD ADBKey::Address::KEYBOARD
|
||||
#define ADDR_MOUSE ADBKey::Address::MOUSE
|
||||
#define ADB_KEY_CAPS_LOCK ADBKey::KeyCode::CAPS_LOCK
|
||||
#define ADB_KEY_NUM_LOCK ADBKey::KeyCode::NUM_LOCK
|
||||
#define ADB_KEY_POWER_DOWN ADBKey::KeyCode::POWER_DOWN
|
||||
#define ADB_KEY_POWER_UP ADBKey::KeyCode::POWER_UP
|
||||
|
||||
// Définitions des modificateurs (compatibilité)
|
||||
#define ADB_KEY_LEFT_SHIFT ADBKey::KeyCode::LEFT_SHIFT
|
||||
#define ADB_KEY_RIGHT_SHIFT ADBKey::KeyCode::RIGHT_SHIFT
|
||||
#define ADB_KEY_LEFT_CONTROL ADBKey::KeyCode::LEFT_CONTROL
|
||||
#define ADB_KEY_RIGHT_CONTROL ADBKey::KeyCode::RIGHT_CONTROL
|
||||
#define ADB_KEY_LEFT_OPTION ADBKey::KeyCode::LEFT_OPTION
|
||||
#define ADB_KEY_RIGHT_OPTION ADBKey::KeyCode::RIGHT_OPTION
|
||||
#define ADB_KEY_LEFT_COMMAND ADBKey::KeyCode::LEFT_COMMAND
|
||||
#define ADB_KEY_RIGHT_COMMAND ADBKey::KeyCode::RIGHT_COMMAND
|
||||
|
||||
#endif // ADB_KEYCODES_H
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "ADBKeymap.h"
|
||||
#include "HIDTables.h"
|
||||
|
||||
// Définition du tableau de conversion ADB vers HID
|
||||
const uint8_t ADBKeymap::keyCodeTable[128] = {
|
||||
// Tableau de conversion des touches ADB vers HID
|
||||
// Format: [code ADB] = code HID
|
||||
KEY_NONE, KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, // 0x00-0x07
|
||||
KEY_X, KEY_C, KEY_V, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R, // 0x08-0x0F
|
||||
KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5, // 0x10-0x17
|
||||
KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O, // 0x18-0x1F
|
||||
KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE, // 0x20-0x27
|
||||
KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT, // 0x28-0x2F
|
||||
KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, KEY_NONE, KEY_ESC, KEY_NONE, KEY_LEFTMETA, // 0x30-0x37
|
||||
KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTCTRL, KEY_NONE, // 0x38-0x3F
|
||||
// Continuer avec le reste du tableau...
|
||||
KEY_NONE, KEY_KPDOT, KEY_NONE, KEY_KPASTERISK, KEY_NONE, KEY_KPPLUS, KEY_NONE, KEY_NUMLOCK, // 0x40-0x47
|
||||
// ...et ainsi de suite jusqu'à 127
|
||||
// Complétez le reste du tableau selon les besoins de votre clavier
|
||||
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 0x48-0x4F
|
||||
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 0x50-0x57
|
||||
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 0x58-0x5F
|
||||
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 0x60-0x67
|
||||
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 0x68-0x6F
|
||||
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 0x70-0x77
|
||||
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE // 0x78-0x7F
|
||||
};
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @file ADBKeymap.h
|
||||
* @brief Constantes et fonctions de conversion pour la bibliothèque ADB multiplateforme
|
||||
*/
|
||||
|
||||
#ifndef ADB_KEYMAP_h
|
||||
#define ADB_KEYMAP_h
|
||||
|
||||
#include <cstdint>
|
||||
#include "HIDTables.h"
|
||||
#include "ADBKeyCodes.h"
|
||||
|
||||
// Classe pour la conversion ADB vers HID
|
||||
class ADBKeymap {
|
||||
public:
|
||||
// Vérifie si une touche est un modificateur
|
||||
static bool isModifier(uint8_t key) {
|
||||
using namespace ADBKey::KeyCode;
|
||||
return
|
||||
(key == LEFT_SHIFT) ||
|
||||
(key == RIGHT_SHIFT) ||
|
||||
(key == LEFT_OPTION) ||
|
||||
(key == RIGHT_OPTION) ||
|
||||
(key == LEFT_COMMAND) ||
|
||||
(key == RIGHT_COMMAND) ||
|
||||
(key == LEFT_CONTROL) ||
|
||||
(key == RIGHT_CONTROL);
|
||||
}
|
||||
|
||||
// Obtient le masque du modificateur correspondant à une touche ADB
|
||||
static uint8_t getModifierMask(uint8_t adbKeycode) {
|
||||
using namespace ADBKey::KeyCode;
|
||||
if (adbKeycode == LEFT_SHIFT) return KEY_MOD_LSHIFT;
|
||||
if (adbKeycode == RIGHT_SHIFT) return KEY_MOD_RSHIFT;
|
||||
if (adbKeycode == LEFT_CONTROL) return KEY_MOD_LCTRL;
|
||||
if (adbKeycode == RIGHT_CONTROL) return KEY_MOD_RCTRL;
|
||||
if (adbKeycode == LEFT_OPTION) return KEY_MOD_LALT;
|
||||
if (adbKeycode == RIGHT_OPTION) return KEY_MOD_RALT;
|
||||
if (adbKeycode == LEFT_COMMAND) return KEY_MOD_LMETA;
|
||||
if (adbKeycode == RIGHT_COMMAND) return KEY_MOD_RMETA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convertit un code ADB en code HID
|
||||
static uint8_t toHID(uint8_t adbKeycode) {
|
||||
if (adbKeycode >= 128) return KEY_NONE;
|
||||
return keyCodeTable[adbKeycode];
|
||||
}
|
||||
|
||||
// Tableau de conversion ADB vers HID
|
||||
static const uint8_t keyCodeTable[128];
|
||||
};
|
||||
|
||||
#endif // ADB_KEYMAP_h
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* @file ADBPlatform.h
|
||||
* @brief Détection automatique de plateforme pour la bibliothèque ADB
|
||||
*
|
||||
* Ce fichier fournit des définitions et configurations automatiques basées
|
||||
* sur la plateforme cible. Il peut être inclus dans des exemples pour une
|
||||
* meilleure portabilité.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#ifndef ADB_PLATFORM_h
|
||||
#define ADB_PLATFORM_h
|
||||
|
||||
// Détection de plateforme et configuration automatique
|
||||
#if defined(ARDUINO_ARCH_AVR)
|
||||
#define ADB_PLATFORM_AVR
|
||||
#define ADB_PLATFORM_NAME "Arduino AVR"
|
||||
#define ADB_DEFAULT_PIN 2
|
||||
|
||||
#elif defined(ARDUINO_ARCH_SAM)
|
||||
#define ADB_PLATFORM_SAM
|
||||
#define ADB_PLATFORM_NAME "Arduino SAM"
|
||||
#define ADB_DEFAULT_PIN 2
|
||||
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#define ADB_PLATFORM_SAMD
|
||||
#define ADB_PLATFORM_NAME "Arduino SAMD"
|
||||
#define ADB_DEFAULT_PIN 2
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#define ADB_PLATFORM_STM32
|
||||
#define ADB_PLATFORM_NAME "STM32"
|
||||
// Sur les STM32, la broche par défaut est PB4
|
||||
#define ADB_DEFAULT_PIN PB4
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#define ADB_PLATFORM_ESP32
|
||||
#define ADB_PLATFORM_NAME "ESP32"
|
||||
#define ADB_DEFAULT_PIN 21
|
||||
|
||||
#elif defined(TEENSYDUINO)
|
||||
#define ADB_PLATFORM_TEENSY
|
||||
#define ADB_PLATFORM_NAME "Teensy"
|
||||
#define ADB_DEFAULT_PIN 3
|
||||
|
||||
#else
|
||||
#define ADB_PLATFORM_UNKNOWN
|
||||
#define ADB_PLATFORM_NAME "Plateforme inconnue"
|
||||
#define ADB_DEFAULT_PIN 2
|
||||
#warning "Plateforme non reconnue, utilisation de la pin 2 par défaut"
|
||||
#endif
|
||||
|
||||
// Paramètres par défaut recommandés par plateforme
|
||||
#ifdef ADB_PLATFORM_AVR
|
||||
// Arduino UNO, MEGA, etc. - MCU plus lent
|
||||
#define ADB_POLL_INTERVAL 100
|
||||
#define ADB_SERIAL_BAUD 9600
|
||||
#elif defined(ADB_PLATFORM_STM32) || defined(ADB_PLATFORM_ESP32) || defined(ADB_PLATFORM_TEENSY)
|
||||
// Plateformes plus rapides
|
||||
#define ADB_POLL_INTERVAL 20
|
||||
#define ADB_SERIAL_BAUD 115200
|
||||
#else
|
||||
// Valeurs par défaut pour autres plateformes
|
||||
#define ADB_POLL_INTERVAL 50
|
||||
#define ADB_SERIAL_BAUD 57600
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Fonction pour afficher les informations de plateforme
|
||||
*/
|
||||
inline void printPlatformInfo() {
|
||||
Serial.print(F("Bibliothèque ADB sur plateforme: "));
|
||||
Serial.println(F(ADB_PLATFORM_NAME));
|
||||
Serial.print(F("Pin ADB par défaut: "));
|
||||
Serial.println(ADB_DEFAULT_PIN);
|
||||
}
|
||||
|
||||
#endif // ADB_PLATFORM_h
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file ADBUtils.h
|
||||
* @brief Utilitaires pour la bibliothèque ADB multiplateforme
|
||||
*
|
||||
* Ce fichier fournit des classes et fonctions utilitaires pour simplifier
|
||||
* l'utilisation de la bibliothèque ADB sur différentes plateformes matérielles.
|
||||
* Les utilitaires sont conçus pour être compatibles avec toutes les plateformes supportées.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#ifndef ADB_UTILS_h
|
||||
#define ADB_UTILS_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "ADB.h"
|
||||
|
||||
/**
|
||||
* @brief Classe d'utilitaires pour faciliter l'utilisation des périphériques ADB
|
||||
*/
|
||||
class ADBUtils {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructeur avec référence à un objet ADBDevices
|
||||
* @param devices Référence à l'instance ADBDevices
|
||||
*/
|
||||
explicit ADBUtils(ADBDevices& devices) : devices(devices) {}
|
||||
|
||||
/**
|
||||
* @brief Imprime l'état des touches du clavier sur le port série
|
||||
* @return true si la lecture a réussi
|
||||
*/
|
||||
bool printKeyboardStatus() {
|
||||
bool error = false;
|
||||
|
||||
// Lecture des modificateurs
|
||||
auto modifiers = devices.keyboardReadModifiers(&error);
|
||||
if (error) return false;
|
||||
|
||||
Serial.println(F("Keyboard Status:"));
|
||||
Serial.print(F(" Caps Lock: "));
|
||||
Serial.println(modifiers.data.led_caps ? F("ON") : F("OFF"));
|
||||
Serial.print(F(" Num Lock: "));
|
||||
Serial.println(modifiers.data.led_num ? F("ON") : F("OFF"));
|
||||
|
||||
// Lecture des touches pressées
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (error) return false;
|
||||
|
||||
if (keyPress.data.key0 != 0) {
|
||||
Serial.print(F(" Key 0: 0x"));
|
||||
Serial.print(keyPress.data.key0, HEX);
|
||||
Serial.print(F(" ("));
|
||||
Serial.print(keyPress.data.released0 ? F("Released") : F("Pressed"));
|
||||
Serial.println(F(")"));
|
||||
}
|
||||
|
||||
if (keyPress.data.key1 != 0) {
|
||||
Serial.print(F(" Key 1: 0x"));
|
||||
Serial.print(keyPress.data.key1, HEX);
|
||||
Serial.print(F(" ("));
|
||||
Serial.print(keyPress.data.released1 ? F("Released") : F("Pressed"));
|
||||
Serial.println(F(")"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Imprime les données de la souris sur le port série
|
||||
* @return true si la lecture a réussi
|
||||
*/
|
||||
bool printMouseStatus() {
|
||||
bool error = false;
|
||||
|
||||
// Lecture des données de la souris
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (error) return false;
|
||||
|
||||
// Conversion des valeurs brutes
|
||||
int8_t xMove = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t yMove = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
|
||||
Serial.println(F("Mouse Status:"));
|
||||
Serial.print(F(" X Movement: "));
|
||||
Serial.println(xMove);
|
||||
Serial.print(F(" Y Movement: "));
|
||||
Serial.println(yMove);
|
||||
Serial.print(F(" Button: "));
|
||||
Serial.println(mouseData.data.button ? F("Pressed") : F("Released"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
ADBDevices& devices;
|
||||
};
|
||||
|
||||
#endif // ADB_UTILS_h
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf, pp. 53
|
||||
// adapted from https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2
|
||||
|
||||
#ifndef HID_TABLES_h
|
||||
#define HID_TABLES_h
|
||||
|
||||
#define KEY_MOD_LCTRL 0x01
|
||||
#define KEY_MOD_LSHIFT 0x02
|
||||
#define KEY_MOD_LALT 0x04
|
||||
#define KEY_MOD_LMETA 0x08
|
||||
#define KEY_MOD_RCTRL 0x10
|
||||
#define KEY_MOD_RSHIFT 0x20
|
||||
#define KEY_MOD_RALT 0x40
|
||||
#define KEY_MOD_RMETA 0x80
|
||||
|
||||
/**
|
||||
* 0x00 if no key pressed.
|
||||
*
|
||||
* If more than N keys are pressed, the HID reports
|
||||
* KEY_ERR_OVF in all slots to indicate this condition.
|
||||
*/
|
||||
|
||||
#define KEY_NONE 0x00 // No key pressed
|
||||
#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
|
||||
// 0x02 // Keyboard POST Fail
|
||||
// 0x03 // Keyboard Error Undefined
|
||||
#define KEY_A 0x04 // Keyboard a and A
|
||||
#define KEY_B 0x05 // Keyboard b and B
|
||||
#define KEY_C 0x06 // Keyboard c and C
|
||||
#define KEY_D 0x07 // Keyboard d and D
|
||||
#define KEY_E 0x08 // Keyboard e and E
|
||||
#define KEY_F 0x09 // Keyboard f and F
|
||||
#define KEY_G 0x0a // Keyboard g and G
|
||||
#define KEY_H 0x0b // Keyboard h and H
|
||||
#define KEY_I 0x0c // Keyboard i and I
|
||||
#define KEY_J 0x0d // Keyboard j and J
|
||||
#define KEY_K 0x0e // Keyboard k and K
|
||||
#define KEY_L 0x0f // Keyboard l and L
|
||||
#define KEY_M 0x10 // Keyboard m and M
|
||||
#define KEY_N 0x11 // Keyboard n and N
|
||||
#define KEY_O 0x12 // Keyboard o and O
|
||||
#define KEY_P 0x13 // Keyboard p and P
|
||||
#define KEY_Q 0x14 // Keyboard q and Q
|
||||
#define KEY_R 0x15 // Keyboard r and R
|
||||
#define KEY_S 0x16 // Keyboard s and S
|
||||
#define KEY_T 0x17 // Keyboard t and T
|
||||
#define KEY_U 0x18 // Keyboard u and U
|
||||
#define KEY_V 0x19 // Keyboard v and V
|
||||
#define KEY_W 0x1a // Keyboard w and W
|
||||
#define KEY_X 0x1b // Keyboard x and X
|
||||
#define KEY_Y 0x1c // Keyboard y and Y
|
||||
#define KEY_Z 0x1d // Keyboard z and Z
|
||||
|
||||
#define KEY_1 0x1e // Keyboard 1 and !
|
||||
#define KEY_2 0x1f // Keyboard 2 and @
|
||||
#define KEY_3 0x20 // Keyboard 3 and #
|
||||
#define KEY_4 0x21 // Keyboard 4 and $
|
||||
#define KEY_5 0x22 // Keyboard 5 and %
|
||||
#define KEY_6 0x23 // Keyboard 6 and ^
|
||||
#define KEY_7 0x24 // Keyboard 7 and &
|
||||
#define KEY_8 0x25 // Keyboard 8 and *
|
||||
#define KEY_9 0x26 // Keyboard 9 and (
|
||||
#define KEY_0 0x27 // Keyboard 0 and )
|
||||
|
||||
#define KEY_ENTER 0x28 // Keyboard Return (ENTER)
|
||||
#define KEY_ESC 0x29 // Keyboard ESCAPE
|
||||
#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
|
||||
#define KEY_TAB 0x2b // Keyboard Tab
|
||||
#define KEY_SPACE 0x2c // Keyboard Spacebar
|
||||
#define KEY_MINUS 0x2d // Keyboard - and _
|
||||
#define KEY_EQUAL 0x2e // Keyboard = and +
|
||||
#define KEY_LEFTBRACE 0x2f // Keyboard [ and {
|
||||
#define KEY_RIGHTBRACE 0x30 // Keyboard ] and }
|
||||
#define KEY_BACKSLASH 0x31 // Keyboard \ and |
|
||||
#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
|
||||
#define KEY_SEMICOLON 0x33 // Keyboard ; and :
|
||||
#define KEY_APOSTROPHE 0x34 // Keyboard ' and "
|
||||
#define KEY_GRAVE 0x35 // Keyboard ` and ~
|
||||
#define KEY_COMMA 0x36 // Keyboard , and <
|
||||
#define KEY_DOT 0x37 // Keyboard . and >
|
||||
#define KEY_SLASH 0x38 // Keyboard / and ?
|
||||
#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
|
||||
|
||||
#define KEY_F1 0x3a // Keyboard F1
|
||||
#define KEY_F2 0x3b // Keyboard F2
|
||||
#define KEY_F3 0x3c // Keyboard F3
|
||||
#define KEY_F4 0x3d // Keyboard F4
|
||||
#define KEY_F5 0x3e // Keyboard F5
|
||||
#define KEY_F6 0x3f // Keyboard F6
|
||||
#define KEY_F7 0x40 // Keyboard F7
|
||||
#define KEY_F8 0x41 // Keyboard F8
|
||||
#define KEY_F9 0x42 // Keyboard F9
|
||||
#define KEY_F10 0x43 // Keyboard F10
|
||||
#define KEY_F11 0x44 // Keyboard F11
|
||||
#define KEY_F12 0x45 // Keyboard F12
|
||||
|
||||
#define KEY_SYSRQ 0x46 // Keyboard Print Screen
|
||||
#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
|
||||
#define KEY_PAUSE 0x48 // Keyboard Pause
|
||||
#define KEY_INSERT 0x49 // Keyboard Insert
|
||||
#define KEY_HOME 0x4a // Keyboard Home
|
||||
#define KEY_PAGEUP 0x4b // Keyboard Page Up
|
||||
#define KEY_DELETE 0x4c // Keyboard Delete Forward
|
||||
#define KEY_END 0x4d // Keyboard End
|
||||
#define KEY_PAGEDOWN 0x4e // Keyboard Page Down
|
||||
#define KEY_RIGHT 0x4f // Keyboard Right Arrow
|
||||
#define KEY_LEFT 0x50 // Keyboard Left Arrow
|
||||
#define KEY_DOWN 0x51 // Keyboard Down Arrow
|
||||
#define KEY_UP 0x52 // Keyboard Up Arrow
|
||||
|
||||
#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
|
||||
#define KEY_KPSLASH 0x54 // Keypad /
|
||||
#define KEY_KPASTERISK 0x55 // Keypad *
|
||||
#define KEY_KPMINUS 0x56 // Keypad -
|
||||
#define KEY_KPPLUS 0x57 // Keypad +
|
||||
#define KEY_KPENTER 0x58 // Keypad ENTER
|
||||
#define KEY_KP1 0x59 // Keypad 1 and End
|
||||
#define KEY_KP2 0x5a // Keypad 2 and Down Arrow
|
||||
#define KEY_KP3 0x5b // Keypad 3 and PageDn
|
||||
#define KEY_KP4 0x5c // Keypad 4 and Left Arrow
|
||||
#define KEY_KP5 0x5d // Keypad 5
|
||||
#define KEY_KP6 0x5e // Keypad 6 and Right Arrow
|
||||
#define KEY_KP7 0x5f // Keypad 7 and Home
|
||||
#define KEY_KP8 0x60 // Keypad 8 and Up Arrow
|
||||
#define KEY_KP9 0x61 // Keypad 9 and Page Up
|
||||
#define KEY_KP0 0x62 // Keypad 0 and Insert
|
||||
#define KEY_KPDOT 0x63 // Keypad . and Delete
|
||||
|
||||
#define KEY_102ND 0x64 // Keyboard Non-US \ and |
|
||||
#define KEY_COMPOSE 0x65 // Keyboard Application
|
||||
#define KEY_POWER 0x66 // Keyboard Power
|
||||
#define KEY_KPEQUAL 0x67 // Keypad =
|
||||
|
||||
#define KEY_F13 0x68 // Keyboard F13
|
||||
#define KEY_F14 0x69 // Keyboard F14
|
||||
#define KEY_F15 0x6a // Keyboard F15
|
||||
#define KEY_F16 0x6b // Keyboard F16
|
||||
#define KEY_F17 0x6c // Keyboard F17
|
||||
#define KEY_F18 0x6d // Keyboard F18
|
||||
#define KEY_F19 0x6e // Keyboard F19
|
||||
#define KEY_F20 0x6f // Keyboard F20
|
||||
#define KEY_F21 0x70 // Keyboard F21
|
||||
#define KEY_F22 0x71 // Keyboard F22
|
||||
#define KEY_F23 0x72 // Keyboard F23
|
||||
#define KEY_F24 0x73 // Keyboard F24
|
||||
|
||||
#define KEY_OPEN 0x74 // Keyboard Execute
|
||||
#define KEY_HELP 0x75 // Keyboard Help
|
||||
#define KEY_PROPS 0x76 // Keyboard Menu
|
||||
#define KEY_FRONT 0x77 // Keyboard Select
|
||||
#define KEY_STOP 0x78 // Keyboard Stop
|
||||
#define KEY_AGAIN 0x79 // Keyboard Again
|
||||
#define KEY_UNDO 0x7a // Keyboard Undo
|
||||
#define KEY_CUT 0x7b // Keyboard Cut
|
||||
#define KEY_COPY 0x7c // Keyboard Copy
|
||||
#define KEY_PASTE 0x7d // Keyboard Paste
|
||||
#define KEY_FIND 0x7e // Keyboard Find
|
||||
#define KEY_MUTE 0x7f // Keyboard Mute
|
||||
#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up
|
||||
#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
|
||||
// 0x82 Keyboard Locking Caps Lock
|
||||
// 0x83 Keyboard Locking Num Lock
|
||||
// 0x84 Keyboard Locking Scroll Lock
|
||||
#define KEY_KPCOMMA 0x85 // Keypad Comma
|
||||
// 0x86 Keypad Equal Sign
|
||||
#define KEY_RO 0x87 // Keyboard International1
|
||||
#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
|
||||
#define KEY_YEN 0x89 // Keyboard International3
|
||||
#define KEY_HENKAN 0x8a // Keyboard International4
|
||||
#define KEY_MUHENKAN 0x8b // Keyboard International5
|
||||
#define KEY_KPJPCOMMA 0x8c // Keyboard International6
|
||||
// 0x8d Keyboard International7
|
||||
// 0x8e Keyboard International8
|
||||
// 0x8f Keyboard International9
|
||||
#define KEY_HANGEUL 0x90 // Keyboard LANG1
|
||||
#define KEY_HANJA 0x91 // Keyboard LANG2
|
||||
#define KEY_KATAKANA 0x92 // Keyboard LANG3
|
||||
#define KEY_HIRAGANA 0x93 // Keyboard LANG4
|
||||
#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
|
||||
// 0x95 Keyboard LANG6
|
||||
// 0x96 Keyboard LANG7
|
||||
// 0x97 Keyboard LANG8
|
||||
// 0x98 Keyboard LANG9
|
||||
// 0x99 Keyboard Alternate Erase
|
||||
// 0x9a Keyboard SysReq/Attention
|
||||
// 0x9b Keyboard Cancel
|
||||
// 0x9c Keyboard Clear
|
||||
// 0x9d Keyboard Prior
|
||||
// 0x9e Keyboard Return
|
||||
// 0x9f Keyboard Separator
|
||||
// 0xa0 Keyboard Out
|
||||
// 0xa1 Keyboard Oper
|
||||
// 0xa2 Keyboard Clear/Again
|
||||
// 0xa3 Keyboard CrSel/Props
|
||||
// 0xa4 Keyboard ExSel
|
||||
|
||||
// 0xb0 Keypad 00
|
||||
// 0xb1 Keypad 000
|
||||
// 0xb2 Thousands Separator
|
||||
// 0xb3 Decimal Separator
|
||||
// 0xb4 Currency Unit
|
||||
// 0xb5 Currency Sub-unit
|
||||
#define KEY_KPLEFTPAREN 0xb6 // Keypad (
|
||||
#define KEY_KPRIGHTPAREN 0xb7 // Keypad )
|
||||
// 0xb8 Keypad {
|
||||
// 0xb9 Keypad }
|
||||
// 0xba Keypad Tab
|
||||
// 0xbb Keypad Backspace
|
||||
// 0xbc Keypad A
|
||||
// 0xbd Keypad B
|
||||
// 0xbe Keypad C
|
||||
// 0xbf Keypad D
|
||||
// 0xc0 Keypad E
|
||||
// 0xc1 Keypad F
|
||||
// 0xc2 Keypad XOR
|
||||
// 0xc3 Keypad ^
|
||||
// 0xc4 Keypad %
|
||||
// 0xc5 Keypad <
|
||||
// 0xc6 Keypad >
|
||||
// 0xc7 Keypad &
|
||||
// 0xc8 Keypad &&
|
||||
// 0xc9 Keypad |
|
||||
// 0xca Keypad ||
|
||||
// 0xcb Keypad :
|
||||
// 0xcc Keypad #
|
||||
// 0xcd Keypad Space
|
||||
// 0xce Keypad @
|
||||
// 0xcf Keypad !
|
||||
// 0xd0 Keypad Memory Store
|
||||
// 0xd1 Keypad Memory Recall
|
||||
// 0xd2 Keypad Memory Clear
|
||||
// 0xd3 Keypad Memory Add
|
||||
// 0xd4 Keypad Memory Subtract
|
||||
// 0xd5 Keypad Memory Multiply
|
||||
// 0xd6 Keypad Memory Divide
|
||||
// 0xd7 Keypad +/-
|
||||
// 0xd8 Keypad Clear
|
||||
// 0xd9 Keypad Clear Entry
|
||||
// 0xda Keypad Binary
|
||||
// 0xdb Keypad Octal
|
||||
// 0xdc Keypad Decimal
|
||||
// 0xdd Keypad Hexadecimal
|
||||
|
||||
#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control
|
||||
#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
|
||||
#define KEY_LEFTALT 0xe2 // Keyboard Left Alt
|
||||
#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI
|
||||
#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
|
||||
#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
|
||||
#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt
|
||||
#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
|
||||
|
||||
#define KEY_MEDIA_PLAYPAUSE 0xe8
|
||||
#define KEY_MEDIA_STOPCD 0xe9
|
||||
#define KEY_MEDIA_PREVIOUSSONG 0xea
|
||||
#define KEY_MEDIA_NEXTSONG 0xeb
|
||||
#define KEY_MEDIA_EJECTCD 0xec
|
||||
#define KEY_MEDIA_VOLUMEUP 0xed
|
||||
#define KEY_MEDIA_VOLUMEDOWN 0xee
|
||||
#define KEY_MEDIA_MUTE 0xef
|
||||
#define KEY_MEDIA_WWW 0xf0
|
||||
#define KEY_MEDIA_BACK 0xf1
|
||||
#define KEY_MEDIA_FORWARD 0xf2
|
||||
#define KEY_MEDIA_STOP 0xf3
|
||||
#define KEY_MEDIA_FIND 0xf4
|
||||
#define KEY_MEDIA_SCROLLUP 0xf5
|
||||
#define KEY_MEDIA_SCROLLDOWN 0xf6
|
||||
#define KEY_MEDIA_EDIT 0xf7
|
||||
#define KEY_MEDIA_SLEEP 0xf8
|
||||
#define KEY_MEDIA_COFFEE 0xf9
|
||||
#define KEY_MEDIA_REFRESH 0xfa
|
||||
#define KEY_MEDIA_CALC 0xfb
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,177 @@
|
||||
# Bibliothèque ADB pour Framework Arduino
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
> **Note de développement** : Cette bibliothèque est implémentée pour le framework Arduino et actuellement optimisée principalement pour la plateforme STM32. Le support pour d'autres plateformes Arduino est en cours de développement.
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
La bibliothèque ADB est une implémentation complète du protocole Apple Desktop Bus (ADB) en C++ pour le framework Arduino, fonctionnant sur diverses cartes comme STM32, ESP32, Arduino AVR et Teensy. Elle permet d'interfacer facilement des périphériques Apple vintage (claviers, souris) avec des systèmes modernes.
|
||||
|
||||
## Fonctionnalités clés
|
||||
|
||||
- 🔌 **Compatible avec plusieurs plateformes** : STM32 (primaire), Arduino, ESP32, Teensy (en cours de développement)
|
||||
- 🧩 **API unifiée** : même interface de programmation quelle que soit la plateforme
|
||||
- ⌨️ **Support complet des claviers ADB** : lecture des touches, gestion des modificateurs, contrôle des LEDs
|
||||
- 🖱️ **Support complet des souris ADB** : lecture des mouvements et des boutons
|
||||
- 🔄 **Conversion ADB vers HID** : mappage des codes de touches ADB vers les codes HID standard
|
||||
- 📊 **Détection automatique des périphériques** : avec gestion des erreurs robuste
|
||||
- 🛠️ **Utilitaires avancés** : fonctions d'aide au développement et débogage
|
||||
- 📝 **Documentation complète** : commentaires explicites et exemples documentés
|
||||
|
||||
## Plateformes Arduino supportées
|
||||
|
||||
| Plateforme | Pin par défaut | Testé sur | Statut |
|
||||
|------------|---------------|----------|--------|
|
||||
| STM32 (Arduino Core) | PB4 | STM32F103, Bluepill, STM32F401, STM32F411 | ✅ Testé et stable |
|
||||
| Arduino AVR | 2 | Uno, Mega | ⚠️ Support préliminaire |
|
||||
| ESP32 (Arduino Core) | 21 | ESP32-WROOM, ESP32-WROVER | ⚠️ En développement |
|
||||
| Teensy (Arduino Core) | 3 | Teensy 3.2, 4.0 | ⚠️ En développement |
|
||||
| Autres cartes Arduino | 2 | Diverses | ⛔ Non testé |
|
||||
|
||||
## Installation
|
||||
|
||||
### Pour l'IDE Arduino
|
||||
1. Téléchargez la bibliothèque depuis le dépôt
|
||||
2. Extrayez les fichiers dans le dossier `libraries` de votre IDE Arduino
|
||||
3. Redémarrez l'IDE Arduino
|
||||
4. La bibliothèque est maintenant disponible dans "Croquis > Inclure une bibliothèque"
|
||||
|
||||
### Pour PlatformIO
|
||||
1. Ajoutez la dépendance dans votre `platformio.ini`:
|
||||
```ini
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
```
|
||||
2. Ou installez-la manuellement dans le dossier `lib/` de votre projet
|
||||
|
||||
#### Configuration exemple pour STM32 (platformio.ini)
|
||||
```ini
|
||||
[env:bluepill_f103c8]
|
||||
platform = ststm32
|
||||
board = bluepill_f103c8
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
upload_protocol = stlink
|
||||
monitor_speed = 115200
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
|
||||
-D USBCON
|
||||
-D USB_MANUFACTURER="\"L'électron rare\""
|
||||
-D USB_PRODUCT="\"ADB2USB HID\""
|
||||
```
|
||||
|
||||
#### Configuration exemple pour ESP32 (platformio.ini)
|
||||
```ini
|
||||
[env:esp32dev]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
monitor_speed = 115200
|
||||
```
|
||||
|
||||
## Utilisation basique dans le framework Arduino
|
||||
|
||||
```cpp
|
||||
#include <Arduino.h>
|
||||
#include "adb.h"
|
||||
|
||||
// Configuration selon la carte Arduino
|
||||
#if defined(ARDUINO_ARCH_STM32)
|
||||
#define ADB_PIN PB4
|
||||
#else
|
||||
#define ADB_PIN 2 // Arduino, ESP32, etc.
|
||||
#endif
|
||||
|
||||
// Initialisation des objets
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
adb.init();
|
||||
Serial.println("ADB Initialized");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Lecture du clavier via Arduino
|
||||
bool error = false;
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (!error && keyPress.data.key0 != 0) {
|
||||
Serial.print("Key: 0x");
|
||||
Serial.println(keyPress.data.key0, HEX);
|
||||
}
|
||||
|
||||
// Lecture de la souris
|
||||
error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (!error) {
|
||||
int8_t xMove = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t yMove = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
// Traiter les données de mouvement...
|
||||
}
|
||||
|
||||
delay(20); // Intervalle de polling typique pour Arduino
|
||||
}
|
||||
```
|
||||
|
||||
## Exemples Arduino inclus
|
||||
|
||||
La bibliothèque est fournie avec plusieurs exemples pratiques pour Arduino IDE et PlatformIO :
|
||||
|
||||
- **basic_keyboard** : Utilisation simple d'un clavier ADB
|
||||
- **basic_mouse** : Utilisation simple d'une souris ADB
|
||||
- **multiplatform_basic** : Exemple multiplateforme (avec détection automatique)
|
||||
- **keyboard_mouse_example** : Utilisation simultanée d'un clavier et d'une souris
|
||||
- **multiplatform_event_handler** : Gestionnaire d'événements avancé
|
||||
- **usb_hid_stm32** : Conversion ADB vers USB HID (STM32 uniquement)
|
||||
- **multiplatform_device_info** : Scanner de périphériques ADB
|
||||
- **platformio_stm32_example** : Exemple complet pour PlatformIO avec STM32
|
||||
- **platformio_esp32_example** : Exemple pour PlatformIO avec ESP32
|
||||
|
||||
## Structure du projet
|
||||
|
||||
## Crédits et contributions
|
||||
|
||||
### Auteurs
|
||||
- **Clément SAILLANT** - L'électron rare - *Développeur principal*
|
||||
- **Szymon Łopaciuk** - *Travail initial et inspiration* - [stm32-adb2usb](https://github.com/szymonlopaciuk/stm32-adb2usb)
|
||||
|
||||
### Remerciements particuliers
|
||||
- **Projet TMK** - Pour la documentation et le travail sur la conversion ADB-USB
|
||||
- **Apple Developer Archives** - Pour la documentation technique sur le protocole ADB
|
||||
- **Communauté r/VintageApple** - Pour le support et les tests
|
||||
|
||||
### Testeurs
|
||||
- L'équipe de L'électron rare
|
||||
- Utilisateurs du forum STM32duino
|
||||
- Membres de la communauté RetroComputing
|
||||
|
||||
## Historique des versions
|
||||
|
||||
- **1.0.0-beta** (Janvier 2025)
|
||||
- Version initiale de la bibliothèque
|
||||
- Support complet pour STM32
|
||||
- Support préliminaire pour d'autres plateformes
|
||||
|
||||
## À venir
|
||||
|
||||
- Support complet pour Arduino, ESP32, et Teensy
|
||||
- Meilleure gestion de l'alimentation
|
||||
- Support pour des périphériques ADB plus exotiques
|
||||
- Interface graphique de configuration et diagnostic
|
||||
|
||||
## Licence
|
||||
|
||||
Ce projet est sous licence GNU GPL v3. Voir le fichier LICENSE pour plus de détails.
|
||||
|
||||
---
|
||||
|
||||
Conçu avec ❤️ pour donner une nouvelle vie aux périphériques Apple vintage.
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file auto_platform_detect.cpp
|
||||
* @brief Exemple avec détection automatique de la plateforme matérielle
|
||||
*
|
||||
* Ce fichier démontre comment la bibliothèque ADB peut être utilisée avec
|
||||
* une détection automatique de la plateforme matérielle sous-jacente.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "adb.h"
|
||||
|
||||
// Détection automatique de plateforme et configuration de la broche
|
||||
#if defined(ARDUINO_ARCH_AVR)
|
||||
#define PLATFORM_NAME "Arduino AVR"
|
||||
#define ADB_PIN 2
|
||||
#elif defined(ARDUINO_ARCH_SAM)
|
||||
#define PLATFORM_NAME "Arduino SAM"
|
||||
#define ADB_PIN 2
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#define PLATFORM_NAME "Arduino SAMD"
|
||||
#define ADB_PIN 2
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#define PLATFORM_NAME "STM32"
|
||||
#define ADB_PIN PB4
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#define PLATFORM_NAME "ESP32"
|
||||
#define ADB_PIN 21
|
||||
#elif defined(TEENSYDUINO)
|
||||
#define PLATFORM_NAME "Teensy"
|
||||
#define ADB_PIN 3
|
||||
#else
|
||||
#define PLATFORM_NAME "Unknown Platform"
|
||||
#define ADB_PIN 2
|
||||
#warning "Plateforme non reconnue, utilisation de la pin 2 par défaut"
|
||||
#endif
|
||||
|
||||
// Paramètres communs
|
||||
constexpr uint32_t SERIAL_BAUD = 115200;
|
||||
constexpr uint16_t POLL_INTERVAL = 250; // ms
|
||||
|
||||
// Initialisation des objets
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
void setup() {
|
||||
// Configuration de la communication série
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
while (!Serial && millis() < 3000); // Attente avec timeout
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
|
||||
Serial.println(F("=== ADB Multiplateforme ==="));
|
||||
Serial.print(F("Plateforme détectée: "));
|
||||
Serial.println(F(PLATFORM_NAME));
|
||||
Serial.print(F("Utilisation de la broche: "));
|
||||
Serial.println(ADB_PIN);
|
||||
Serial.println(F("========================"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Affichage des informations périphériques ADB
|
||||
utils.printKeyboardStatus();
|
||||
utils.printMouseStatus();
|
||||
|
||||
Serial.println(F("------------------------"));
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @file multiplatform_basic.cpp
|
||||
* @brief Exemple de base pour l'utilisation de la bibliothèque ADB sur plusieurs plateformes
|
||||
*
|
||||
* Cet exemple montre comment utiliser la bibliothèque ADB sur différentes plateformes
|
||||
* en modifiant simplement la définition de la plateforme et la broche utilisée.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "adb.h"
|
||||
|
||||
// Définir la plateforme (décommenter une seule ligne)
|
||||
#define PLATFORM_ARDUINO
|
||||
// #define PLATFORM_STM32
|
||||
// #define PLATFORM_ESP32
|
||||
// #define PLATFORM_TEENSY
|
||||
|
||||
// Configuration de la broche ADB selon la plateforme
|
||||
#ifdef PLATFORM_ARDUINO
|
||||
#define ADB_PIN 2
|
||||
#define PLATFORM_NAME "Arduino"
|
||||
#elif defined(PLATFORM_STM32)
|
||||
#define ADB_PIN PB4
|
||||
#define PLATFORM_NAME "STM32"
|
||||
#elif defined(PLATFORM_ESP32)
|
||||
#define ADB_PIN 21
|
||||
#define PLATFORM_NAME "ESP32"
|
||||
#elif defined(PLATFORM_TEENSY)
|
||||
#define ADB_PIN 3
|
||||
#define PLATFORM_NAME "Teensy"
|
||||
#else
|
||||
#error "Aucune plateforme définie! Décommentez une définition de plateforme."
|
||||
#endif
|
||||
|
||||
// Paramètres communs
|
||||
constexpr uint32_t SERIAL_BAUD = 115200;
|
||||
constexpr uint16_t POLL_INTERVAL = 250; // ms
|
||||
|
||||
// Initialisation des objets
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
|
||||
void setup() {
|
||||
// Configuration de la communication série
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
while (!Serial && millis() < 3000); // Attente du port série avec timeout
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
|
||||
Serial.print(F("ADB Initialized on "));
|
||||
Serial.println(F(PLATFORM_NAME));
|
||||
Serial.println(F("Bibliothèque ADB multiplateforme"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
bool error = false;
|
||||
|
||||
// Tentative de lecture du clavier
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (!error && (keyPress.data.key0 != 0)) {
|
||||
Serial.print(F("Keyboard - Key: 0x"));
|
||||
Serial.print(keyPress.data.key0, HEX);
|
||||
Serial.print(F(" ("));
|
||||
Serial.print(keyPress.data.released0 ? F("Released") : F("Pressed"));
|
||||
Serial.println(F(")"));
|
||||
}
|
||||
|
||||
// Tentative de lecture de la souris
|
||||
error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (!error) {
|
||||
int8_t xMove = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t yMove = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
|
||||
if (xMove != 0 || yMove != 0 || mouseData.data.button) {
|
||||
Serial.print(F("Mouse - X: "));
|
||||
Serial.print(xMove);
|
||||
Serial.print(F(", Y: "));
|
||||
Serial.print(yMove);
|
||||
Serial.print(F(", Button: "));
|
||||
Serial.println(mouseData.data.button ? F("Pressed") : F("Released"));
|
||||
}
|
||||
}
|
||||
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* @file multiplatform_device_info.cpp
|
||||
* @brief Exemple de récupération d'informations sur les périphériques ADB
|
||||
*
|
||||
* Ce programme permet de détecter et d'afficher des informations sur les périphériques
|
||||
* ADB connectés. Il est compatible avec toutes les plateformes supportées.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "adb.h"
|
||||
|
||||
// Configuration multiplateforme
|
||||
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
|
||||
#define ADB_PIN 2
|
||||
#define PLATFORM_NAME "Arduino"
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#define ADB_PIN PB4
|
||||
#define PLATFORM_NAME "STM32"
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#define ADB_PIN 21
|
||||
#define PLATFORM_NAME "ESP32"
|
||||
#elif defined(TEENSYDUINO)
|
||||
#define ADB_PIN 3
|
||||
#define PLATFORM_NAME "Teensy"
|
||||
#else
|
||||
#define ADB_PIN 2
|
||||
#define PLATFORM_NAME "Plateforme inconnue"
|
||||
#endif
|
||||
|
||||
// Adresses ADB à tester
|
||||
constexpr uint8_t DEVICE_ADDRESSES[] = {2, 3, 4, 5, 6, 7};
|
||||
constexpr uint8_t NUM_ADDRESSES = sizeof(DEVICE_ADDRESSES) / sizeof(DEVICE_ADDRESSES[0]);
|
||||
|
||||
// Initialisation des objets
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
|
||||
void setup() {
|
||||
// Configuration de la communication série
|
||||
Serial.begin(115200);
|
||||
while (!Serial && millis() < 3000);
|
||||
|
||||
Serial.println(F("=== Scanner de périphériques ADB ==="));
|
||||
Serial.print(F("Plateforme: "));
|
||||
Serial.print(F(PLATFORM_NAME));
|
||||
Serial.print(F(", Broche ADB: "));
|
||||
Serial.println(ADB_PIN);
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
delay(500); // Attendre que le bus se stabilise
|
||||
|
||||
Serial.println(F("Recherche de périphériques ADB..."));
|
||||
Serial.println(F("--------------------------------"));
|
||||
|
||||
// Tentative de détection de périphériques
|
||||
bool deviceFound = false;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_ADDRESSES; i++) {
|
||||
uint8_t addr = DEVICE_ADDRESSES[i];
|
||||
bool error = false;
|
||||
bool devicePresent = false;
|
||||
|
||||
Serial.print(F("Adresse 0x"));
|
||||
Serial.print(addr, HEX);
|
||||
Serial.print(F(" : "));
|
||||
|
||||
// Essai de lecture du registre 3
|
||||
adb_data<adb_register3> reg3 = {0};
|
||||
adb.writeCommand(ADBProtocol::CMD_TALK | ADBProtocol::ADDRESS(addr) | ADBProtocol::REGISTER(3));
|
||||
adb.waitTLT(true);
|
||||
bool success = adb.readDataPacket(®3.raw, 16);
|
||||
|
||||
if (success) {
|
||||
Serial.println(F("Périphérique détecté!"));
|
||||
Serial.print(F(" Handler ID: 0x"));
|
||||
Serial.println(reg3.data.device_handler_id, HEX);
|
||||
|
||||
// Identification du type de périphérique
|
||||
if (addr == ADDR_KEYBOARD) {
|
||||
Serial.println(F(" Type: Clavier ADB"));
|
||||
// Tentative de lecture des modificateurs
|
||||
bool keyError = false;
|
||||
auto modifiers = devices.keyboardReadModifiers(&keyError);
|
||||
if (!keyError) {
|
||||
Serial.println(F(" État Caps Lock: ") +
|
||||
String(modifiers.data.caps_lock ? "Activé" : "Désactivé"));
|
||||
}
|
||||
}
|
||||
else if (addr == ADDR_MOUSE) {
|
||||
Serial.println(F(" Type: Souris ADB"));
|
||||
}
|
||||
else {
|
||||
Serial.print(F(" Type: Autre périphérique ADB ("));
|
||||
Serial.print(addr);
|
||||
Serial.println(F(")"));
|
||||
}
|
||||
|
||||
deviceFound = true;
|
||||
} else {
|
||||
Serial.println(F("Aucun périphérique"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!deviceFound) {
|
||||
Serial.println(F("Aucun périphérique ADB détecté."));
|
||||
Serial.println(F("Vérifiez les connexions et l'alimentation."));
|
||||
}
|
||||
|
||||
Serial.println(F("--------------------------------"));
|
||||
Serial.println(F("Scan terminé. Surveillance active..."));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Surveillance continue des périphériques
|
||||
bool keyboardError = false;
|
||||
bool mouseError = false;
|
||||
static bool keyboardPresent = false;
|
||||
static bool mousePresent = false;
|
||||
|
||||
// Vérification du clavier
|
||||
auto keyPress = devices.keyboardReadKeyPress(&keyboardError);
|
||||
if (!keyboardError) {
|
||||
if (!keyboardPresent) {
|
||||
Serial.println(F("Clavier ADB connecté"));
|
||||
keyboardPresent = true;
|
||||
}
|
||||
|
||||
// Affichage des touches pressées
|
||||
if (keyPress.data.key0 != 0 && !keyPress.data.released0) {
|
||||
Serial.print(F("Touche: 0x"));
|
||||
Serial.println(keyPress.data.key0, HEX);
|
||||
}
|
||||
} else if (keyboardPresent) {
|
||||
Serial.println(F("Clavier ADB déconnecté"));
|
||||
keyboardPresent = false;
|
||||
}
|
||||
|
||||
// Vérification de la souris
|
||||
auto mouseData = devices.mouseReadData(&mouseError);
|
||||
if (!mouseError) {
|
||||
if (!mousePresent) {
|
||||
Serial.println(F("Souris ADB connectée"));
|
||||
mousePresent = true;
|
||||
}
|
||||
|
||||
// Affichage des mouvements significatifs
|
||||
int8_t xMove = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t yMove = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
|
||||
if (abs(xMove) > 5 || abs(yMove) > 5) {
|
||||
Serial.print(F("Mouvement: X="));
|
||||
Serial.print(xMove);
|
||||
Serial.print(F(", Y="));
|
||||
Serial.println(yMove);
|
||||
}
|
||||
} else if (mousePresent) {
|
||||
Serial.println(F("Souris ADB déconnectée"));
|
||||
mousePresent = false;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @file multiplatform_event_handler.cpp
|
||||
* @brief Gestionnaire d'événements ADB multiplateforme
|
||||
*
|
||||
* Cet exemple implémente un gestionnaire d'événements avancé pour les périphériques ADB.
|
||||
* Il est compatible avec toutes les plateformes prises en charge et montre comment traiter
|
||||
* les événements du clavier et de la souris de manière événementielle.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "adb.h"
|
||||
|
||||
// Configuration spécifique à la plateforme
|
||||
#if defined(ARDUINO_ARCH_AVR)
|
||||
#define ADB_PIN 2
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#define ADB_PIN PB4
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#define ADB_PIN 21
|
||||
#elif defined(TEENSYDUINO)
|
||||
#define ADB_PIN 3
|
||||
#else
|
||||
#define ADB_PIN 2
|
||||
#endif
|
||||
|
||||
// Paramètres communs
|
||||
constexpr uint32_t SERIAL_BAUD = 115200;
|
||||
constexpr uint16_t POLL_INTERVAL = 20; // Intervalle court pour la réactivité
|
||||
|
||||
// Initialisation des objets
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
|
||||
// État du système
|
||||
uint8_t lastKeys[2] = {0, 0};
|
||||
bool lastReleased[2] = {true, true};
|
||||
int8_t lastX = 0, lastY = 0;
|
||||
bool lastButton = false;
|
||||
|
||||
// Fonctions de traitement des événements
|
||||
void onKeyPressed(uint8_t keyCode) {
|
||||
Serial.print(F("Touche pressée: 0x"));
|
||||
Serial.print(keyCode, HEX);
|
||||
|
||||
// Affichage du code HID équivalent si disponible
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyCode);
|
||||
if (hidCode != KEY_NONE) {
|
||||
Serial.print(F(" (HID: 0x"));
|
||||
Serial.print(hidCode, HEX);
|
||||
Serial.print(F(")"));
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void onKeyReleased(uint8_t keyCode) {
|
||||
Serial.print(F("Touche relâchée: 0x"));
|
||||
Serial.println(keyCode, HEX);
|
||||
}
|
||||
|
||||
void onMouseMove(int8_t deltaX, int8_t deltaY) {
|
||||
Serial.print(F("Souris - Mouvement: ("));
|
||||
Serial.print(deltaX);
|
||||
Serial.print(F(", "));
|
||||
Serial.print(deltaY);
|
||||
Serial.println(F(")"));
|
||||
}
|
||||
|
||||
void onMouseButtonChange(bool isPressed) {
|
||||
Serial.print(F("Souris - Bouton: "));
|
||||
Serial.println(isPressed ? F("Pressé") : F("Relâché"));
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Configuration de la communication série
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
while (!Serial && millis() < 3000);
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
Serial.println(F("Gestionnaire d'événements ADB multiplateforme initialisé"));
|
||||
Serial.println(F("En attente d'événements..."));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Traitement des événements clavier
|
||||
bool error = false;
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
|
||||
if (!error) {
|
||||
// Vérification de la première touche
|
||||
if (keyPress.data.key0 != lastKeys[0] || keyPress.data.released0 != lastReleased[0]) {
|
||||
if (keyPress.data.key0 != 0) {
|
||||
if (!keyPress.data.released0 && lastReleased[0]) {
|
||||
onKeyPressed(keyPress.data.key0);
|
||||
} else if (keyPress.data.released0 && !lastReleased[0]) {
|
||||
onKeyReleased(keyPress.data.key0);
|
||||
}
|
||||
}
|
||||
lastKeys[0] = keyPress.data.key0;
|
||||
lastReleased[0] = keyPress.data.released0;
|
||||
}
|
||||
|
||||
// Vérification de la seconde touche
|
||||
if (keyPress.data.key1 != lastKeys[1] || keyPress.data.released1 != lastReleased[1]) {
|
||||
if (keyPress.data.key1 != 0) {
|
||||
if (!keyPress.data.released1 && lastReleased[1]) {
|
||||
onKeyPressed(keyPress.data.key1);
|
||||
} else if (keyPress.data.released1 && !lastReleased[1]) {
|
||||
onKeyReleased(keyPress.data.key1);
|
||||
}
|
||||
}
|
||||
lastKeys[1] = keyPress.data.key1;
|
||||
lastReleased[1] = keyPress.data.released1;
|
||||
}
|
||||
}
|
||||
|
||||
// Traitement des événements souris
|
||||
error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
|
||||
if (!error) {
|
||||
int8_t xMove = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t yMove = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
|
||||
// Détection du mouvement
|
||||
if (xMove != 0 || yMove != 0) {
|
||||
onMouseMove(xMove, yMove);
|
||||
}
|
||||
|
||||
// Détection du changement d'état du bouton
|
||||
if (mouseData.data.button != lastButton) {
|
||||
onMouseButtonChange(mouseData.data.button);
|
||||
lastButton = mouseData.data.button;
|
||||
}
|
||||
}
|
||||
|
||||
// Fréquence de polling élevée pour une bonne réactivité
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @file platform_aware_example.cpp
|
||||
* @brief Exemple utilisant la détection automatique de plateforme
|
||||
*
|
||||
* Cet exemple démontre l'utilisation du fichier ADBPlatform.h pour
|
||||
* créer un code qui s'adapte automatiquement à la plateforme cible.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "adb.h"
|
||||
#include "ADBPlatform.h"
|
||||
|
||||
// Utilisation des paramètres de la plateforme
|
||||
ADB adb(ADB_DEFAULT_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
void setup() {
|
||||
// Configuration adaptée à la plateforme
|
||||
Serial.begin(ADB_SERIAL_BAUD);
|
||||
while (!Serial && millis() < 3000);
|
||||
|
||||
adb.init();
|
||||
|
||||
// Affichage des informations de plateforme
|
||||
printPlatformInfo();
|
||||
Serial.println(F("Initialisation ADB réussie"));
|
||||
|
||||
// Configuration spécifique selon la plateforme
|
||||
#ifdef ADB_PLATFORM_ESP32
|
||||
// Code spécifique pour ESP32
|
||||
Serial.println(F("Configuration spécifique pour ESP32 appliquée"));
|
||||
#elif defined(ADB_PLATFORM_STM32)
|
||||
// Code spécifique pour STM32
|
||||
Serial.println(F("Configuration spécifique pour STM32 appliquée"));
|
||||
#elif defined(ADB_PLATFORM_AVR)
|
||||
// Code spécifique pour Arduino AVR
|
||||
Serial.println(F("Mode économie de mémoire activé pour AVR"));
|
||||
#endif
|
||||
|
||||
Serial.println(F("Prêt à recevoir les événements ADB"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Lecture des périphériques
|
||||
utils.printKeyboardStatus();
|
||||
utils.printMouseStatus();
|
||||
|
||||
// Utilisation de l'intervalle adapté à la plateforme
|
||||
delay(ADB_POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
# 🔌 ADB2BLE Adapter pour ESP32
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
[](https://www.espressif.com/en/products/socs/esp32)
|
||||
[](https://www.arduino.cc/)
|
||||
[](https://platformio.org/)
|
||||
|
||||
> Ce projet permet de connecter des périphériques Apple Desktop Bus (ADB) comme les claviers et souris Apple vintage à des appareils modernes via Bluetooth Low Energy (BLE).
|
||||
|
||||
<p align="center">
|
||||
<img src="https://placeholder-image-url.com/adb2ble_adapter.jpg" alt="ADB2BLE Adapter" width="500">
|
||||
</p>
|
||||
|
||||
## 📋 Sommaire
|
||||
- [Fonctionnalités](#-fonctionnalités)
|
||||
- [Prérequis](#-prérequis)
|
||||
- [Schéma de connexion](#-schéma-de-connexion)
|
||||
- [Installation](#-installation)
|
||||
- [Utilisation](#-utilisation)
|
||||
- [Dépannage](#-dépannage)
|
||||
- [Détails techniques](#-détails-techniques)
|
||||
- [Licence et auteur](#-licence-et-auteur)
|
||||
- [Contributions](#-contributions)
|
||||
|
||||
## ✨ Fonctionnalités
|
||||
|
||||
- ✅ Conversion des signaux ADB vers BLE HID
|
||||
- ⌨️ Support des claviers ADB
|
||||
- 🖱️ Support des souris ADB
|
||||
- 🔍 Reconnaissance automatique des périphériques
|
||||
- 🔄 Reconnnexion automatique en cas de déconnexion
|
||||
- ⚡ Faible latence (50Hz de taux de rafraîchissement)
|
||||
|
||||
## 🛠️ Prérequis
|
||||
|
||||
### Matériel
|
||||
- ESP32 (testé sur ESP32-WROOM-32)
|
||||
- Adaptateur de niveau logique 5V/3.3V ou simple résistance de 1kΩ
|
||||
- Connecteur ADB (Mini-DIN 4 broches) ou adaptateur
|
||||
- Câbles et connecteurs
|
||||
|
||||
### Logiciel
|
||||
- PlatformIO
|
||||
- Arduino IDE (version 2.x ou supérieure)
|
||||
- Bibliothèques requises:
|
||||
- ADB (fournie dans ce dépôt)
|
||||
- Arduino BLE HID (intégrée à l'ESP32)
|
||||
|
||||
## 🔌 Schéma de connexion
|
||||
|
||||
┌─────────┐ ┌─────────┐
|
||||
│ │ │ │
|
||||
│ ESP32 │ │ ADB │
|
||||
│ │ │ │
|
||||
├─────────┤ ├─────────┤
|
||||
│ GPIO21 ├───[Résistance 1kΩ]────────────────┤ DATA │
|
||||
│ │ │ │ │
|
||||
│ │ │ │ │
|
||||
│ │ pull-up 4.7-10kΩ │ │
|
||||
│ │ │ │ │
|
||||
│ 3.3V ├───────────────────────────────────┤ +5V │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
│ GND ├───────────────────────────────────┤ GND │
|
||||
└─────────┘ └─────────┘
|
||||
|
||||
⚠️ **Attention**:
|
||||
- Vérifiez la tolérance de votre ESP32 avant de connecter directement l'alimentation 5V d'ADB.
|
||||
- **Important**: Une résistance de pull-up (entre 4.7kΩ et 10kΩ) doit être connectée entre la ligne DATA et +5V pour assurer le bon fonctionnement du bus ADB.
|
||||
|
||||
## 📥 Installation
|
||||
|
||||
1. Clonez ce dépôt:
|
||||
```bash
|
||||
git clone https://github.com/electron_rare/stm32-adb2usb.git
|
||||
cd stm32-adb2usb
|
||||
```
|
||||
|
||||
2. Ouvrez le projet dans PlatformIO IDE:
|
||||
- Sélectionnez "Open Project"
|
||||
- Naviguez jusqu'au dossier `stm32-adb2usb/lib/adb/examples/platformio_BLE_esp32_example`
|
||||
|
||||
3. Compilez et téléversez le projet sur votre ESP32:
|
||||
```bash
|
||||
pio run --target upload
|
||||
```
|
||||
|
||||
## 📝 Utilisation
|
||||
|
||||
1. Connectez vos périphériques ADB à l'adaptateur
|
||||
2. Allumez l'ESP32
|
||||
3. Recherchez le périphérique Bluetooth "ADB2BLE Adapter" depuis votre ordinateur ou appareil mobile
|
||||
4. Connectez-vous à l'adaptateur
|
||||
5. Utilisez vos périphériques ADB comme des périphériques Bluetooth standard
|
||||
|
||||
## ❓ Dépannage
|
||||
|
||||
| Problème | Solution |
|
||||
|----------|----------|
|
||||
| **Périphérique non détecté** | Vérifiez les connexions ADB et assurez-vous que les périphériques sont alimentés |
|
||||
| **Mouvement de souris irrégulier** | Ajustez les valeurs de conversion de mouvement dans le code |
|
||||
| **Touches de clavier incorrectes** | Consultez la correspondance des touches dans la bibliothèque ADB |
|
||||
|
||||
## 📊 Détails techniques
|
||||
|
||||
- **Taux de rafraîchissement**: 50Hz (configurable via `POLL_INTERVAL`)
|
||||
- **Consommation électrique**: ~30-50mA en fonctionnement normal
|
||||
- **Compatibilité**: La plupart des périphériques ADB standards
|
||||
|
||||
## 📄 Licence et auteur
|
||||
|
||||
Développé par **Clément SAILLANT** - *L'électron rare*
|
||||
|
||||
Copyright (C) 2025 Clément SAILLANT
|
||||
|
||||
Ce projet est sous licence [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## 👥 Contributions
|
||||
|
||||
Les contributions sont les bienvenues! N'hésitez pas à:
|
||||
|
||||
- Ouvrir des [issues](https://github.com/electron_rare/stm32-adb2usb/issues)
|
||||
- Soumettre des [pull requests](https://github.com/electron_rare/stm32-adb2usb/pulls)
|
||||
- Partager vos retours d'expérience
|
||||
@@ -0,0 +1,7 @@
|
||||
[env:esp32dev]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
electronrare/ADB
|
||||
monitor_speed = 115200
|
||||
@@ -0,0 +1,352 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @brief Exemple PlatformIO pour ESP32 avec la bibliothèque ADB
|
||||
*
|
||||
* Cet exemple montre comment utiliser la bibliothèque ADB dans un projet PlatformIO
|
||||
* avec l'ESP32 pour lire et traiter les données des périphériques ADB.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ADB.h>
|
||||
#include <ADBUtils.h>
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEHIDDevice.h>
|
||||
#include <HIDTypes.h>
|
||||
|
||||
// Configuration pour ESP32
|
||||
constexpr uint8_t ADB_PIN = 21; // Pin de données ADB
|
||||
constexpr uint16_t POLL_INTERVAL = 20; // 20ms (50Hz)
|
||||
constexpr const char* DEVICE_NAME = "ADB2BLE Adapter";
|
||||
|
||||
// Variables globales
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
// BLE HID
|
||||
BLEHIDDevice* hid;
|
||||
BLECharacteristic* inputKeyboard;
|
||||
BLECharacteristic* inputMouse;
|
||||
bool connected = false;
|
||||
|
||||
// États
|
||||
bool keyboardConnected = false;
|
||||
bool mouseConnected = false;
|
||||
uint8_t keyboardReport[8] = {0}; // Modificateurs + touches
|
||||
uint8_t mouseReport[4] = {0}; // Bouton, X, Y, Wheel
|
||||
|
||||
// Variables pour le suivi des mouvements de souris
|
||||
int16_t accumulatedX = 0;
|
||||
int16_t accumulatedY = 0;
|
||||
|
||||
// Callback pour la connexion BLE
|
||||
class ServerCallbacks : public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* server) {
|
||||
connected = true;
|
||||
Serial.println(F("Client BLE connecté"));
|
||||
}
|
||||
|
||||
void onDisconnect(BLEServer* server) {
|
||||
connected = false;
|
||||
Serial.println(F("Client BLE déconnecté"));
|
||||
BLEDevice::startAdvertising();
|
||||
}
|
||||
};
|
||||
|
||||
void setupBLE() {
|
||||
// Initialisation du BLE
|
||||
BLEDevice::init(DEVICE_NAME);
|
||||
BLEServer* server = BLEDevice::createServer();
|
||||
server->setCallbacks(new ServerCallbacks());
|
||||
|
||||
// Création du service HID
|
||||
hid = new BLEHIDDevice(server);
|
||||
inputKeyboard = hid->inputReport(1); // Report ID 1: Keyboard
|
||||
inputMouse = hid->inputReport(2); // Report ID 2: Mouse
|
||||
|
||||
// Configuration des descripteurs HID
|
||||
hid->manufacturer()->setValue("L'électron rare");
|
||||
hid->pnp(0x02, 0x05AC, 0x8240, 0x0001); // Apple
|
||||
hid->hidInfo(0x00, 0x01);
|
||||
|
||||
// Définition des descripteurs de rapport
|
||||
const uint8_t reportMapKeyboard[] = {
|
||||
// Clavier
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x06, // Usage (Keyboard)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x01, // Report ID (1)
|
||||
0x05, 0x07, // Usage Page (Key Codes)
|
||||
0x19, 0xE0, // Usage Minimum (224)
|
||||
0x29, 0xE7, // Usage Maximum (231)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x08, // Report Count (8)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x81, 0x01, // Input (Constant)
|
||||
0x95, 0x06, // Report Count (6)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x65, // Logical Maximum (101)
|
||||
0x05, 0x07, // Usage Page (Key Codes)
|
||||
0x19, 0x00, // Usage Minimum (0)
|
||||
0x29, 0x65, // Usage Maximum (101)
|
||||
0x81, 0x00, // Input (Data, Array)
|
||||
0xC0, // End Collection
|
||||
|
||||
// Souris
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x02, // Usage (Mouse)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x02, // Report ID (2)
|
||||
0x09, 0x01, // Usage (Pointer)
|
||||
0xA1, 0x00, // Collection (Physical)
|
||||
0x05, 0x09, // Usage Page (Button)
|
||||
0x19, 0x01, // Usage Minimum (1)
|
||||
0x29, 0x03, // Usage Maximum (3)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x95, 0x03, // Report Count (3)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x75, 0x05, // Report Size (5)
|
||||
0x81, 0x01, // Input (Constant)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x38, // Usage (Wheel)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x03, // Report Count (3)
|
||||
0x81, 0x06, // Input (Data, Variable, Relative)
|
||||
0xC0, // End Collection
|
||||
0xC0 // End Collection
|
||||
};
|
||||
|
||||
hid->reportMap((uint8_t*)reportMapKeyboard, sizeof(reportMapKeyboard));
|
||||
|
||||
// Activation du service
|
||||
hid->startServices();
|
||||
|
||||
// Démarrage de la publicité BLE
|
||||
BLEAdvertising* advertising = server->getAdvertising();
|
||||
advertising->setAppearance(HID_KEYBOARD);
|
||||
advertising->addServiceUUID(hid->hidService()->getUUID());
|
||||
advertising->start();
|
||||
|
||||
Serial.println(F("BLE HID prêt, en attente de connexion"));
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialisation de la communication série
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println(F("ADB2BLE pour ESP32 - PlatformIO"));
|
||||
Serial.println(F("Bibliothèque ADB multiplateforme"));
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
|
||||
// Configuration BLE
|
||||
setupBLE();
|
||||
|
||||
// Détection des périphériques ADB
|
||||
bool error;
|
||||
|
||||
// Test du clavier
|
||||
auto kbData = devices.keyboardReadModifiers(&error);
|
||||
keyboardConnected = !error;
|
||||
|
||||
// Test de la souris
|
||||
error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
mouseConnected = !error;
|
||||
|
||||
Serial.print(F("Périphériques détectés - Clavier: "));
|
||||
Serial.print(keyboardConnected ? F("Oui") : F("Non"));
|
||||
Serial.print(F(", Souris: "));
|
||||
Serial.println(mouseConnected ? F("Oui") : F("Non"));
|
||||
|
||||
Serial.println(F("Conversion ADB->BLE active"));
|
||||
}
|
||||
|
||||
void handleKeyboard() {
|
||||
if (!keyboardConnected || !connected) return;
|
||||
|
||||
bool error = false;
|
||||
static uint8_t lastModifiers = 0;
|
||||
static uint8_t lastKeys[6] = {0};
|
||||
bool reportChanged = false;
|
||||
|
||||
// Lecture des touches
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (error) {
|
||||
keyboardConnected = false;
|
||||
Serial.println(F("Clavier ADB déconnecté"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Lecture des modificateurs
|
||||
auto modifiers = devices.keyboardReadModifiers(&error);
|
||||
if (error) return;
|
||||
|
||||
// Construction du rapport clavier BLE HID
|
||||
uint8_t modByte = 0;
|
||||
if (modifiers.data.shift) modByte |= KEY_MOD_LSHIFT;
|
||||
if (modifiers.data.control) modByte |= KEY_MOD_LCTRL;
|
||||
if (modifiers.data.option) modByte |= KEY_MOD_LALT;
|
||||
if (modifiers.data.command) modByte |= KEY_MOD_LMETA;
|
||||
|
||||
if (modByte != lastModifiers) {
|
||||
lastModifiers = modByte;
|
||||
reportChanged = true;
|
||||
}
|
||||
|
||||
// Effacement des touches
|
||||
memset(&keyboardReport[2], 0, 6);
|
||||
|
||||
// Ajout des touches
|
||||
uint8_t keyIdx = 0;
|
||||
|
||||
if (keyPress.data.key0 && !keyPress.data.released0) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key0);
|
||||
if (hidCode != KEY_NONE && !ADBKeymap::isModifier(keyPress.data.key0)) {
|
||||
keyboardReport[2 + keyIdx++] = hidCode;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyPress.data.key1 && !keyPress.data.released1) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key1);
|
||||
if (hidCode != KEY_NONE && !ADBKeymap::isModifier(keyPress.data.key1)) {
|
||||
keyboardReport[2 + keyIdx++] = hidCode;
|
||||
}
|
||||
}
|
||||
|
||||
// Vérification des changements
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (keyboardReport[2 + i] != lastKeys[i]) {
|
||||
lastKeys[i] = keyboardReport[2 + i];
|
||||
reportChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Envoi du rapport si nécessaire
|
||||
if (reportChanged) {
|
||||
keyboardReport[0] = modByte;
|
||||
keyboardReport[1] = 0; // Reserved byte
|
||||
inputKeyboard->setValue(keyboardReport, 8);
|
||||
inputKeyboard->notify();
|
||||
}
|
||||
}
|
||||
|
||||
void handleMouse() {
|
||||
if (!mouseConnected || !connected) return;
|
||||
|
||||
bool error = false;
|
||||
static bool lastButton = false;
|
||||
|
||||
// Lecture des données de la souris
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (error) {
|
||||
mouseConnected = false;
|
||||
Serial.println(F("Souris ADB déconnectée"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Conversion des valeurs
|
||||
int8_t deltaX = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t deltaY = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
bool button = mouseData.data.button;
|
||||
|
||||
// Accumulation des petits mouvements
|
||||
accumulatedX += deltaX;
|
||||
accumulatedY += deltaY;
|
||||
|
||||
// Envoi du rapport souris si mouvement ou changement de bouton
|
||||
if (accumulatedX != 0 || accumulatedY != 0 || button != lastButton) {
|
||||
// Limitation des valeurs
|
||||
int8_t reportX = (accumulatedX > 127) ? 127 : ((accumulatedX < -127) ? -127 : accumulatedX);
|
||||
int8_t reportY = (accumulatedY > 127) ? 127 : ((accumulatedY < -127) ? -127 : accumulatedY);
|
||||
|
||||
// Construction du rapport
|
||||
mouseReport[0] = button ? 1 : 0; // Bouton gauche
|
||||
mouseReport[1] = reportX;
|
||||
mouseReport[2] = reportY;
|
||||
mouseReport[3] = 0; // Molette
|
||||
|
||||
// Envoi du rapport
|
||||
inputMouse->setValue(mouseReport, 4);
|
||||
inputMouse->notify();
|
||||
|
||||
// Mise à jour de l'état
|
||||
lastButton = button;
|
||||
|
||||
// Réinitialisation des accumulateurs après envoi
|
||||
accumulatedX -= reportX;
|
||||
accumulatedY -= reportY;
|
||||
}
|
||||
}
|
||||
|
||||
void reconnectDevices() {
|
||||
static uint32_t lastReconnectAttempt = 0;
|
||||
uint32_t now = millis();
|
||||
|
||||
// Tentative de reconnexion toutes les 3 secondes
|
||||
if (now - lastReconnectAttempt > 3000) {
|
||||
lastReconnectAttempt = now;
|
||||
|
||||
bool shouldReconnect = false;
|
||||
|
||||
if (!keyboardConnected) {
|
||||
bool error = false;
|
||||
devices.keyboardReadModifiers(&error);
|
||||
if (!error) {
|
||||
keyboardConnected = true;
|
||||
Serial.println(F("Clavier ADB reconnecté"));
|
||||
shouldReconnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mouseConnected) {
|
||||
bool error = false;
|
||||
devices.mouseReadData(&error);
|
||||
if (!error) {
|
||||
mouseConnected = true;
|
||||
Serial.println(F("Souris ADB reconnectée"));
|
||||
shouldReconnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReconnect) {
|
||||
Serial.println(F("Périphériques ADB actifs:"));
|
||||
Serial.print(F("- Clavier: "));
|
||||
Serial.println(keyboardConnected ? F("Connecté") : F("Déconnecté"));
|
||||
Serial.print(F("- Souris: "));
|
||||
Serial.println(mouseConnected ? F("Connectée") : F("Déconnectée"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Lecture et conversion des périphériques ADB
|
||||
handleKeyboard();
|
||||
handleMouse();
|
||||
|
||||
// Reconnexion si nécessaire
|
||||
if (!keyboardConnected || !mouseConnected) {
|
||||
reconnectDevices();
|
||||
}
|
||||
|
||||
// Délai de polling optimal
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[env:uno]
|
||||
platform = atmelavr
|
||||
board = uno
|
||||
framework = arduino
|
||||
monitor_speed = 9600
|
||||
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
electronrare/USBHID @ ^1.0.0
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <Arduino.h>
|
||||
#include <ADB.h>
|
||||
#include <ADBUtils.h>
|
||||
#include <USBHID.h>
|
||||
|
||||
// Configuration pour Arduino Uno
|
||||
constexpr uint8_t ADB_PIN = 2; // Pin de données ADB
|
||||
constexpr uint16_t POLL_INTERVAL = 10; // 10ms (100Hz)
|
||||
|
||||
// Variables globales
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
// États
|
||||
bool keyboardConnected = false;
|
||||
bool mouseConnected = false;
|
||||
uint8_t keyboardReport[8] = {0}; // Modificateurs + touches
|
||||
uint8_t mouseReport[4] = {0}; // Bouton, X, Y, Wheel
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(1000);
|
||||
|
||||
Serial.println(F("ADB2USB pour Arduino Uno - PlatformIO"));
|
||||
adb.init();
|
||||
USBHID_begin(true, true);
|
||||
|
||||
bool error;
|
||||
keyboardConnected = !devices.keyboardReadModifiers(&error);
|
||||
mouseConnected = !devices.mouseReadData(&error);
|
||||
|
||||
Serial.print(F("Clavier: "));
|
||||
Serial.println(keyboardConnected ? F("Connecté") : F("Déconnecté"));
|
||||
Serial.print(F("Souris: "));
|
||||
Serial.println(mouseConnected ? F("Connectée") : F("Déconnectée"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (keyboardConnected) {
|
||||
bool error = false;
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (error) keyboardConnected = false;
|
||||
// ...traitement clavier...
|
||||
}
|
||||
|
||||
if (mouseConnected) {
|
||||
bool error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (error) mouseConnected = false;
|
||||
// ...traitement souris...
|
||||
}
|
||||
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[env:esp32]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
electronrare/USBHID @ ^1.0.0
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <Arduino.h>
|
||||
#include <ADB.h>
|
||||
#include <ADBUtils.h>
|
||||
#include <USBHID.h>
|
||||
|
||||
// Configuration pour ESP32
|
||||
constexpr uint8_t ADB_PIN = 21; // Pin de données ADB
|
||||
constexpr uint16_t POLL_INTERVAL = 10; // 10ms (100Hz)
|
||||
|
||||
// Variables globales
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
// États
|
||||
bool keyboardConnected = false;
|
||||
bool mouseConnected = false;
|
||||
uint8_t keyboardReport[8] = {0}; // Modificateurs + touches
|
||||
uint8_t mouseReport[4] = {0}; // Bouton, X, Y, Wheel
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println(F("ADB2USB pour ESP32 - PlatformIO"));
|
||||
adb.init();
|
||||
USBHID_begin(true, true);
|
||||
|
||||
bool error;
|
||||
keyboardConnected = !devices.keyboardReadModifiers(&error);
|
||||
mouseConnected = !devices.mouseReadData(&error);
|
||||
|
||||
Serial.print(F("Clavier: "));
|
||||
Serial.println(keyboardConnected ? F("Connecté") : F("Déconnecté"));
|
||||
Serial.print(F("Souris: "));
|
||||
Serial.println(mouseConnected ? F("Connectée") : F("Déconnectée"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (keyboardConnected) {
|
||||
bool error = false;
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (error) keyboardConnected = false;
|
||||
// ...traitement clavier...
|
||||
}
|
||||
|
||||
if (mouseConnected) {
|
||||
bool error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (error) mouseConnected = false;
|
||||
// ...traitement souris...
|
||||
}
|
||||
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[env:leonardo]
|
||||
platform = atmelavr
|
||||
board = leonardo
|
||||
framework = arduino
|
||||
monitor_speed = 9600
|
||||
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
HID-Project @ ^2.6.0
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <Arduino.h>
|
||||
#include <ADB.h>
|
||||
#include <ADBUtils.h>
|
||||
#include <HID-Project.h> // Bibliothèque HID pour Arduino Leonardo/Micro
|
||||
|
||||
// Configuration pour Arduino Leonardo/Micro
|
||||
constexpr uint8_t ADB_PIN = 2; // Pin de données ADB
|
||||
constexpr uint16_t POLL_INTERVAL = 10; // 10ms (100Hz)
|
||||
|
||||
// Variables globales
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
// États
|
||||
bool keyboardConnected = false;
|
||||
bool mouseConnected = false;
|
||||
uint8_t keyboardReport[8] = {0}; // Modificateurs + touches
|
||||
uint8_t mouseReport[4] = {0}; // Bouton, X, Y, Wheel
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(1000);
|
||||
|
||||
Serial.println(F("ADB2USB pour Arduino Leonardo/Micro - PlatformIO"));
|
||||
adb.init();
|
||||
|
||||
// Initialisation HID
|
||||
Keyboard.begin();
|
||||
Mouse.begin();
|
||||
|
||||
bool error;
|
||||
keyboardConnected = !devices.keyboardReadModifiers(&error);
|
||||
mouseConnected = !devices.mouseReadData(&error);
|
||||
|
||||
Serial.print(F("Clavier: "));
|
||||
Serial.println(keyboardConnected ? F("Connecté") : F("Déconnecté"));
|
||||
Serial.print(F("Souris: "));
|
||||
Serial.println(mouseConnected ? F("Connectée") : F("Déconnectée"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (keyboardConnected) {
|
||||
bool error = false;
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (error) {
|
||||
keyboardConnected = false;
|
||||
Serial.println(F("Clavier déconnecté"));
|
||||
} else {
|
||||
// Traitement des touches
|
||||
if (keyPress.data.key0 && !keyPress.data.released0) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key0);
|
||||
if (hidCode != KEY_NONE) {
|
||||
Keyboard.press(hidCode);
|
||||
}
|
||||
}
|
||||
if (keyPress.data.released0) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key0);
|
||||
if (hidCode != KEY_NONE) {
|
||||
Keyboard.release(hidCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mouseConnected) {
|
||||
bool error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (error) {
|
||||
mouseConnected = false;
|
||||
Serial.println(F("Souris déconnectée"));
|
||||
} else {
|
||||
// Traitement des mouvements de souris
|
||||
int8_t deltaX = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t deltaY = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
bool button = mouseData.data.button;
|
||||
|
||||
Mouse.move(deltaX, deltaY);
|
||||
if (button) {
|
||||
Mouse.press(MOUSE_LEFT);
|
||||
} else {
|
||||
Mouse.release(MOUSE_LEFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
[env:stm32]
|
||||
platform = ststm32
|
||||
board = bluepill_f103c8
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
electronrare/USBHID @ ^1.0.0
|
||||
upload_protocol = stlink
|
||||
monitor_speed = 115200
|
||||
|
||||
[env:esp32]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
electronrare/USBHID @ ^1.0.0
|
||||
monitor_speed = 115200
|
||||
|
||||
[env:leonardo]
|
||||
platform = atmelavr
|
||||
board = leonardo
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
HID-Project @ ^2.6.0
|
||||
monitor_speed = 9600
|
||||
@@ -0,0 +1,127 @@
|
||||
#include <Arduino.h>
|
||||
#include <ADB.h>
|
||||
#include <ADBUtils.h>
|
||||
|
||||
#ifdef ARDUINO_ARCH_STM32
|
||||
#include <USBHID.h> // STM32 USB HID
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#include <USBHID.h> // ESP32 USB HID
|
||||
#elif defined(ARDUINO_ARCH_AVR)
|
||||
#include <HID-Project.h> // Arduino Leonardo/Micro HID
|
||||
#endif
|
||||
|
||||
// Configuration des broches et paramètres
|
||||
#ifdef ARDUINO_ARCH_STM32
|
||||
constexpr uint8_t ADB_PIN = PB4; // STM32
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
constexpr uint8_t ADB_PIN = 21; // ESP32
|
||||
#elif defined(ARDUINO_ARCH_AVR)
|
||||
constexpr uint8_t ADB_PIN = 2; // Arduino Leonardo/Micro
|
||||
#endif
|
||||
|
||||
constexpr uint16_t POLL_INTERVAL = 10; // 10ms (100Hz)
|
||||
|
||||
// Variables globales
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
// États
|
||||
bool keyboardConnected = false;
|
||||
bool mouseConnected = false;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println(F("ADB2USB - Multi-Platform Example"));
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
|
||||
// Initialisation USB HID
|
||||
#ifdef ARDUINO_ARCH_STM32
|
||||
USBHID_begin(true, true);
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
USBHID_begin(true, true);
|
||||
#elif defined(ARDUINO_ARCH_AVR)
|
||||
Keyboard.begin();
|
||||
Mouse.begin();
|
||||
#endif
|
||||
|
||||
// Détection des périphériques
|
||||
bool error;
|
||||
keyboardConnected = !devices.keyboardReadModifiers(&error);
|
||||
mouseConnected = !devices.mouseReadData(&error);
|
||||
|
||||
Serial.print(F("Clavier: "));
|
||||
Serial.println(keyboardConnected ? F("Connecté") : F("Déconnecté"));
|
||||
Serial.print(F("Souris: "));
|
||||
Serial.println(mouseConnected ? F("Connectée") : F("Déconnectée"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Gestion du clavier
|
||||
if (keyboardConnected) {
|
||||
bool error = false;
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (error) {
|
||||
keyboardConnected = false;
|
||||
Serial.println(F("Clavier déconnecté"));
|
||||
} else {
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
// Gestion HID pour Arduino Leonardo/Micro
|
||||
if (keyPress.data.key0 && !keyPress.data.released0) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key0);
|
||||
if (hidCode != KEY_NONE) {
|
||||
Keyboard.press(hidCode);
|
||||
}
|
||||
}
|
||||
if (keyPress.data.released0) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key0);
|
||||
if (hidCode != KEY_NONE) {
|
||||
Keyboard.release(hidCode);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Gestion HID pour STM32/ESP32
|
||||
uint8_t keyboardReport[8] = {0};
|
||||
keyboardReport[2] = ADBKeymap::toHID(keyPress.data.key0);
|
||||
USBHID_keyboard_report(keyboardReport);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Gestion de la souris
|
||||
if (mouseConnected) {
|
||||
bool error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (error) {
|
||||
mouseConnected = false;
|
||||
Serial.println(F("Souris déconnectée"));
|
||||
} else {
|
||||
int8_t deltaX = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t deltaY = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
bool button = mouseData.data.button;
|
||||
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
// Gestion HID pour Arduino Leonardo/Micro
|
||||
Mouse.move(deltaX, deltaY);
|
||||
if (button) {
|
||||
Mouse.press(MOUSE_LEFT);
|
||||
} else {
|
||||
Mouse.release(MOUSE_LEFT);
|
||||
}
|
||||
#else
|
||||
// Gestion HID pour STM32/ESP32
|
||||
uint8_t mouseReport[4] = {0};
|
||||
mouseReport[0] = button ? 1 : 0;
|
||||
mouseReport[1] = deltaX;
|
||||
mouseReport[2] = deltaY;
|
||||
USBHID_mouse_report(mouseReport);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
# ADB2USB pour STM32 - Convertisseur Apple Desktop Bus vers USB
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/electron-rare/stm32-adb2usb/main/docs/assets/adb2usb-logo.png" alt="Logo ADB2USB" width="300" />
|
||||
</p>
|
||||
|
||||
> Donnez une seconde vie à vos périphériques Apple vintage en les connectant à des ordinateurs modernes !
|
||||
|
||||
## 📋 Table des matières
|
||||
|
||||
- [À propos du projet](#à-propos)
|
||||
- [Fonctionnalités](#fonctionnalités)
|
||||
- [Matériel requis](#matériel-requis)
|
||||
- [Schéma de branchement](#branchements)
|
||||
- [Installation](#installation)
|
||||
- [Utilisation](#utilisation)
|
||||
- [Personnalisation](#personnalisation)
|
||||
- [Débogage](#débogage)
|
||||
- [Contribution](#contribution)
|
||||
- [Licence](#licence)
|
||||
- [Contact](#contact)
|
||||
|
||||
## ℹ️ À propos
|
||||
|
||||
Cette implémentation permet de connecter des anciens claviers et souris Apple utilisant le bus ADB à un ordinateur moderne via USB. Le microcontrôleur STM32 agit comme un pont de conversion, interprétant les signaux ADB et les transformant en signaux USB HID.
|
||||
|
||||
## ✨ Fonctionnalités
|
||||
|
||||
- ⌨️ Prise en charge des claviers ADB (touches et modificateurs)
|
||||
- 🖱️ Prise en charge des souris ADB (déplacements et boutons)
|
||||
- 🔍 Détection automatique des périphériques ADB
|
||||
- 🔄 Reconnexion automatique des périphériques déconnectés
|
||||
- 💡 Synchronisation des LED (Verr. Maj, etc.) entre USB et ADB
|
||||
- 📦 Exemple complet pour PlatformIO
|
||||
|
||||
## 🔌 Matériel requis
|
||||
|
||||
- Carte de développement STM32 compatible avec Arduino (par exemple, STM32 Blue Pill)
|
||||
- Périphériques ADB (clavier et/ou souris Apple)
|
||||
- Connecteur ADB (Mini-DIN 4 broches)
|
||||
- Résistance pull-up de 4.7kΩ à 10kΩ pour la ligne de données ADB
|
||||
- Câble USB pour connecter la carte STM32 à l'ordinateur
|
||||
|
||||
## 🔧 Branchements
|
||||
|
||||
```
|
||||
ADB Mini-DIN 4 broches:
|
||||
- Pin 1 (ADB Data) → STM32 Pin PB4 (avec résistance pull-up 4.7kΩ à 10kΩ vers 5V)
|
||||
- Pin 2 (Power SW) → Non connecté
|
||||
- Pin 3 (5V) → 5V
|
||||
- Pin 4 (GND) → GND
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Schéma de câblage</summary>
|
||||
<img src="https://raw.githubusercontent.com/electron-rare/stm32-adb2usb/main/docs/assets/wiring.png" alt="Schéma de câblage" width="600" />
|
||||
</details>
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
### Prérequis logiciels
|
||||
|
||||
- [PlatformIO](https://platformio.org/) (installé comme extension VS Code ou en ligne de commande)
|
||||
- Environnement de développement STM32 pour Arduino
|
||||
|
||||
### Étapes d'installation
|
||||
|
||||
1. Cloner ce dépôt
|
||||
```bash
|
||||
git clone https://github.com/electron-rare/stm32-adb2usb.git
|
||||
cd stm32-adb2usb
|
||||
```
|
||||
|
||||
2. Ouvrir le dossier dans PlatformIO
|
||||
```bash
|
||||
code .
|
||||
```
|
||||
|
||||
3. Compiler et téléverser vers votre carte
|
||||
```bash
|
||||
pio run -t upload
|
||||
```
|
||||
|
||||
## 📝 Utilisation
|
||||
|
||||
Une fois le code téléversé:
|
||||
|
||||
1. Connectez votre périphérique ADB à la carte STM32
|
||||
2. Connectez la carte STM32 à votre ordinateur via USB
|
||||
3. Les périphériques ADB seront automatiquement détectés et fonctionneront comme des périphériques USB HID
|
||||
|
||||
## ⚙️ Personnalisation
|
||||
|
||||
Pour adapter ce code à votre matériel spécifique:
|
||||
- Modifiez la constante `ADB_PIN` pour correspondre à votre brochage
|
||||
- Ajustez `POLL_INTERVAL` selon vos besoins de réactivité
|
||||
|
||||
## 🐛 Débogage
|
||||
|
||||
Vous pouvez suivre le processus de détection et la connexion des périphériques via le moniteur série:
|
||||
|
||||
```bash
|
||||
pio device monitor -b 115200
|
||||
```
|
||||
|
||||
## 👥 Contribution
|
||||
|
||||
Les contributions sont les bienvenues ! N'hésitez pas à ouvrir une issue ou une pull request.
|
||||
|
||||
1. Forkez le projet
|
||||
2. Créez votre branche (`git checkout -b feature/amazing-feature`)
|
||||
3. Commitez vos changements (`git commit -m 'Add some amazing feature'`)
|
||||
4. Pushez vers la branche (`git push origin feature/amazing-feature`)
|
||||
5. Ouvrez une Pull Request
|
||||
|
||||
## 📄 Licence
|
||||
|
||||
Ce projet est sous licence GNU GPL v3. Voir le fichier `LICENSE` pour plus de détails.
|
||||
|
||||
## 📧 Contact
|
||||
|
||||
Clément SAILLANT - [@lelectron_rare](https://twitter.com/lelectron_rare) - contact@lelectron-rare.fr
|
||||
|
||||
Lien du projet: [https://github.com/electron-rare/stm32-adb2usb](https://github.com/electron-rare/stm32-adb2usb)
|
||||
@@ -0,0 +1,25 @@
|
||||
[env:bluepill_f103c8]
|
||||
platform = ststm32
|
||||
board = bluepill_f103c8
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
electronrare/ADB @ ^1.0.0
|
||||
electronrare/USBHID @ ^1.0.0
|
||||
upload_protocol = stlink
|
||||
monitor_speed = 115200
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
|
||||
-D USBCON
|
||||
-D USB_MANUFACTURER="ElectronRare"
|
||||
-D USB_PRODUCT="ADB2USB HID"
|
||||
|
||||
[env:stm32]
|
||||
platform = ststm32
|
||||
board = bluepill_f103c8
|
||||
framework = arduino
|
||||
upload_protocol = stlink
|
||||
monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
ADB
|
||||
USBHID
|
||||
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @brief Exemple PlatformIO pour STM32 avec la bibliothèque ADB
|
||||
*
|
||||
* Cet exemple montre comment utiliser la bibliothèque ADB dans un projet PlatformIO
|
||||
* pour convertir un périphérique ADB en USB HID avec un STM32.
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ADB.h>
|
||||
#include <ADBUtils.h>
|
||||
#include <USBHID.h>
|
||||
|
||||
// Configuration pour STM32
|
||||
constexpr uint8_t ADB_PIN = PB4; // Pin de données ADB
|
||||
constexpr uint16_t POLL_INTERVAL = 10; // 10ms (100Hz)
|
||||
|
||||
// Variables globales
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
ADBUtils utils(devices);
|
||||
|
||||
// États
|
||||
bool keyboardConnected = false;
|
||||
bool mouseConnected = false;
|
||||
uint8_t keyboardReport[8] = {0}; // Modificateurs + touches
|
||||
uint8_t mouseReport[4] = {0}; // Bouton, X, Y, Wheel
|
||||
|
||||
// Variables pour le suivi des mouvements de souris
|
||||
int16_t accumulatedX = 0;
|
||||
int16_t accumulatedY = 0;
|
||||
|
||||
void setup() {
|
||||
// Initialisation de la communication série
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println(F("ADB2USB pour STM32 - PlatformIO"));
|
||||
Serial.println(F("Bibliothèque ADB multiplateforme"));
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
|
||||
// Initialisation USB HID (clavier + souris)
|
||||
USBHID_begin(true, true);
|
||||
|
||||
// Détection des périphériques ADB
|
||||
bool error;
|
||||
|
||||
// Test du clavier
|
||||
auto kbData = devices.keyboardReadModifiers(&error);
|
||||
keyboardConnected = !error;
|
||||
|
||||
// Test de la souris
|
||||
error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
mouseConnected = !error;
|
||||
|
||||
Serial.print(F("Périphériques détectés - Clavier: "));
|
||||
Serial.print(keyboardConnected ? F("Oui") : F("Non"));
|
||||
Serial.print(F(", Souris: "));
|
||||
Serial.println(mouseConnected ? F("Oui") : F("Non"));
|
||||
|
||||
Serial.println(F("Conversion ADB->USB active"));
|
||||
}
|
||||
|
||||
void handleKeyboard() {
|
||||
if (!keyboardConnected) return;
|
||||
|
||||
bool error = false;
|
||||
static uint8_t lastModifiers = 0;
|
||||
static uint8_t lastKeys[6] = {0};
|
||||
bool reportChanged = false;
|
||||
|
||||
// Lecture des touches
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
if (error) {
|
||||
keyboardConnected = false;
|
||||
Serial.println(F("Clavier ADB déconnecté"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Lecture des modificateurs
|
||||
auto modifiers = devices.keyboardReadModifiers(&error);
|
||||
if (error) return;
|
||||
|
||||
// Construction du rapport clavier USB HID
|
||||
uint8_t modByte = 0;
|
||||
if (modifiers.data.shift) modByte |= KEY_MOD_LSHIFT;
|
||||
if (modifiers.data.control) modByte |= KEY_MOD_LCTRL;
|
||||
if (modifiers.data.option) modByte |= KEY_MOD_LALT;
|
||||
if (modifiers.data.command) modByte |= KEY_MOD_LMETA;
|
||||
|
||||
if (modByte != lastModifiers) {
|
||||
lastModifiers = modByte;
|
||||
reportChanged = true;
|
||||
}
|
||||
|
||||
// Effacement des touches
|
||||
memset(&keyboardReport[2], 0, 6);
|
||||
|
||||
// Ajout des touches
|
||||
uint8_t keyIdx = 0;
|
||||
|
||||
if (keyPress.data.key0 && !keyPress.data.released0) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key0);
|
||||
if (hidCode != KEY_NONE && !ADBKeymap::isModifier(keyPress.data.key0)) {
|
||||
keyboardReport[2 + keyIdx++] = hidCode;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyPress.data.key1 && !keyPress.data.released1) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key1);
|
||||
if (hidCode != KEY_NONE && !ADBKeymap::isModifier(keyPress.data.key1)) {
|
||||
keyboardReport[2 + keyIdx++] = hidCode;
|
||||
}
|
||||
}
|
||||
|
||||
// Vérification des changements
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (keyboardReport[2 + i] != lastKeys[i]) {
|
||||
lastKeys[i] = keyboardReport[2 + i];
|
||||
reportChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Envoi du rapport si nécessaire
|
||||
if (reportChanged) {
|
||||
keyboardReport[0] = modByte;
|
||||
keyboardReport[1] = 0; // Reserved byte
|
||||
USBHID_keyboard_report(keyboardReport);
|
||||
}
|
||||
}
|
||||
|
||||
void handleMouse() {
|
||||
if (!mouseConnected) return;
|
||||
|
||||
bool error = false;
|
||||
static bool lastButton = false;
|
||||
|
||||
// Lecture des données de la souris
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
if (error) {
|
||||
mouseConnected = false;
|
||||
Serial.println(F("Souris ADB déconnectée"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Conversion des valeurs
|
||||
int8_t deltaX = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t deltaY = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
bool button = mouseData.data.button;
|
||||
|
||||
// Accumulation des petits mouvements
|
||||
accumulatedX += deltaX;
|
||||
accumulatedY += deltaY;
|
||||
|
||||
// Envoi du rapport souris si mouvement ou changement de bouton
|
||||
if (accumulatedX != 0 || accumulatedY != 0 || button != lastButton) {
|
||||
// Limitation des valeurs
|
||||
int8_t reportX = (accumulatedX > 127) ? 127 : ((accumulatedX < -127) ? -127 : accumulatedX);
|
||||
int8_t reportY = (accumulatedY > 127) ? 127 : ((accumulatedY < -127) ? -127 : accumulatedY);
|
||||
|
||||
// Construction du rapport
|
||||
mouseReport[0] = button ? 1 : 0; // Bouton gauche
|
||||
mouseReport[1] = reportX;
|
||||
mouseReport[2] = reportY;
|
||||
mouseReport[3] = 0; // Molette
|
||||
|
||||
// Envoi du rapport
|
||||
USBHID_mouse_report(mouseReport);
|
||||
|
||||
// Mise à jour de l'état
|
||||
lastButton = button;
|
||||
|
||||
// Réinitialisation des accumulateurs après envoi
|
||||
accumulatedX -= reportX;
|
||||
accumulatedY -= reportY;
|
||||
}
|
||||
}
|
||||
|
||||
void updateLEDs() {
|
||||
// Synchronisation des LEDs USB avec le clavier ADB
|
||||
static uint8_t lastLEDs = 0;
|
||||
uint8_t currentLEDs = USBHID_get_status();
|
||||
|
||||
if (currentLEDs != lastLEDs) {
|
||||
lastLEDs = currentLEDs;
|
||||
|
||||
bool numLock = (currentLEDs & 0x01);
|
||||
bool capsLock = (currentLEDs & 0x02);
|
||||
bool scrollLock = (currentLEDs & 0x04);
|
||||
|
||||
if (keyboardConnected) {
|
||||
devices.keyboardWriteLEDs(scrollLock, capsLock, numLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reconnectDevices() {
|
||||
static uint32_t lastReconnectAttempt = 0;
|
||||
uint32_t now = millis();
|
||||
|
||||
// Tentative de reconnexion toutes les 3 secondes
|
||||
if (now - lastReconnectAttempt > 3000) {
|
||||
lastReconnectAttempt = now;
|
||||
|
||||
bool shouldReconnect = false;
|
||||
|
||||
if (!keyboardConnected) {
|
||||
bool error = false;
|
||||
devices.keyboardReadModifiers(&error);
|
||||
if (!error) {
|
||||
keyboardConnected = true;
|
||||
Serial.println(F("Clavier ADB reconnecté"));
|
||||
shouldReconnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mouseConnected) {
|
||||
bool error = false;
|
||||
devices.mouseReadData(&error);
|
||||
if (!error) {
|
||||
mouseConnected = true;
|
||||
Serial.println(F("Souris ADB reconnectée"));
|
||||
shouldReconnect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReconnect) {
|
||||
Serial.println(F("Périphériques ADB actifs:"));
|
||||
Serial.print(F("- Clavier: "));
|
||||
Serial.println(keyboardConnected ? F("Connecté") : F("Déconnecté"));
|
||||
Serial.print(F("- Souris: "));
|
||||
Serial.println(mouseConnected ? F("Connectée") : F("Déconnectée"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Lecture et conversion des périphériques ADB
|
||||
handleKeyboard();
|
||||
handleMouse();
|
||||
updateLEDs();
|
||||
|
||||
// Reconnexion si nécessaire
|
||||
if (!keyboardConnected || !mouseConnected) {
|
||||
reconnectDevices();
|
||||
}
|
||||
|
||||
// Délai de polling optimal
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* @file usb_hid_stm32.cpp
|
||||
* @brief Exemple de conversion ADB vers USB HID pour STM32
|
||||
*
|
||||
* Cet exemple montre comment convertir un clavier et une souris ADB en un périphérique
|
||||
* USB HID sur les plateformes STM32. Il permet d'utiliser des périphériques Apple vintage
|
||||
* sur des ordinateurs modernes via USB.
|
||||
*
|
||||
* @note Cet exemple nécessite un STM32 avec prise en charge USB (STM32F1, STM32F4, etc.)
|
||||
*
|
||||
* @author Clément SAILLANT - L'électron rare
|
||||
* @copyright Copyright (C) 2025 Clément SAILLANT
|
||||
* @license GNU GPL v3
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "adb.h"
|
||||
#include "USBHID.h" // Bibliothèque STM32 USB HID
|
||||
|
||||
// Configuration des broches
|
||||
constexpr uint8_t ADB_PIN = PB4; // Broche de données ADB
|
||||
|
||||
// Configuration des constantes
|
||||
constexpr uint16_t POLL_INTERVAL = 10; // Fréquence d'interrogation en ms (10ms = 100Hz)
|
||||
constexpr uint8_t MAX_KEYS = 6; // Nombre maximum de touches dans un rapport HID
|
||||
|
||||
// Initialisation des objets
|
||||
ADB adb(ADB_PIN);
|
||||
ADBDevices devices(adb);
|
||||
|
||||
// Buffers pour les rapports HID
|
||||
uint8_t keyboardReport[8] = {0}; // Modificateurs (1) + réservé (1) + touches (6)
|
||||
uint8_t mouseReport[4] = {0}; // Boutons (1) + X (1) + Y (1) + molette (1)
|
||||
|
||||
// État précédent des périphériques
|
||||
uint8_t lastKeyboardKeys[MAX_KEYS] = {0};
|
||||
uint8_t lastModifiers = 0;
|
||||
int16_t mouseAccumulatedX = 0;
|
||||
int16_t mouseAccumulatedY = 0;
|
||||
bool lastButton = false;
|
||||
|
||||
// Indicateurs de présence des périphériques
|
||||
bool keyboardPresent = false;
|
||||
bool mousePresent = false;
|
||||
|
||||
/**
|
||||
* @brief Met à jour les LEDs du clavier ADB en fonction de l'état USB
|
||||
*/
|
||||
void updateKeyboardLEDs() {
|
||||
static uint8_t lastLEDState = 0;
|
||||
uint8_t currentLEDs = USBHID_get_status();
|
||||
|
||||
if (currentLEDs != lastLEDState) {
|
||||
lastLEDState = currentLEDs;
|
||||
|
||||
bool numLock = (currentLEDs & 0x01) != 0;
|
||||
bool capsLock = (currentLEDs & 0x02) != 0;
|
||||
bool scrollLock = (currentLEDs & 0x04) != 0;
|
||||
|
||||
// Mise à jour des LEDs sur le clavier ADB
|
||||
if (keyboardPresent) {
|
||||
devices.keyboardWriteLEDs(scrollLock, capsLock, numLock);
|
||||
}
|
||||
|
||||
Serial.print(F("LEDs mises à jour: "));
|
||||
Serial.print(capsLock ? F("CapsLock ") : F(""));
|
||||
Serial.print(numLock ? F("NumLock ") : F(""));
|
||||
Serial.println(scrollLock ? F("ScrollLock") : F(""));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Détecte et initialise les périphériques ADB
|
||||
*/
|
||||
void detectADBDevices() {
|
||||
bool error = false;
|
||||
|
||||
// Essai de lecture des modificateurs du clavier
|
||||
devices.keyboardReadModifiers(&error);
|
||||
keyboardPresent = !error;
|
||||
|
||||
// Essai de lecture de la souris
|
||||
error = false;
|
||||
devices.mouseReadData(&error);
|
||||
mousePresent = !error;
|
||||
|
||||
Serial.print(F("Détection ADB: Clavier: "));
|
||||
Serial.print(keyboardPresent ? F("Oui") : F("Non"));
|
||||
Serial.print(F(", Souris: "));
|
||||
Serial.println(mousePresent ? F("Oui") : F("Non"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lit les données du clavier ADB et les convertit en rapport USB HID
|
||||
*/
|
||||
void handleKeyboard() {
|
||||
if (!keyboardPresent) return;
|
||||
|
||||
bool error = false;
|
||||
auto keyPress = devices.keyboardReadKeyPress(&error);
|
||||
|
||||
if (error) {
|
||||
keyboardPresent = false;
|
||||
Serial.println(F("Erreur: Clavier ADB déconnecté"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Mise à jour des modificateurs (registre 2)
|
||||
auto modifiers = devices.keyboardReadModifiers(&error);
|
||||
if (error) return;
|
||||
|
||||
// Calcul du nouvel état des modificateurs
|
||||
uint8_t newModifiers = 0;
|
||||
if (modifiers.data.shift) newModifiers |= KEY_MOD_LSHIFT;
|
||||
if (modifiers.data.control) newModifiers |= KEY_MOD_LCTRL;
|
||||
if (modifiers.data.option) newModifiers |= KEY_MOD_LALT;
|
||||
if (modifiers.data.command) newModifiers |= KEY_MOD_LMETA;
|
||||
|
||||
// Construction du rapport clavier
|
||||
keyboardReport[0] = newModifiers; // Octet des modificateurs
|
||||
|
||||
// Effacer les touches
|
||||
memset(&keyboardReport[2], 0, MAX_KEYS);
|
||||
|
||||
// Ajouter les touches pressées
|
||||
uint8_t keyIndex = 0;
|
||||
|
||||
// Gestion de la touche 0
|
||||
if (keyPress.data.key0 != 0 && !keyPress.data.released0) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key0);
|
||||
if (hidCode != KEY_NONE && !ADBKeymap::isModifier(keyPress.data.key0)) {
|
||||
keyboardReport[2 + keyIndex++] = hidCode;
|
||||
}
|
||||
}
|
||||
|
||||
// Gestion de la touche 1
|
||||
if (keyPress.data.key1 != 0 && !keyPress.data.released1) {
|
||||
uint8_t hidCode = ADBKeymap::toHID(keyPress.data.key1);
|
||||
if (hidCode != KEY_NONE && !ADBKeymap::isModifier(keyPress.data.key1)) {
|
||||
keyboardReport[2 + keyIndex++] = hidCode;
|
||||
}
|
||||
}
|
||||
|
||||
// Envoi du rapport uniquement s'il a changé
|
||||
bool changed = false;
|
||||
if (newModifiers != lastModifiers) {
|
||||
changed = true;
|
||||
lastModifiers = newModifiers;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < MAX_KEYS; i++) {
|
||||
if (keyboardReport[2 + i] != lastKeyboardKeys[i]) {
|
||||
changed = true;
|
||||
lastKeyboardKeys[i] = keyboardReport[2 + i];
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
USBHID_keyboard_report(keyboardReport);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lit les données de la souris ADB et les convertit en rapport USB HID
|
||||
*/
|
||||
void handleMouse() {
|
||||
if (!mousePresent) return;
|
||||
|
||||
bool error = false;
|
||||
auto mouseData = devices.mouseReadData(&error);
|
||||
|
||||
if (error) {
|
||||
mousePresent = false;
|
||||
Serial.println(F("Erreur: Souris ADB déconnectée"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Récupération des données souris
|
||||
int8_t deltaX = adbMouseConvertAxis(mouseData.data.x_offset);
|
||||
int8_t deltaY = adbMouseConvertAxis(mouseData.data.y_offset);
|
||||
bool buttonPressed = mouseData.data.button;
|
||||
|
||||
// Cumul des petits mouvements pour éviter la perte de mouvements lents
|
||||
mouseAccumulatedX += deltaX;
|
||||
mouseAccumulatedY += deltaY;
|
||||
|
||||
// Création du rapport souris seulement s'il y a un mouvement ou un changement d'état du bouton
|
||||
if (mouseAccumulatedX != 0 || mouseAccumulatedY != 0 || buttonPressed != lastButton) {
|
||||
mouseReport[0] = buttonPressed ? 1 : 0; // Bouton gauche
|
||||
|
||||
// Limitation des valeurs pour tenir dans un int8_t
|
||||
if (mouseAccumulatedX > 127) mouseAccumulatedX = 127;
|
||||
if (mouseAccumulatedX < -127) mouseAccumulatedX = -127;
|
||||
if (mouseAccumulatedY > 127) mouseAccumulatedY = 127;
|
||||
if (mouseAccumulatedY < -127) mouseAccumulatedY = -127;
|
||||
|
||||
mouseReport[1] = (int8_t)mouseAccumulatedX;
|
||||
mouseReport[2] = (int8_t)mouseAccumulatedY;
|
||||
mouseReport[3] = 0; // Pas de défilement
|
||||
|
||||
// Envoi du rapport souris
|
||||
USBHID_mouse_report(mouseReport);
|
||||
|
||||
// Réinitialisation des accumulateurs
|
||||
mouseAccumulatedX = 0;
|
||||
mouseAccumulatedY = 0;
|
||||
lastButton = buttonPressed;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialisation de la communication série pour le débogage
|
||||
Serial.begin(115200);
|
||||
while (!Serial && millis() < 3000); // Attente avec timeout
|
||||
|
||||
Serial.println(F("=== Convertisseur ADB vers USB HID pour STM32 ==="));
|
||||
Serial.println(F("Initialisation du bus ADB..."));
|
||||
|
||||
// Initialisation du bus ADB
|
||||
adb.init();
|
||||
|
||||
// Initialisation USB HID
|
||||
USBHID_begin(true, true); // Activer clavier + souris
|
||||
|
||||
// Détection des périphériques
|
||||
detectADBDevices();
|
||||
|
||||
Serial.println(F("Initialisation terminée"));
|
||||
Serial.println(F("Le périphérique devrait maintenant être reconnu comme un clavier/souris USB"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Lecture des périphériques ADB et envoi des rapports USB HID
|
||||
handleKeyboard();
|
||||
handleMouse();
|
||||
|
||||
// Mise à jour des LEDs du clavier ADB en fonction de l'état du clavier USB
|
||||
updateKeyboardLEDs();
|
||||
|
||||
// Si un périphérique a été déconnecté, tentative de reconnexion
|
||||
static uint32_t lastReconnectTime = 0;
|
||||
if ((!keyboardPresent || !mousePresent) && (millis() - lastReconnectTime > 1000)) {
|
||||
if (!keyboardPresent || !mousePresent) {
|
||||
Serial.println(F("Tentative de reconnexion des périphériques ADB..."));
|
||||
detectADBDevices();
|
||||
lastReconnectTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
// Pause entre les lectures pour ne pas surcharger le bus
|
||||
delay(POLL_INTERVAL);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Spécifications du logo ADB2USB
|
||||
|
||||
## Concept
|
||||
Un logo représentant la conversion des périphériques Apple Desktop Bus (ADB) vers USB, combinant des éléments vintage Apple et la modernité.
|
||||
|
||||
## Éléments principaux
|
||||
1. **Symbole ADB**: Représentation stylisée du connecteur Mini-DIN 4 broches ADB
|
||||
2. **Flèche de transition**: Indiquant la conversion d'une technologie à l'autre
|
||||
3. **Symbole USB**: Icône USB standard ou connecteur USB-A stylisé
|
||||
4. **Carte STM32**: Petite silhouette d'une carte STM32 (optionnelle)
|
||||
|
||||
## Palette de couleurs
|
||||
- **ADB (côté gauche)**: Couleurs vintage Apple
|
||||
- Beige: #E0D7C5 (couleur des premiers Macintosh)
|
||||
- Rainbow Apple: Utiliser des éléments du logo Apple arc-en-ciel
|
||||
- **USB (côté droit)**: Couleurs modernes
|
||||
- Bleu: #3B7BBF (bleu USB standard)
|
||||
- Blanc: #FFFFFF
|
||||
- **Accent**: Rouge STM32 (#EE3424) pour la partie microcontrôleur
|
||||
|
||||
## Style et composition
|
||||
- Style épuré et légèrement rétro
|
||||
- Disposition horizontale avec ADB à gauche, USB à droite
|
||||
- Polices suggérées:
|
||||
- "Chicago" ou "Geneva" (polices vintage Apple) pour la partie ADB
|
||||
- "Source Sans Pro" ou "Helvetica Neue" pour la partie USB
|
||||
|
||||
## Variantes à créer
|
||||
1. **Logo complet**: Tous les éléments avec texte "ADB2USB"
|
||||
2. **Icône seule**: Version sans texte pour favicon ou petits affichages
|
||||
3. **Version monochrome**: Pour impression ou situations à contraste limité
|
||||
|
||||
## Dimensions recommandées
|
||||
- Logo principal: 2000x800px (ratio 2.5:1)
|
||||
- Icône: 512x512px (ratio 1:1)
|
||||
- Prévoir des versions pour GitHub, Twitter et autres plateformes sociales
|
||||
|
||||
## Exemples d'inspiration
|
||||
- Logo Apple rétro (1977-1998)
|
||||
- Logos d'interface HID standards
|
||||
- Design minimaliste des logos de projets open source
|
||||
|
||||
## Production
|
||||
Créer le logo en format vectoriel (SVG) pour permettre un redimensionnement sans perte de qualité, puis exporter en PNG pour différentes utilisations.
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "ADB",
|
||||
"version": "1.0.0",
|
||||
"description": "Une bibliothèque multiplateforme pour le protocole Apple Desktop Bus (ADB)",
|
||||
"keywords": "adb, apple, vintage, usb, hid, keyboard, mouse",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/electronrare/stm32-adb2usb"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Clément SAILLANT",
|
||||
"email": "contact@electronrare.com",
|
||||
"url": "https://electronrare.com",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"license": "GPL-3.0-or-later",
|
||||
"homepage": "https://github.com/electronrare/stm32-adb2usb",
|
||||
"dependencies": {},
|
||||
"frameworks": "arduino",
|
||||
"platforms": ["ststm32", "espressif32", "atmelavr", "teensy"]
|
||||
}
|
||||
Reference in New Issue
Block a user