Problemi con l'emulatore tastiera Arduino PS / 2


10

Sì, ho cercato nei forum Arduino.cc e qui. Sì, ho trovato gli articoli riguardanti la libreria ps2dev. Sì, ho letto (ok, alcuni ho scremato) l'articolo di interfaccia PS / 2 definitivo su questo sito . Sì, ho questo lavoro, un po '. Ho bisogno di alcune idee per fare il salto per funzionare pienamente. :)

No, non posso semplicemente emulare una tastiera HID USB e lasciarla lì - deve essere un'emulazione della tastiera PS / 2. Sì, sto inviando segnali di creazione e interruzione adeguati: gestisce anche combinazioni di tasti molto complicate. Allo stato attuale, ho il codice scritto per il mio Arduino come pubblicato di seguito (tecnicamente un Freeduino 1.22) e ho inviato sequenze di tasti tramite il monitor Serial Monitor o il terminale PuTTY, nonché con un pratico wrapper / driver Python che invia Informazioni su scancode PS / 2 - e in generale mi semplificano molto la vita - anche togliendo un po 'di carico dall'Arduino.

In questo momento, ho uno schizzo in esecuzione su Arduino che emula una tastiera PS / 2. Ovviamente, devo avviare la mia macchina "target" (macchina su cui va inserita la PS / 2 Plug) e vedo che si verifica la "stretta di mano". Avvia su WinDoze, apri il blocco note e guida i tasti sullo schermo (con successo) usando il mio "driver" Python. (Il driver prende semplicemente posto sul terminale Serial Monitor / PuTTY e legge / scrive sulla porta seriale usando un modulo chiamato PySerial.) Tutto questo viene fatto su un AMD nella "scheda" della scheda madre ASUS.

Ora, l'obiettivo è farlo funzionare sul mio Intel in "target" basato su scheda madre Intel, lo collego, avvio e nessun dado. Quindi, ho modificato un po 'lo schizzo per provare a darmi un'idea di ciò che sta realmente accadendo sul mio piccolo amico Ardy. La versione dopo le mod è visualizzata di seguito. A quanto ho capito (il codice è stato "preso in prestito" da un altro post del forum Arduino.cc, qui ) Proverà prima a stabilire una connessione con il "target" su PS / 2, facendo lampeggiare il LED di bordo in un periodo di 0,5 secondi fino a quando il connessione stabilita. Il target Intel non supera il secondo periodo di 5 lampeggi e la connessione seriale non viene mai stabilita con l '"host".

La mia domanda è questa: c'è una grande differenza nel modo in cui le tastiere ps / 2 stabiliscono la comunicazione con la loro macchina target? È davvero una differenza di design o dovrei cercare qualcosa di più basilare che è il problema qui? Ho sentito parlare della necessità di resistori di pull-up sugli ingressi dati / clock, ma questo dovrebbe essere gestito nel codice, soprattutto perché FUNZIONA su un altro target, non quello su cui ho bisogno per lavorare.

Qualche idea? Mi piacerebbe farlo funzionare al più presto - Continuerò a fare il debug, qualsiasi suggerimento o suggerimento sarebbe molto apprezzato. Saranno tutti presi in piena considerazione perché ho bisogno di alcuni nuovi occhi su questo problema. Forse è necessaria una migliore implementazione nella libreria ps2dev?

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

Alcune domande: "Sketch" è Arduino-lingo per "programma"? Questa roba del driver Python è indipendente dalla macchina target, giusto? Il tuo problema è che funziona su una macchina target e non sull'altra, giusto? Hai provato ad avviare il target non funzionante con una tastiera PS / 2 collegata e poi a scambiarlo con Arduino?
AndreKR,

Sì, programma Sketch == in Ardu-lingo. Ho provato questo e non sembra funzionare (ma ho bisogno di modificare lo schizzo in modo che non attenda gli ACK dal bersaglio prima di inviare personaggi.) Ti farò sapere quando avrò la possibilità di testarlo più tardi oggi.
Chisaipete,

