Initial commit

This commit is contained in:
2020-12-30 03:22:45 +01:00
commit bec3721e46
10 changed files with 563 additions and 0 deletions

37
src/fifo.c Normal file
View File

@@ -0,0 +1,37 @@
#include "fifo.h"
void FIFO_push(volatile struct FIFO* fifo, uint8_t value) {
if (fifo->size == FIFO_SIZE) {
return;
}
fifo->size++;
if (fifo->size > 1) {
fifo->tail++;
fifo->tail %= FIFO_SIZE;
}
fifo->buffer[fifo->tail] = value;
}
uint8_t FIFO_pop(volatile struct FIFO* fifo) {
if (fifo->size == 0) {
return 0;
}
fifo->size--;
uint8_t data = fifo->buffer[fifo->head];
if (fifo->size >= 1) {
fifo->head++;
fifo->head %= FIFO_SIZE;
}
return data;
}
int FIFO_size(volatile struct FIFO* fifo) {
return fifo->size;
}

231
src/keyboard.c Normal file
View File

@@ -0,0 +1,231 @@
#include <avr/io.h>
#include <util/delay.h>
#include "keyboard.h"
#include "scancode.h"
#include "fifo.h"
volatile struct {
struct FIFO buffer;
uint8_t sending : 1;
uint16_t value;
uint8_t counter;
struct {
uint8_t shift : 1;
uint8_t caps_lock : 1;
uint8_t ctrl : 1;
} modifier;
uint8_t released : 1;
} keyboard = {0};
// Send a command to the keyboard (BLOCKS)
void send_keyboard_cmd(uint8_t value) {
// Pull clock low
DDRD |= (1<<KEYBOARD_CLK);
PORTD &= ~(1<<KEYBOARD_CLK);
_delay_ms(1);
// Pull data low
DDRD |= (1<<KEYBOARD_DATA);
PORTD &= ~(1<<KEYBOARD_DATA);
// Release clock
DDRD &= ~(1<<KEYBOARD_CLK);
keyboard.sending = 1;
keyboard.value = value;
while (keyboard.sending) {};
}
// Add keyboard command to the queue
void queue_keyboard_cmd(uint8_t value) {
FIFO_push(&keyboard.buffer, value);
}
// Send queued command
void send_keyboard_cmd_queue() {
while (FIFO_size(&keyboard.buffer)) {
send_keyboard_cmd(FIFO_pop(&keyboard.buffer));
}
}
// Calculate parity
uint8_t parity(uint8_t value) {
value ^= value >> 4;
value ^= value >> 2;
value ^= value >> 1;
return (~value) & 1;
}
void receive_scancode_bit(void (*callback)(uint8_t)) {
keyboard.value |= ((PIND >> KEYBOARD_DATA) & 1) << keyboard.counter;
keyboard.counter++;
// Check that the first bit is 0
if (keyboard.counter == 1 && keyboard.value & 1) {
keyboard.counter = 0;
keyboard.value = 0;
return;
}
// Check the parity
if (keyboard.counter == 10 && parity(keyboard.value >> 1) != ((keyboard.value >> 9) & 1)) {
keyboard.counter = 0;
keyboard.value = 0;
return;
}
// Check that the last bit is 1
if (keyboard.counter == 11 && !((keyboard.value >> 10) & 1)) {
keyboard.counter = 0;
keyboard.value = 0;
return;
}
// Process the scancode
if (keyboard.counter == 11) {
uint8_t value = keyboard.value >> 1;
keyboard.counter = 0;
keyboard.value = 0;
switch (value) {
// Left and right shift
case 18:
case 89:
keyboard.modifier.shift = !keyboard.released;
keyboard.released = 0;
break;
// Caps lock
case 0x58:
if (!keyboard.released) {
keyboard.modifier.caps_lock = !keyboard.modifier.caps_lock;
queue_keyboard_cmd(0xED);
queue_keyboard_cmd(keyboard.modifier.caps_lock << 2);
}
keyboard.released = 0;
break;
// Left ctrl
case 0x14:
keyboard.modifier.ctrl = !keyboard.released;
keyboard.released = 0;
break;
case 240:
keyboard.released = 1;
break;
default:
if (!keyboard.released) {
char c = convert_scancode(keyboard.modifier.shift, value & 127);
if (keyboard.modifier.caps_lock && !keyboard.modifier.shift && c >= 'a' && c <= 'z') {
c -= 0x20;
}
if (keyboard.modifier.ctrl) {
switch (c) {
case 'c':
c = 0x03;
break;
case 'e':
c = 0x05;
break;
case 'p':
c = 0x10;
break;
case 'r':
c = 0x12;
break;
case 's':
c = 0x13;
break;
case 'u':
c = 0x15;
break;
case 'x':
c = 0x18;
break;
case 'z':
c = 0x1A;
break;
default:
c = 0x00;
break;
}
}
if (c) {
callback(c);
}
}
keyboard.released = 0;
break;
}
}
}
void send_cmd_bit() {
if (keyboard.counter == 8) {
// Send parity
if (parity(keyboard.value)) {
PORTD |= (1<<KEYBOARD_DATA);
} else {
PORTD &= ~(1<<KEYBOARD_DATA);
}
++keyboard.counter;
} else if (keyboard.counter == 9) {
// Release data line
PORTD &= ~(1<<KEYBOARD_DATA);
DDRD &= ~(1<<KEYBOARD_DATA);
++keyboard.counter;
} else if (keyboard.counter == 10) {
// Wait for data to go low as ack
if (!((PIND >> KEYBOARD_DATA) & 1)) {
keyboard.counter = 0;
keyboard.value = 0;
keyboard.sending = 0;
}
} else {
// Send bit
if ((keyboard.value >> keyboard.counter) & 1) {
PORTD |= (1<<KEYBOARD_DATA);
} else {
PORTD &= ~(1<<KEYBOARD_DATA);
}
++keyboard.counter;
}
}
void keyboard_interrupt(void (*callback)(uint8_t)) {
if (!keyboard.sending && PIND & (1<<KEYBOARD_CLK)) {
receive_scancode_bit(callback);
}
if (keyboard.sending && !(PIND>>KEYBOARD_CLK & 1)) {
send_cmd_bit();
}
}

