Problemy z emulatorem klawiatury Arduino PS / 2

10

Tak, przeszukałem fora Arduino.cc i tutaj. Tak, znalazłem artykuły dotyczące biblioteki ps2dev. Tak, przeczytałem (w porządku, trochę przeszukałem) ostateczny artykuł na temat interfejsu PS / 2 na tej stronie . Tak, to działa. Potrzebuję kilku pomysłów, aby zrobić krok do pełnego działania. :)

Nie, nie mogę po prostu emulować klawiatury USB HID i zostawić ją przy tym - musi to być emulacja klawiatury PS / 2. Tak, wysyłam odpowiednie sygnały make i break - obsługuje nawet bardzo skomplikowane kombinacje klawiszy. W tej chwili mam napisany kod dla mojego Arduino, jak napisano poniżej (technicznie Freeduino 1.22), i wysłałem naciśnięcia klawiszy za pomocą Serial Monitor lub terminala PuTTY, a także z poręcznym opakowaniem / sterownikiem Python, który wysyła rzeczywiste Informacja o skancodzie PS / 2 - i ogólnie znacznie ułatwia mi życie - również odciąża Arduino.

W tej chwili mam szkic działający na Arduino, który emuluje klawiaturę PS / 2. Oczywiście muszę uruchomić moją maszynę „docelową” (maszynę, do której wchodzi wtyczka PS / 2) i widzę, że odbywa się „handshake”. Uruchom do WinDoze, otwórz notatnik i poprowadź naciśnięcia klawiszy na ekranie (z powodzeniem) za pomocą mojego „sterownika” Pythona. (Sterownik po prostu odbywa się na terminalu Serial Monitor / PuTTY i odczytuje / zapisuje do portu szeregowego za pomocą modułu o nazwie PySerial.) Wszystko to odbywa się na AMD w płycie docelowej płyty głównej ASUS.

Teraz celem jest, aby działał na moim procesorze Intel na płycie głównej „Intel” na płycie głównej Intela, podłączam go, uruchamiam i nie ma kości. Zmodyfikowałem więc trochę szkic, aby dowiedzieć się, co się właściwie dzieje z moim małym przyjacielem Ardy. Wersja po modyfikacjach jest wyświetlana poniżej. Jak rozumiem (kod został „wypożyczony” z innego postu na forum Arduino.cc, tutaj ) Najpierw spróbuje nawiązać połączenie z „celem” na PS / 2, mrugając diodę pokładową co 0,5 sekundy, aż do połączenie jest ustanowione. Cel Intela nie przekroczył 0,5 sekundy, a połączenie szeregowe nigdy nie jest ustanawiane z „hostem”.

Moje pytanie brzmi: czy istnieje zasadnicza różnica w sposobie, w jaki klawiatury ps / 2 nawiązują komunikację z maszyną docelową? Czy to naprawdę różnica w projekcie, czy powinienem szukać czegoś bardziej podstawowego, o co tu chodzi? Słyszałem coś o potrzebie podciągania rezystorów na wejściach danych / zegara, ale to powinno być załatwione w kodzie, szczególnie dlatego, że DZIAŁA na innym celu, po prostu nie tym, nad którym muszę pracować.

Jakieś pomysły? Chciałbym uzyskać ten działający jak najszybciej - zamierzam nadal debugować, wszelkie wskazówki lub sugestie byłyby bardzo mile widziane. Wszyscy zostaną dokładnie rozważeni, ponieważ potrzebuję świeżego spojrzenia na tę kwestię. Być może potrzebna jest lepsza implementacja w bibliotece 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
źródło
Kilka pytań: „Szkic” to Arduino-lingo dla „programu”? Ten sterownik Pythona jest niezależny od maszyny docelowej, prawda? Problem polega na tym, że działa on na jednej maszynie docelowej, a nie na drugiej, prawda? Czy próbowałeś uruchomić niedziałający cel z podłączoną klawiaturą PS / 2, a następnie zamienić go z Arduino?
AndreKR,
Tak, Sketch == program w Ardu-lingo. Próbowałem tego i wydaje się, że to nie działa (ale muszę zmodyfikować szkic, aby nie czekał na ACK od celu przed wysłaniem postaci). Dam ci znać, kiedy będę miał okazję go przetestować później dzisiaj.
chisaipete,
Przetestowałem program zgodnie z sugestią i działa! Na koniec chciałbym móc włączyć i wyłączyć cyklicznie cel przy zainstalowanym emulatorze klawiatury i móc za jego pomocą zmieniać ustawienia BIOS-u. Więc myślę, że uścisk dłoni przy rozruchu jest wyłączony?
chisaipete
Tak, prawdopodobnie. Czy widziałeś sekwencję inicjalizacji na samym dole computer-engineering.org/ps2keyboard ? Zacznę od porównania mojej sekwencji z tym.
AndreKR,
1
Niestety, pozwoliłem temu wątkowi przestać działać - nie miałem czasu wypróbować rozwiązania AndreKR. Poza tym nie używam rezystorów pullup, więc trudno jest ustalić, który koniec nie ma rezystorów pullup :)
chisaipete