Quindi, ho testato il programma come mi hai suggerito, e funziona! Alla fine mi piacerebbe essere in grado di spegnere e riaccendere il target con l'emulatore di tastiera installato e di poter modificare le impostazioni del BIOS con esso. Quindi, sto pensando che la stretta di mano all'avvio sia disattivata?
Chisaipete,

Sì, probabilmente. Hai visto la sequenza di inizializzazione in fondo a computer-engineering.org/ps2keyboard ? Comincerei confrontando la mia sequenza con quella.
AndreKR,

1
Spiacente, ho lasciato che questa discussione diventasse viziata: non ho avuto il tempo di provare la soluzione di AndreKR. Inoltre, non sto usando resistori pullup, quindi è difficile determinare quale estremità non abbia resistori pullup :)
chisaipete

Risposte:


5

A quanto ho capito, connetti il ​​tuo Arduino a due diverse macchine target e su una funziona e dall'altra no.

Quindi sembra che ci sia una differenza tra i requisiti di inizializzazione delle due macchine. In questa pagina in fondo c'è un elenco di una possibile sequenza di inizializzazione. Inizia confrontando la tua inizializzazione con quella.

Sarà molto più semplice usando un analizzatore logico. Sto usando Intronix Logicport , ma ce ne sono entrambi più economici e migliori, anche se non allo stesso tempo.

Toccare un bus a collettore aperto è un po 'complicato perché non si vede quale dispositivo sta parlando. Tuttavia, se si inserisce un resistore serie all'estremità in cui il pullup non è presente , è possibile stabilire dal livello di tensione quale dispositivo sta tenendo premuto il bus. Ogni bus open collector (come PS / 2) ha bisogno di resistori pullup, di solito sono integrati nel PC. Puoi vedere facilmente i diversi livelli di tensione su un DSO. Con solo un LA devi registrare due volte con tensioni di soglia diverse.


La decisione su chi dare la generosità è stata più difficile di quanto mi aspettassi, ma la tua risposta ha ottenuto il maggior numero di voti e preferisco leggermente. Avrei preferito premiare tutti!
Kortuk,

3

Dato che il tuo progetto funziona con una scheda madre e non con un'altra, sembra che tu abbia un classico caso di "conformità parziale alle specifiche" - nel tuo progetto, e forse anche in una delle schede madri. Ma la maggior parte delle tastiere funzionerà con qualsiasi scheda madre, quindi un'implementazione robusta dovrebbe essere portatile. La sfida è che dovrai capire perché la tua non lo è.

Potresti riuscire a farlo semplicemente fissando il problema e pensando a come dovrebbe funzionare (forse dopo una pausa - o un giorno la risposta ti colpisce sotto la doccia) ma sarai più efficace se riesci a monitorare cosa sta succedendo. Per problemi elettrici ciò significa un ambito, per protocolli un analizzatore logico. Ci sono alcune opzioni economiche disponibili in quella zona, ad esempio la scheda "bus pirate" che ha alcune capacità specifiche per il protocollo della tastiera o qualcosa basato su FPGA che potrebbe avere un buffer di acquisizione più lungo (vedi sump.org).

Un'altra cosa che potresti provare sarebbe usare un altro dispositivo, un microcontrollore o un FPGA, per costruire un host di tastiera e usarlo per testare il tuo progetto verso i limiti delle specifiche.


2

Non ho guardato la libreria ps2dev per vedere esattamente come funziona, ma una cosa mi salta fuori.

Al momento viene effettuato un singolo tentativo di connessione al computer "host". In caso contrario, viene atteso un secondo intero (LED acceso 0,5 secondi, LED spento 0,5 secondi) prima di effettuare un altro tentativo.

Se la scheda madre Intel non è in attesa abbastanza a lungo per il rilevamento della tastiera, potrebbe non riuscire mai a ottenere il tentativo di connessione prima di continuare la sequenza di avvio.

Se diminuisci il tempo di attesa per dire 0,1 s (modifica le linee di ritardo (500) in ritardo (50)) potresti avere un po 'di fortuna.

In caso contrario, prova ancora più velocemente. Cavolo, provalo anche senza ritardi e guarda come va.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.