53
src/main.c Normal file
View File

@@ -0,0 +1,53 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stddef.h>
#include "scancode.h"
#include "keyboard.h"
#define CLK 4
#define DATA 5
// Clock the value to 74164
void write_value(uint8_t value) {
for (uint8_t i = 0; i < 8; ++i) {
uint8_t bit = (value >> i) & 1;
PORTD |= (1<<CLK) | (bit<<DATA);
PORTD &= ~((1<<CLK) | (bit<<DATA));
}
}
ISR(PCINT2_vect) {
keyboard_interrupt(write_value);
}
int main() {
// Configure pins as output
DDRD |= (1<<CLK) | (1<<DATA);
DDRD &= ~((1<<KEYBOARD_CLK) | (1<<KEYBOARD_DATA));
// interrupt
PCMSK2 |= (1<<PCINT18);
PCICR |= (1<<PCIE2);
write_value(0);
sei();
// Wait for the keyboard to be ready
_delay_ms(1000);
// Reset the keyboard
send_keyboard_cmd(0xFF);
_delay_ms(1000);
// Set the keyboard repeat rate (and delay)
send_keyboard_cmd(0xF3);
send_keyboard_cmd(0x00 | (1<<5) | (1<<4));
for (;;) {
send_keyboard_cmd_queue();
}
}

10
src/scancode.c Normal file
View File

@@ -0,0 +1,10 @@
#include "scancode.h"
char scancode[2][128] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x71,0x31,0x00,0x00,0x00,0x7a,0x73,0x61,0x77,0x32,0x00,0x00,0x63,0x78,0x64,0x65,0x34,0x33,0x00,0x00,0x20,0x76,0x66,0x74,0x72,0x35,0x00,0x00,0x6e,0x62,0x68,0x67,0x79,0x36,0x00,0x00,0x00,0x6d,0x6a,0x75,0x37,0x38,0x00,0x00,0x2c,0x6b,0x69,0x6f,0x30,0x39,0x00,0x00,0x2e,0x2f,0x6c,0x3b,0x70,0x2d,0x00,0x00,0x00,0x27,0x00,0x5b,0x3d,0x00,0x00,0x00,0x00,0x0d,0x5d,0x00,0x5c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x31,0x00,0x32,0x37,0x00,0x00,0x00,0x30,0x2e,0x32,0x35,0x36,0x38,0x1b,0x00,0x00,0x2b,0x33,0x2d,0x2a,0x39,0x00,0x00,},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x21,0x00,0x00,0x00,0x5a,0x53,0x41,0x57,0x40,0x00,0x00,0x43,0x58,0x44,0x45,0x24,0x23,0x00,0x00,0x20,0x56,0x46,0x54,0x52,0x25,0x00,0x00,0x4e,0x42,0x48,0x47,0x59,0x5e,0x00,0x00,0x00,0x4d,0x4a,0x55,0x26,0x2a,0x00,0x00,0x3c,0x4b,0x49,0x4f,0x29,0x28,0x00,0x00,0x3e,0x3f,0x4c,0x3a,0x50,0x5f,0x00,0x00,0x00,0x22,0x00,0x7b,0x2b,0x00,0x00,0x00,0x00,0x0d,0x7d,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x31,0x00,0x32,0x37,0x00,0x00,0x00,0x30,0x2e,0x32,0x35,0x36,0x38,0x1b,0x00,0x00,0x2b,0x33,0x2d,0x2a,0x39,0x00,0x00,},
};
uint8_t convert_scancode(uint8_t shift, uint8_t code) {
return scancode[shift][code];
}