Problemas con el emulador de teclado PS / 2 de Arduino

10

Sí, he buscado en los foros de Arduino.cc y aquí. Sí, he encontrado los artículos sobre la biblioteca ps2dev. Sí, he leído (bueno, algunos he leído) el artículo de la interfaz PS / 2 definitiva en este sitio web . Sí, tengo este trabajo, un poco. Necesito algunas ideas para dar el salto para trabajar plenamente. :)

No, no puedo simplemente emular un teclado USB HID y dejarlo así: tiene que ser una emulación de teclado PS / 2. Sí, estoy enviando señales correctas de marca y corte, incluso maneja combinaciones de teclas muy complicadas. Tal como está ahora, tengo un código escrito para mi Arduino como se muestra a continuación (técnicamente es un Freeduino 1.22), y he enviado pulsaciones de teclas a través del monitor Serial o el terminal PuTTY, así como con un envoltorio / controlador Python práctico que envía datos reales. La información de PS / 2 scancode, y en general hace que mi vida sea mucho más fácil, también quita algo de la carga del Arduino.

Ahora mismo, tengo un boceto en ejecución en el Arduino que emula un teclado PS / 2. Naturalmente, tengo que arrancar mi máquina "objetivo" (la máquina en la que se conecta el enchufe PS / 2), y veo que tiene lugar el "apretón de manos". Arranque en WinDoze, abra el bloc de notas y dirija las pulsaciones a la pantalla (con éxito) usando mi "controlador" de Python. (El controlador simplemente toma lugar en el terminal Serial Monitor / PuTTY y lee / escribe en el puerto serie usando un módulo llamado PySerial). Todo esto se hace en un AMD en la placa base de ASUS "target".

Ahora, el objetivo es hacer que funcione en mi Intel en el "objetivo" basado en la placa base de Intel, lo enchufo, arranco y no doy. Entonces, modifiqué un poco el boceto para intentar hacerme una idea de lo que realmente está pasando con mi pequeño amigo Ardy. La versión después de los mods se muestra a continuación. Como lo entiendo (el código fue "tomado prestado" de otra publicación del foro Arduino.cc, aquí ) Intentará establecer una conexión con el "objetivo" a través de PS / 2 primero, parpadeando el LED de a bordo durante un período de 0,5 segundos hasta que se establezca la conexión. El objetivo de Intel no pasa el parpadeo de .5 segundos y la conexión en serie nunca se establece con el "host".

Mi pregunta es la siguiente: ¿existe una diferencia importante en la forma en que los teclados ps / 2 establecen la comunicación con su máquina de destino? ¿Es realmente una diferencia de diseño o debería estar buscando algo más básico que es el problema aquí? He escuchado algo sobre la necesidad de resistencias de pull-up en las entradas de datos / reloj, pero eso debería manejarse en el código, especialmente porque está TRABAJANDO en otro objetivo, pero no en el que necesito que funcione.

¿Alguna idea? Me encantaría que esto funcione lo antes posible. Voy a seguir haciendo la depuración, cualquier sugerencia o sugerencia sería muy apreciada. A todos se les dará plena consideración porque necesito algunos ojos nuevos sobre este tema. Quizás se necesita una mejor implementación en la biblioteca 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);
    }
  }
}
    
pregunta chisaipete

3 respuestas

5

Según tengo entendido, conectas tu Arduino a dos máquinas objetivo diferentes y en una funciona y en la otra no.

Parece que hay una diferencia entre los requisitos de inicialización de las dos máquinas. En esta página en la parte inferior hay una lista de una posible secuencia de inicialización. Comience por comparar su inicialización con esa.

Será mucho más fácil usando un analizador lógico. Estoy utilizando el Intronix Logicport , pero hay otros más baratos y mejores, aunque no al mismo tiempo.

Entrar en un bus de colector abierto es un poco incómodo porque no ves qué dispositivo está hablando. Sin embargo, si coloca una resistencia en serie en el extremo donde el pullup no es no , puede saber por el nivel de voltaje qué dispositivo está presionando el bus. Cada bus de colector abierto (como PS / 2) necesita resistencias de extracción, generalmente están incorporadas en la PC. Puedes ver los diferentes niveles de voltaje fácilmente en un DSO. Con solo un LA tienes que grabar dos veces con diferentes voltajes de umbral.

    
respondido por el AndreKR
3

Dado que su proyecto funciona con una placa base y no con otra, parece que tiene un caso clásico de "cumplimiento parcial de especificaciones" en su proyecto, y tal vez incluso en una de las placas base. Pero la mayoría de los teclados funcionarán con cualquier placa base, por lo que una implementación robusta debería ser portátil. El desafío es que tendrás que averiguar por qué el tuyo no lo es.

Es posible que pueda hacer esto simplemente observando el problema y pensando cómo se supone que funciona (quizás después de un descanso, o un día la respuesta lo golpee en la ducha), pero será más efectivo si Puedes monitorear lo que está pasando. Para los problemas eléctricos que significa un alcance, para los protocolos un analizador lógico. Hay algunas opciones baratas disponibles en esa área, por ejemplo, la placa "bus pirata" que tiene alguna capacidad específica para el protocolo de teclado o algo basado en FPGA que podría tener un búfer de captura más largo (vea sump.org).

Otra cosa que podrías intentar sería usar otro dispositivo, ya sea un microcontrolador o un FPGA, para construir un host de teclado y usarlo para probar tu proyecto hacia los límites de la especificación.

    
respondido por el Chris Stratton
2

No he mirado la biblioteca ps2dev para ver exactamente cómo funciona, pero una cosa me sobresalta.

En el momento en que se realiza un solo intento para conectarse a la computadora "host". Cuando eso falla, se espera un segundo entero (LED en 0,5 s, LED apagado 0,5 s) antes de realizar otro intento.

Si la placa base Intel no está esperando el tiempo suficiente para la detección del teclado, es posible que nunca obtenga el intento de conexión antes de que continúe su secuencia de arranque.

Si reduce el tiempo de espera para decir 0.1s (cambie el retardo (500) líneas para retrasar (50)) puede tener algo de suerte.

Si no, inténtalo aún más rápido. Demonios, incluso inténtalo sin demora y mira cómo va.

    
respondido por el Majenko

Lea otras preguntas en las etiquetas