Initial commit

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

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.build/
.clangd
compile_commands.json

39
Makefile Normal file
View File

@ -0,0 +1,39 @@
OBJCOPY = avr-objcopy
CC = avr-gcc
BUILD = .build
TARGET = main
OPT = s
CFLAGS = -Wall -Wextra -std=c18 -O$(OPT) -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects -mmcu=atmega328p -DF_CPU=16000000L -Iinclude
LDFLAGS = -Wall -Wextra -O$(OPT) -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p
SRC = \
src/main.c \
src/keyboard.c \
src/fifo.c \
src/scancode.c
OBJ = $(addprefix $(BUILD)/, $(notdir $(SRC:.c=.o)))
vpath %.c $(sort $(dir $(SRC)))
.PHONY: all clean
all: $(BUILD) $(BUILD)/$(TARGET).bin
%.hex: %.elf | $(BUILD)
$(OBJCOPY) -O ihex -R .eeprom $< $@
%.bin: %.hex | $(BUILD)
$(OBJCOPY) -I ihex -O binary $< $@
$(BUILD)/%.o: %.c Makefile | $(BUILD)
$(CC) -c $(CFLAGS) $< -o $@
$(BUILD)/$(TARGET).elf: $(OBJ) Makefile
$(CC) $(LDFLAGS) $(OBJ) -o $@
$(BUILD):
mkdir $@
clean:
rm -fr $(BUILD)

147
generate_scancode.py Normal file
View File