Odpowiedzi:

5

Jak rozumiem, podłączasz swoje Arduino do dwóch różnych docelowych maszyn, na jednej działa, a na drugiej nie.

Wydaje się więc, że istnieje różnica między wymaganiami inicjalizacji obu komputerów. Na tej stronie na samym dole znajduje się lista możliwych sekwencji inicjalizacji. Zacznij od porównania swojej inicjalizacji z tą.

Będzie to o wiele łatwiejsze dzięki zastosowaniu analizatora logicznego. Korzystam z Intronix Logicport , ale są zarówno tańsze, jak i lepsze, choć nie w tym samym czasie.

Dotykanie do magistrali z otwartym kolektorem jest nieco kłopotliwe, ponieważ nie widać, które urządzenie mówi. Jeśli jednak umieścisz rezystor szeregowy na końcu, na którym nie występuje pullup , możesz po poziomie napięcia stwierdzić, które urządzenie przytrzymuje magistralę. Każda magistrala typu otwarty kolektor (jak PS / 2) potrzebuje rezystorów podciągających, zwykle są one wbudowane w komputer. Można łatwo zobaczyć różne poziomy napięcia w DSO. Tylko LA wymaga dwukrotnego nagrywania przy różnych napięciach progowych.

AndreKR
źródło
Decyzja o przyznaniu nagrody była trudniejsza niż się spodziewałem, ale twoja odpowiedź zdobyła najwięcej głosów i trochę wolę. Wolałbym nagradzać wszystkich!
Kortuk
3

Biorąc pod uwagę, że twój projekt działa z jedną płytą główną, a nie drugą, wydaje się, że masz klasyczny przypadek „częściowej zgodności specyfikacji” - w swoim projekcie, a może nawet na jednej z płyt głównych. Ale większość klawiatur będzie współpracować z dowolną płytą główną, więc solidna implementacja powinna być przenośna. Wyzwanie polega na tym, że musisz dowiedzieć się, dlaczego tak nie jest.

Możesz to zrobić, wpatrując się w problem i zastanawiając się, jak powinien on działać (być może po przerwie - lub któregoś dnia odpowiedź trafi cię pod prysznic), ale będziesz bardziej skuteczny, jeśli będziesz w stanie monitorować co się dzieje. W przypadku problemów elektrycznych oznacza to zakres, w przypadku protokołów analizator logiki. Istnieją pewne tanie opcje dostępne w tym obszarze, na przykład płyta „pirata autobusu”, która ma pewne specyficzne możliwości protokołu klawiatury lub coś opartego na FPGA, który może mieć dłuższy bufor przechwytywania (patrz sump.org).

Inną rzeczą, którą możesz wypróbować, byłoby użycie innego urządzenia, mikrokontrolera lub FPGA, do zbudowania hosta klawiatury i użycia go do przetestowania projektu pod kątem specyfikacji.

Chris Stratton
źródło
2

Nie patrzyłem na bibliotekę ps2dev, aby zobaczyć, jak to dokładnie działa, ale jedna rzecz mnie zaskakuje.

W tej chwili podejmowana jest jedna próba połączenia z komputerem „hosta”. Kiedy to się nie powiedzie, cała kolejna sekunda (dioda LED świeci 0,5 s, dioda LED świeci 0,5 s) przed podjęciem kolejnej próby.

Jeśli płyta główna Intela nie czeka wystarczająco długo na wykrycie klawiatury, może nigdy nie uzyskać próby połączenia przed kontynuowaniem sekwencji rozruchowej.

Jeśli skrócisz czas oczekiwania do 0,1 sekundy (zmień linie opóźnienia (500) na opóźnienie (50)), możesz mieć szczęście.

Jeśli nie, spróbuj jeszcze szybciej. Do diabła, nawet spróbuj go w ogóle bez zwłoki i zobacz, jak to idzie.

Majenko
źródło