Problèmes liés à l'émulateur de clavier Arduino PS / 2


10

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);
    }
  }
}

Quelques questions: "Sketch" est Arduino-lingo pour "programme"? Ce truc de pilote python est indépendant de la machine cible, non? Votre problème est qu'il fonctionne sur une machine cible et non sur l'autre, non? Avez-vous essayé de démarrer la cible non fonctionnelle avec un clavier PS / 2 attaché, puis de l'échanger avec l'Arduino?
AndreKR

Oui, programme Sketch == en Ardu-lingo. J'ai essayé et cela ne semble pas fonctionner (mais je dois modifier le croquis pour qu'il n'attende pas les ACK de la cible avant d'envoyer des caractères.) Je vous ferai savoir quand j'aurai la chance de le tester plus tard aujourd'hui.
chisaipete

J'ai donc testé le programme comme vous l'avez suggéré, et ça marche! À la fin, j'aimerais pouvoir redémarrer la cible avec l'émulateur de clavier installé et pouvoir modifier les paramètres du BIOS avec. Donc, je pense que la poignée de main de démarrage est désactivée?
chisaipete

Oui probablement. Avez-vous vu la séquence d'initialisation tout en bas de computer-engineering.org/ps2keyboard ? Je commencerais par comparer ma séquence à cela.
AndreKR

1
Désolé, j'ai laissé ce fil devenir obsolète - je n'ai pas eu le temps d'essayer la solution d'AndreKR. De plus, je n'utilise pas de résistances de pullup, il est donc difficile de déterminer quelle extrémité n'a pas de résistances de pullup :)
chisaipete

Réponses:


5

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 décision de qui donner la prime a été plus difficile que prévu, mais votre réponse a recueilli le plus de votes et je préfère légèrement. J'aurais préféré récompenser tout le monde!
Kortuk

3

É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.


2

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.