@ -0,0 +1,147 @@
#!/usr/bin/env python3
scancode = [[0]*128, [0]*128]
scancode[0][0x0D] = '\t'
scancode[0][0x0E] = '`'
scancode[0][0x15] = 'q'
scancode[0][0x16] = '1'
scancode[0][0x1A] = 'z'
scancode[0][0x1B] = 's'
scancode[0][0x1C] = 'a'
scancode[0][0x1D] = 'w'
scancode[0][0x1E] = '2'
scancode[0][0x21] = 'c'
scancode[0][0x22] = 'x'
scancode[0][0x23] = 'd'
scancode[0][0x24] = 'e'
scancode[0][0x25] = '4'
scancode[0][0x26] = '3'
scancode[0][0x29] = ' '
scancode[0][0x2A] = 'v'
scancode[0][0x2B] = 'f'
scancode[0][0x2C] = 't'
scancode[0][0x2D] = 'r'
scancode[0][0x2E] = '5'
scancode[0][0x31] = 'n'
scancode[0][0x32] = 'b'
scancode[0][0x33] = 'h'
scancode[0][0x34] = 'g'
scancode[0][0x35] = 'y'
scancode[0][0x36] = '6'
scancode[0][0x3A] = 'm'
scancode[0][0x3B] = 'j'
scancode[0][0x3C] = 'u'
scancode[0][0x3D] = '7'
scancode[0][0x3E] = '8'
scancode[0][0x41] = ','
scancode[0][0x42] = 'k'
scancode[0][0x43] = 'i'
scancode[0][0x44] = 'o'
scancode[0][0x45] = '0'
scancode[0][0x46] = '9'
scancode[0][0x49] = '.'
scancode[0][0x4A] = '/'
scancode[0][0x4B] = 'l'
scancode[0][0x4C] = ';'
scancode[0][0x4D] = 'p'
scancode[0][0x4E] = '-'
scancode[0][0x52] = '\''
scancode[0][0x54] = '['
scancode[0][0x55] = '='
scancode[0][0x5A] = '\r'
scancode[0][0x5B] = ']'
scancode[0][0x5D] = '\\'
scancode[0][0x66] = 0x08
scancode[0][0x69] = '1'
scancode[0][0x6B] = '2'
scancode[0][0x6C] = '7'
scancode[0][0x70] = '0'
scancode[0][0x71] = '.'
scancode[0][0x72] = '2'
scancode[0][0x73] = '5'
scancode[0][0x74] = '6'
scancode[0][0x75] = '8'
scancode[0][0x76] = 0x1B
scancode[0][0x79] = '+'
scancode[0][0x7A] = '3'
scancode[0][0x7B] = '-'
scancode[0][0x7C] = '*'
scancode[0][0x7D] = '9'
scancode[1][0x0D] = '\t'
scancode[1][0x0E] = '~'
scancode[1][0x15] = 'Q'
scancode[1][0x16] = '!'
scancode[1][0x1A] = 'Z'
scancode[1][0x1B] = 'S'
scancode[1][0x1C] = 'A'
scancode[1][0x1D] = 'W'
scancode[1][0x1E] = '@'
scancode[1][0x21] = 'C'
scancode[1][0x22] = 'X'
scancode[1][0x23] = 'D'
scancode[1][0x24] = 'E'
scancode[1][0x25] = '$'
scancode[1][0x26] = '#'
scancode[1][0x29] = ' '
scancode[1][0x2A] = 'V'
scancode[1][0x2B] = 'F'
scancode[1][0x2C] = 'T'
scancode[1][0x2D] = 'R'
scancode[1][0x2E] = '%'
scancode[1][0x31] = 'N'
scancode[1][0x32] = 'B'
scancode[1][0x33] = 'H'
scancode[1][0x34] = 'G'
scancode[1][0x35] = 'Y'
scancode[1][0x36] = '^'
scancode[1][0x3A] = 'M'
scancode[1][0x3B] = 'J'
scancode[1][0x3C] = 'U'
scancode[1][0x3D] = '&'
scancode[1][0x3E] = '*'
scancode[1][0x41] = '<'
scancode[1][0x42] = 'K'
scancode[1][0x43] = 'I'
scancode[1][0x44] = 'O'
scancode[1][0x45] = ')'
scancode[1][0x46] = '('
scancode[1][0x49] = '>'
scancode[1][0x4A] = '?'
scancode[1][0x4B] = 'L'
scancode[1][0x4C] = ':'
scancode[1][0x4D] = 'P'
scancode[1][0x4E] = '_'
scancode[1][0x52] = '"'
scancode[1][0x54] = '{'
scancode[1][0x55] = '+'
scancode[1][0x5A] = '\r'
scancode[1][0x5B] = '}'
scancode[1][0x5D] = '|'
scancode[1][0x66] = 0X08
scancode[1][0x69] = '1'
scancode[1][0x6B] = '2'
scancode[1][0x6C] = '7'
scancode[1][0x70] = '0'
scancode[1][0x71] = '.'
scancode[1][0x72] = '2'
scancode[1][0x73] = '5'
scancode[1][0x74] = '6'
scancode[1][0x75] = '8'
scancode[1][0x76] = 0X1B
scancode[1][0x79] = '+'
scancode[1][0x7A] = '3'
scancode[1][0x7B] = '-'
scancode[1][0x7C] = '*'
scancode[1][0x7D] = '9'
print("char scancode[2][128] = {")
for i in scancode:
print("\t{", end="")
for j in i:
if (type(j) == str):
j = ord(j)
print(f"0x{j:02x},", end="")
print("},")
print("};")

19
include/fifo.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef FIFO_h
#define FIFO_h
#include <stdint.h>
#define FIFO_SIZE 64
struct FIFO {
int head;
int tail;
int size;
uint8_t buffer[FIFO_SIZE];
};
void FIFO_push(volatile struct FIFO* fifo, uint8_t value);
uint8_t FIFO_pop(volatile struct FIFO* fifo);
int FIFO_size(volatile struct FIFO* fifo);
#endif

15
include/keyboard.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef KEYBOARD_h
#define KEYBOARD_h
#include <stdint.h>
#define KEYBOARD_CLK 2
#define KEYBOARD_DATA 7
void send_keyboard_cmd(uint8_t value);
void queue_keyboard_cmd(uint8_t value);
void send_keyboard_cmd_queue();
void keyboard_interrupt(void (*callback)(uint8_t));
#endif

9
include/scancode.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef SCANCODE_H
#define SCANCODE_H
#include <stdint.h>
void setup_scancode();
// uint8_t convert_scancode(uint8_t shift, uint8_t code);
#endif

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];
}