Problemas do emulador de teclado Arduino PS / 2

10

Sim, procurei nos fóruns do Arduino.cc e aqui. Sim, encontrei os artigos relacionados à biblioteca ps2dev. Sim, li (ok, alguns foram os que li) o artigo definitivo da interface PS / 2 neste site . Sim, eu tenho esse trabalho, meio. Preciso de algumas idéias para dar o salto para o pleno funcionamento. :)

Não, não posso simplesmente emular um teclado USB HID e deixá-lo assim - ele precisa ser uma emulação de teclado PS / 2. Sim, estou enviando sinais adequados de fabricação e interrupção - ele até lida com combinações de teclas muito complicadas. Como está agora, tenho um código escrito para o meu Arduino, como publicado abaixo (tecnicamente um Freeduino 1.22), e enviei pressionamentos de tecla pelo Serial Monitor ou pelo terminal PuTTY, além de um prático wrapper / driver Python que envia mensagens reais. As informações do scancode do PS / 2 - e geralmente facilitam minha vida - também diminuindo parte da carga do Arduino.

No momento, tenho um esboço em execução no Arduino que emula um teclado PS / 2. Naturalmente, tenho que inicializar minha máquina "alvo" (máquina na qual o PS / 2 Plug entra) e vejo o "aperto de mão". Inicialize no WinDoze, abra o bloco de notas e pressione as teclas pressionadas na tela (com sucesso) usando o meu "driver" do Python. (O driver simplesmente ocorre no terminal Serial Monitor / PuTTY e lê / grava na porta serial usando um módulo chamado PySerial.) Isso tudo é feito em um "destino" da placa-mãe AMD na ASUS.

Agora, o objetivo é fazê-lo funcionar na minha Intel na placa-mãe Intel "target", eu conecto, inicializo e não dou dados. Então, modifiquei um pouco o esboço para tentar me informar do que realmente está acontecendo com meu pequeno amigo Ardy. A versão após os mods é exibida abaixo. Pelo que entendi (o código foi "emprestado" de outra postagem no fórum do Arduino.cc, aqui ) Ele tentará estabelecer uma conexão com o "destino" no PS / 2 primeiro, piscando o LED integrado em um período de 0,5 segundo até o conexão estabelecida. O destino da Intel não passa dos 0,5 segundo período piscando e a conexão serial nunca é estabelecida com o "host".

Minha pergunta é a seguinte: existe uma grande diferença na maneira como os teclados ps / 2 estabelecem comunicação com a máquina de destino? É realmente uma diferença de design ou devo procurar algo mais básico que seja o problema aqui? Ouvi algo sobre a necessidade de resistores pull-up nas entradas de dados / relógio, mas isso deve ser tratado no código, especialmente porque está FUNCIONANDO em outro alvo, mas não no que eu preciso trabalhar.

Alguma ideia? Eu adoraria fazer isso funcionar o mais rápido possível - continuarei fazendo a depuração, quaisquer sugestões ou sugestões serão muito apreciadas. Todos serão levados em consideração porque preciso de novos olhos sobre esse assunto. Talvez seja necessária uma melhor implementação na 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);
    }
  }
}
chisaipete
fonte
Algumas perguntas: "Sketch" é o Arduino-jargão para "program"? Esse driver de python é independente da máquina de destino, certo? Seu problema é que ele funciona em uma máquina de destino e não na outra, certo? Você tentou inicializar o destino que não funcionava com um teclado PS / 2 conectado e depois o trocou com o Arduino?
AndreKR
Sim, Sketch == programa em Ardu-jargão. Eu tentei isso e parece que não funcionou (mas preciso modificar o esboço para não esperar os ACKs do destino antes de enviar os personagens.) Avisarei quando tiver a chance de testá-lo hoje mais tarde.
Chisaipete
Então, testei o programa como você sugeriu e funciona! No final, eu gostaria de poder ligar e desligar o alvo com o emulador de teclado instalado e alterar as configurações do BIOS com ele. Então, estou pensando que o aperto de mão inicial está desligado?
chisaipete
Sim provavelmente. Você viu a sequência de inicialização na parte inferior de computer-engineering.org/ps2keyboard ? Eu começaria comparando minha sequência a isso.
precisa saber é o seguinte
11
Desculpe, deixei esse tópico obsoleto - não tive tempo de experimentar a solução do AndreKR. Além disso, eu não estou usando resistor pull-up, por isso é difícil determinar qual final não tem pullup resistências :)
chisaipete

Respostas:

5

Pelo que entendi, você conecta seu Arduino a duas máquinas-alvo diferentes e, em uma, ela funciona e, na outra, não.

Portanto, parece que há uma diferença entre os requisitos de inicialização das duas máquinas. Em desta página na parte inferior há uma listagem de uma seqüência de inicialização possível. Comece comparando sua inicialização àquela.

Será muito mais fácil usar um analisador lógico. Estou usando o Intronix Logicport , mas existem os mais baratos e os melhores, embora não ao mesmo tempo.

Bater em um barramento de coletor aberto é um pouco complicado, porque você não vê qual dispositivo está falando. No entanto, se você colocar um resistor em série no final, onde o pullup não está , poderá saber pelo nível de tensão qual dispositivo está pressionando o barramento. Todo barramento de coletor aberto (como PS / 2) precisa de resistores de pullup, geralmente eles são embutidos no PC. Você pode ver os diferentes níveis de tensão facilmente em um DSO. Com apenas um LA, você deve gravar duas vezes com tensões de limiar diferentes.

AndreKR
fonte
A decisão de quem dar a recompensa foi mais difícil do que eu esperava, mas sua resposta obteve mais votos e prefiro um pouco. Eu teria preferido recompensar todos!
Kortuk
3

Dado que seu projeto funciona com uma placa-mãe e não com outra, você parece ter um caso clássico de "conformidade parcial de especificações" - em seu projeto e talvez até em uma das placas-mãe. Mas a maioria dos teclados funciona com qualquer placa-mãe, portanto, uma implementação robusta deve ser portátil. O desafio é que você terá que descobrir por que o seu não é.

Você pode fazer isso apenas olhando para o problema e pensando em como ele deve funcionar (talvez depois de um intervalo - ou um dia a resposta o acerte no chuveiro), mas será mais eficaz se puder monitorar o que está acontecendo. Para questões elétricas que significam um escopo, para protocolos um analisador lógico. Existem algumas opções baratas disponíveis nessa área, por exemplo, a placa "barramento pirata", que possui alguma capacidade específica para protocolo de teclado ou algo baseado em FPGA, que pode ter um buffer de captura mais longo (consulte sump.org).

Outra coisa que você poderia tentar seria usar outro dispositivo, um microcontrolador ou um FPGA, para criar um host de teclado e usá-lo para testar seu projeto dentro dos limites da especificação.

Chris Stratton
fonte
2

Eu não olhei para a biblioteca ps2dev para ver exatamente como ela funciona, mas uma coisa me impressiona.

No momento, é feita uma única tentativa de conexão com o computador "host". Quando isso falha, um segundo inteiro é aguardado (LED aceso 0,5s, LED apagado 0,5s) antes de outra tentativa.

Se a placa-mãe da Intel não estiver aguardando o tempo suficiente para a detecção do teclado, ela poderá nunca estar recebendo a tentativa de conexão antes de continuar sua sequência de inicialização.

Se você diminuir o tempo de espera para dizer 0,1s (altere as linhas de atraso (500) para atraso (50)), poderá ter alguma sorte.

Caso contrário, tente ainda mais rápido. Inferno, até tente sem demora e veja como isso acontece.

Majenko
fonte