/*************************************************************************** * ________ _______ ______ * / /| / _____/| /___ /| * / // / / / /___ _|/ _|__/ / / * __/_______/___/____ _/|___/_____/___________/ / / / / / / * / / ___|/ |___/ / / / /___ |/ / / / / / / / * /___/ / /______/ / /_____/| * |___|/ |______|/ |_____|/ * * * Projekt: PS2 * Filename: ps2drv.c * Autor: Fabian Heusser / Pascal Näf www.w3p.ch/ps2 * Compiler, Language: HIWARE V5.0 C * Target: Medusa-Trainer * *-------------------------------------------------------------------------- * Änderungen: * * CVS: $Revision: 1.6 $ * * Version Datum Autor Beschreibung der Änderung * * 0.0 2002-05-28 hef Erstellung * 0.0 2002-06-11 hef read und write funtionieren einwandfrei. * 0.0 2002-06-12 hef getch funtioniert * 0.0 2002-06-13 hef Kommentare * *-------------------------------------------------------------------------- * Kurzbeschreibung: * * Dieser Treiber erlaubt das einfache anschliessen und ansteuern einer * MF-II resp. PS/2 Tastatur. * * Dieses Modul implementiert die Serielle Übertragung von un zur Tastatur * Plus einige User Funktionen wie getch() welches der ASCII-Code der * gedrückten Taste zurückliefert. * *-------------------------------------------------------------------------- * LEGAL NOTICE * THIS PROJECT AND ITS FILES ARE COPYRIGHTED BY THE AUTHORS * THIS PROJECT CAN BE COPIED, MODIFIED AND DISTRIBUTED * UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENCE * * **************************************************************************/ #include #include "Lcdrv_PC.h" /************************************************************************************************* KONSTATEN UND DEFINTIONEN *************************************************************************************************/ /************************************************************************** * Hier wird bestimmt wo die Tastatur angeschlossen wird. * * Standard ist Porta.0 für den 'Clock' und Porta.1 für 'Data'. * * STECKERBELEGUNG * =============== * * MINI-DIN 6 POL (PS/2) DIN 5-POL (AT) * ____ ____ * / `´ \ 1. Clock / `´ \ 1. Clcok * / 4 3 \ 2. Ground / \ 2. Data * |5 2| 3. Data | | 3. N/C * | || | 4. N/C |1 3| 4. GND * \6 || 1/ 5. VCC (+5V/300mA) \4 5/ 5. VCC (+5V/300mA) * \____/ 6. N/C \__2_/ * * */ #define KeyBoard PORTA_ #define Clock PA0 #define Data PA1 #define Dir DDRA_ #define ClockDir DDA0 #define DataDir DDA1 #define Input 0x00; //Wert welcher ins DDR geschrieben werden muss um den Port als Input zu Benutzen #define Output 0x01; //Wert welcher ins DDR geschrieben werden muss um den Port als Output zu Benutzen /************************************************************************** * SCANCODE TO ASCII CODE * * hier werden Tasten bzw. Scancodes auf Asciicodes gemappt. * Beispiel: Taste A entspricht Scancode 0x1C und hat ASCII Code 0x61 * So finden wir in Spalte 'C' Zeile '1' den ASCII Code 0x61 */ // 0 1 2 3 4 5 6 7 8 9 A B C D E F unsigned char scancodes[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0 0, 0, 0, 0, 0,0x71,0x31, 0, 0, 0,0x7A,0x73,0x61,0x77,0x32, 0, //1 0,0x63,0x78,0x64,0x65,0x34,0x33, 0, 0,0x20,0x76,0x66,0x74,0x72,0x35, 0, //2 0,0x6E,0x62,0x68,0x67,0x79,0x36, 0, 0, 0,0x6D,0x6A,0x75,0x37,0x38, 0, //3 0, 0,0x6B,0x69,0x6F,0x30,0x39, 0, 0, 0, 0,0x6C, 0,0x70,0x2D, 0, //4 0, 0, 0, 0, 0,0x3D, 0, 0, 0, 0,0x0D, 0, 0, 0, 0, 0, //5 0, 0, 0, 0, 0, 0,0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, //6 0, 0, 0, 0, 0, 0,0x76, 0, 0, 0, 0, 0, 0, 0, 0, 0, //7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //F /************************************************************************************** SUPPORT FUNKTIONEN ***************************************************************************************/ //************************************************************************** //Wartet bis Keyboard.Clock auf 1 geht, ist er schon 1 wird nicht gewartet. void awaitForClockHigh(){ while (KeyBoard.Clock != 1) {}// wait for Clock going high } //************************************************************************** //Wartet bis Keyboard.Clock auf 0 geht, ist er schon 0 wird nicht gewartet. void awaitForClockLow(){ while (KeyBoard.Clock != 0) {}// wait for Clock going low } //************************************************************************** //Wartet auf die Nächste fallende Flanke am Keyboard.Clock void awaitFallingEdge(){ awaitForClockHigh(); awaitForClockLow(); } //************************************************************************** //Loopt ein bisschen // //@param loops (unsigned char) anzahl loops die gemacht werden sollen. void delay(unsigned char loops){ int i; for(i = 0; i> 1; awaitFallingEdge(); } //last bat not least the parity bit KeyBoard.Data = ~(parity & 0x01); //odd parity awaitFallingEdge(); //Release the Data Line Dir.DataDir = Input; //wait for the device to bring the Data Low while (KeyBoard.Data == 1){} awaitForClockLow(); //wait for the device to release Data and Clock //This could lock the programm for a while if the keybord don't behavour like we think while (KeyBoard.Data == 0 || KeyBoard.Clock ==0 ) {} delay(20); Dir.ClockDir = Output; KeyBoard.Data = 0; } /***************************************************************** * char READ() - Liest Zeichen vom der Tastatur * * Diese Prozedur setzt den Host auf ready, wartet bis ein Zeichen * empfangn wurde (also Blockierend), und setzt dann der Host wieder auf Busy. * * Ist die Übertragung gescheitert wird 0x00 zurückgegeben. * (Die Tastatur selbst sendet bei einem Fehler 0x00 oder 0xFF) * * * @return unsigned char Zeichen, das gelesen wurde. */ unsigned char read() { unsigned char i = 0; unsigned char data = 0; unsigned char parity = 0; unsigned char inbit = 0; //relase the Clock. That's the sign for the keybord that it can send Data. -> ready Dir.ClockDir = Input; Dir.DataDir = Input; //wait of falling edge with timeout. awaitFallingEdge(); //the StartBit must be zero if (KeyBoard.Data != 0) { Dir.ClockDir = Output; KeyBoard.Clock = 0x00;// false startbit return 0x00; } //read the Byte for (i=0; i<8; i++){ awaitFallingEdge(); inbit = KeyBoard.Data; parity = parity + inbit; //we place the bit read at the most significant Position then shift the whole Thing rigth. //(first bit would be the least significant at the end) data = data >> 1; inbit = inbit << 7; data = data | inbit; } // Paritätsbit awaitFallingEdge(); if (KeyBoard.Data == (parity & 0x01)) { Dir.ClockDir = Output; KeyBoard.Clock = 0x00;// false parity bit return 0x00; } //wait for the Stop Bit awaitFallingEdge(); awaitForClockHigh(); delay(20); //set Clock to Zero to sign that the host isn't Ready. Dir.ClockDir = Output; KeyBoard.Clock = 0x00; return data; } /************************************************************************************* USER FUNCTIONS **************************************************************************************/ /************************************************************************* * unsigned char getScanCode() - Liest das erste Zeichen im Tastatur Buffer * * Dies Prozedur liest ein Zeichen mittels der read() Funktion ein und liefert es zurück. * falls die Tastatur oder die read methode einen Fehler generiert wird die Tastatur aufgefordert * das letzte Zeichen erneut zu senden. Geht das 10 mal schief wir das letzte * gelesene Zeichen zurückgegeben. * * */ unsigned char getScanCode() { unsigned char ch = 0x00; unsigned char i = 0; delay(20); ch = read(); //we ask the keybord to retransmit the last char if we read an error; //we do this a maximum of 10 times; while ((ch == 0x00 || ch == 0xFF ) && i<10){ write(0xFE); ch = read(); i++; } return ch; } /************************************************************************* * unsigned char GETCH() - Liest Zeichen von der Tastatur und liefert das ASCII equivalent zurück. * * Dies Prozedur liest ein Zeichen mittels der getScanCode() Funktion ein und übersetzt diesen mittels * dem scancodes[] Arrays in ASCII-Codes zurück. * Wurde die gedrückte Taste nicht im Scancodes Array gefunden liefert die Prozedur 0x00 zurück, so * auch bei erweiterten scancodes. * * Wird ein Break-Code empfangen wird er ignoiert. * * */ unsigned char getch() { unsigned char ch = getScanCode(); //detect brake code; we use while because if wê release SHIFT-A we got 2 break codes... while (ch==0xF0) { ch = getScanCode(); // read witch key was relased ch = getScanCode(); // read the next key } return scancodes[ch]; } /************************************************************************* * unsigned char scancode2ascii(unsigned char scancode) - wandelt ein Scan Code in ein ASCII Zeichen um * * return ASCII-Code welcher durch dem Scancode representiert wird oder 0 fals das nicht möglich ist. * */ unsigned char scancode2ascii(unsigned char scancode){ return scancodes[scancode]; } /************************************************************************* * void setLED(code) - Setz die NumLock CapsLock und ScrollLock LED auf der Tastatur * * Diese Funktion setzt mittels Kommando 0xED die LEDs auf der Tastatur * Der zu übergebende Parameter setzt sich wie folgt zusammen: * * XXXX XCNS * ||°-Scroll Lock * |°--Num Lock * °---Caps Lock * */ void setLED(unsigned char code) { unsigned char ch = 0; write(0xED); ch = getScanCode(); if( ch != 0xFA ) {return;} write(code & 0x07); } /************************************************************************* * unsigned char testKB() - Testet ob eine Tastatur vorhanden ist und ob diese funktioniert. * * Es wird eine Echo Request (0xEE an die Tastatur gesendet. Kommt eine Echo Response (0xEE) * zurück war der Test erfolgreich und die Prozedur liefer 0 zurück, sonst irgend eine Zahl grösser 0 * * @return (unsigned char) 0 wenn der Test erfolgreich war, sonst eine Zahl != 0 */ unsigned char testKB(){ unsigned char ch = 0; write(0xEE); // send request for Echo delay(20); ch = read(); return ch+0x12; //this returns zero for EE (Echo-Reply) other values if Error) } /************************************************************************* * void reset() - setzt die Tastatur zurück * * Diese Funktion setzt die Tastatur mittels Kommando 0xFF zurück * */ void reset(){ unsigned char cha = 0x00; write(0xFF); delay(20); cha = read(); if(cha != 0xFA) {return;} //fehler ? } /************************************************************************* * void init() - initialisiert den Tastatur Treiber * * Diese Funktion setzt den Host auf nicht bereit, so dass die Tastatur * alle Zeichen Buffert. * */ void init(){ Dir.ClockDir = Output; KeyBoard.Clock = 0x00; } /************************************************************************* * unsigned char extendedInit() - initialisiert den Tastatur Treiber mit Funktionstest * * Diese Funktion setzt den Host auf nicht bereit, so dass die Tastatur * alle Zeichen Buffert. Weiter wird ein Reset durchgeführt und mit Echo * die Tastatur getestet. * * @return (unsigned char) fals der Test erfolgreich war 0 sonst Zahl != 0 * */ unsigned char extendedInit(){ unsigned char ch = 0x00; //reset write(0xFF); ch = read(); if(ch != 0xFA) {return ch+0x06;} //fehler so liefere einen wert ungleich null zurück (wär ja nur null wenn ch = FA wird aber da wird das return nicht ausgeführt. delay(200); return testKB(); }