Oui, j'ai cherché sur les forums Arduino.cc et ici. Oui, j'ai trouvé les articles concernant la bibliothèque ps2dev. Oui, j'ai lu (d'accord, certains j'ai survolé) l'article définitif sur l'interface PS / 2 sur ce site . Oui, j'ai ce travail, un peu. J'ai besoin de quelques idées pour franchir le pas pour travailler pleinement. :)
Non, je ne peux pas simplement émuler un clavier USB HID et en rester là - il doit s'agir d'une émulation de clavier PS / 2. Oui, j'envoie des signaux corrects de création et de rupture - il gère même des combinaisons de touches très compliquées. Dans l'état actuel des choses, j'ai du code écrit pour mon Arduino comme indiqué ci-dessous (techniquement un Freeduino 1.22), et j'ai envoyé des touches via le moniteur série ou le terminal PuTTY, ainsi qu'avec un wrapper / pilote Python pratique qui envoie des données réelles Les informations de scancode PS / 2 - et me facilitent généralement la vie - allégeant également une partie de la charge de l'Arduino.
En ce moment, j'ai un croquis en cours d'exécution sur l'Arduino qui émule un clavier PS / 2. Naturellement, je dois démarrer ma machine "cible" (machine dans laquelle la prise PS / 2 entre), et je vois la "prise de contact" avoir lieu. Démarrez sur WinDoze, ouvrez le bloc-notes et appuyez sur les touches à l'écran (avec succès) en utilisant mon "pilote" Python. (Le pilote prend simplement la place du terminal Serial Monitor / PuTTY et lit / écrit sur le port série à l'aide d'un module appelé PySerial.) Tout cela se fait sur un AMD dans la carte mère ASUS "target".
Maintenant, le but est de le faire fonctionner sur ma "cible" basée sur la carte mère Intel dans Intel, je la branche, je démarre et aucun dé. J'ai donc un peu modifié le croquis pour essayer de me donner un aperçu de ce qui se passe réellement avec mon petit ami Ardy. La version après les mods est affichée ci-dessous. Si je comprends bien (le code a été "emprunté" à un autre message du forum Arduino.cc, ici ). la connexion est établie. La cible Intel ne dépasse pas les clignotements de la seconde période de 0,5 et la connexion série n'est jamais établie avec "l'hôte".
Ma question est la suivante: y a-t-il une différence majeure dans la façon dont les claviers ps / 2 établissent la communication avec leur machine cible? Est-ce vraiment une différence de conception ou devrais-je rechercher quelque chose de plus basique qui est le problème ici? J'ai entendu parler de la nécessité d'avoir des résistances de rappel sur les entrées données / horloge, mais cela devrait être géré dans le code, surtout parce qu'il FONCTIONNE sur une autre cible, mais pas sur celle sur laquelle je veux travailler.
Des idées? J'adorerais que cela fonctionne dès que possible - je vais continuer à faire le débogage, tous les pointeurs ou suggestions seraient grandement appréciés. Ils seront tous pris en considération car j'ai besoin d'un regard neuf sur cette question. Peut-être qu'une meilleure implémentation dans la bibliothèque ps2dev est nécessaire?
#include "ps2dev.h" // to emulate a PS/2 device
// Orange = 2
// Blue = 3
// Red = 5V (3 in)
// Black = GND (4 in)
// EXT Power, USB for COM only
PS2dev keyboard(3,2); // PS2dev object (2:data, 3:clock)
int enabled = 0; // pseudo variable for state of "keyboard"
boolean serialConnected = false;
int incomingByte = 0;
void ack() {
//acknowledge commands
while(keyboard.write(0xFA));
}
int kbdCmd(int command) {
unsigned char val;
switch (command) {
case 0xFF: //reset
ack();
//the while loop lets us wait for the host to be ready
while(keyboard.write(0xAA)!=0);
break;
case 0xFE: //resend
ack();
break;
case 0xF6: //set defaults
//enter stream mode
ack();
break;
case 0xF5: //disable data reporting
//FM
enabled = 0;
ack();
break;
case 0xF4: //enable data reporting
//FM
enabled = 1;
ack();
break;
case 0xF3: //set typematic rate
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xF2: //get device id
ack();
keyboard.write(0xAB);
keyboard.write(0x83);
break;
case 0xF0: //set scan code set
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xEE: //echo
//ack();
keyboard.write(0xEE);
break;
case 0xED: //set/reset LEDs
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
}
}
void connectHost() {
while (Serial.available() <= 0) {
Serial.print('A'); // send a capital A
delay(300);
}
}
void setup() {
pinMode(13, OUTPUT);
//establish serial connection with host
Serial.begin(9600);
// establish ps/2 connection with target
while(keyboard.write(0xAA)!=0){
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
}
delay(100);
connectHost();
Serial.println("\nSerial Host Connected");
Serial.flush();
}
void loop() {
unsigned char c;
if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
if(digitalRead(3)==LOW){
Serial.println("pin 3 is LOW");
} else {
Serial.println("pin 2 is LOW");
}
while(keyboard.read(&c));
kbdCmd(c);
Serial.print("Target: 0x");
Serial.println(c, HEX);
}
else {//if host device wants to send a command:
//echo ASCII code from terminal and write to ps/2
if(Serial.available() > 0) {
incomingByte = Serial.read();
keyboard.write(incomingByte);
Serial.print("Host: 0x");
Serial.print(incomingByte, HEX);
Serial.print(" ");
Serial.print(incomingByte);
Serial.print(" ");
Serial.println(incomingByte, BIN);
}
}
}
Réponses:
Si je comprends bien, vous connectez votre Arduino à deux machines cibles différentes et l'une fonctionne et l'autre non.
Il semble donc qu'il y ait une différence entre les exigences d'initialisation des deux machines. Sur cette page tout en bas se trouve une liste d'une séquence d'initialisation possible. Commencez par comparer votre initialisation à celle-ci.
Ce sera beaucoup plus facile en utilisant un analyseur logique. J'utilise l' Intronix Logicport , mais il y en a à la fois moins cher et meilleur, mais pas en même temps.
Taper dans un bus à collecteur ouvert est un peu lourd car vous ne voyez pas quel appareil parle. Cependant, si vous installez une résistance série à l'extrémité où le pullup n'est pas , vous pouvez dire par le niveau de tension quel appareil maintient le bus. Chaque bus à collecteur ouvert (comme PS / 2) a besoin de résistances de rappel, généralement elles sont intégrées dans le PC. Vous pouvez facilement voir les différents niveaux de tension sur un DSO. Avec seulement un LA, vous devez enregistrer deux fois avec différentes tensions de seuil.
la source
Étant donné que votre projet fonctionne avec une carte mère et non avec une autre, vous semblez avoir un cas classique de «conformité partielle aux spécifications» - dans votre projet, et peut-être même dans l'une des cartes mères. Mais la plupart des claviers fonctionneront avec n'importe quelle carte mère, donc une implémentation robuste devrait être portable. Le défi est que vous devrez comprendre pourquoi le vôtre ne l'est pas.
Vous pouvez peut-être le faire en regardant simplement le problème et en réfléchissant à la façon dont il est censé fonctionner (peut-être après une pause - ou un jour, la réponse vous frappera sous la douche), mais vous serez plus efficace si vous pouvez surveiller que se passe-t-il. Pour les problèmes électriques, cela signifie une portée, pour les protocoles, un analyseur logique. Il existe des options bon marché disponibles dans ce domaine, par exemple la carte "pirate de bus" qui a une capacité spécifique pour le protocole du clavier ou quelque chose basé sur FPGA qui pourrait avoir un tampon de capture plus long (voir sump.org).
Une autre chose que vous pourriez essayer serait d'utiliser un autre appareil, soit un microcontrôleur ou un FPGA, pour construire un hôte de clavier et l'utiliser pour tester votre projet vers les limites de la spécification.
la source
Je n'ai pas regardé la bibliothèque ps2dev pour voir exactement comment cela fonctionne, mais une chose me saute aux yeux.
Pour le moment, une seule tentative est effectuée pour se connecter à l'ordinateur "hôte". En cas d'échec, une seconde entière est attendue (LED allumée 0,5 s, LED éteinte 0,5 s) avant une nouvelle tentative.
Si la carte mère Intel n'attend pas assez longtemps pour la détection du clavier, il se peut qu'elle n'obtienne jamais la tentative de connexion avant de poursuivre sa séquence de démarrage.
Si vous diminuez le temps d'attente pour dire 0,1 s (changez les lignes de retard (500) en retard (50)), vous aurez peut-être de la chance.
Sinon, essayez encore plus vite. Enfer, essayez-le sans délai et voyez comment ça se passe.
la source