Close

AnyHardKeyboard

A project log for Scraptop

Laptop made out of scrap - Combined with a FairPhone2 a possible step in the journey toward a fair laptop.

ronaldRonald 10/19/2017 at 17:510 Comments

The guy from Tynemouth software created a lot of USB keyboards. He using Arduino however, and I like plain C better. Also, I cannot find his code right now. Because I don't think scanning & debouncing could be that hard, I made a start. This guy did however inspire me by showing that an ATmega microcontroller with V-USB is capable of being used as a keyboard.

My plan is to write a code generation tool, and today I started. It's only the init routine for now, but it's a start. :-) The code generation tool will justify the name AnyHardKeyboard; the plan is to be able to give a CSV of the keyboard layout to this little program, and have it generate the keyboard routines from it.

A big thanks to the guys of FreeBSD who put a text format  key table online (everyone else points to the PDF). I'll use a modified version of that one for the key mapping.

What I have now is the following:

,"B5","B6","C0","C1","C2","C3","C4","C5"
"D0","ESCAPE","F12","`","Tab","Caps Lock","A",,1
"D1","F3","F2",2,"W","S","X","Z","Q"
"D3","Fn","LeftShift","LeftControl","Left GUI","RightShift","LeftAlt","RightAlt","RightControl"
"D4","F6",6,5,"R","G","F","V","T"
"D5","F5","F4",4,"ENTER","D","C3",,3
"D6","F7",8,7,"Y","H","N","B","U"
"B0","F9","F8","I","K","M",",","Spacebar","J"
"B1","F10",9,"O","L",";",".",,"P"
"B2","F11","F12",0,"[","'","/",,"-"
"C6","Scroll Lock","Pause","=",,,,,"]"
"B3","Delete","Insert","Backspace","ENTER","\","PageDown","DownArrow","RightArrow"

The topmost row and the leftmost column designate the ATmega8's pins used.

The proof-of-concept Python code:

import csv
with open('esprimo.csv', 'rb') as csvfile:
    csvreader = csv.reader(csvfile, delimiter=',', quotechar='"')
    i = 0
    inputmatrix = []
    writepins = []
    for row in csvreader:
        inputmatrix.append(row)
        if i > 0:
            writepins.append(row[0])
            #writepins[i] = row[1]
        i = i + 1
    readpins = inputmatrix[0][1:]
    writepins.sort()
    readpins.sort()
    outfile = "init_kb_pins() {\r\n"
    outfile = outfile + "\t" + '// write pins\r\n'
    buf = ''
    lastp = ''
    for p in writepins:
        if lastp != p[0] and lastp != '':
            outfile = outfile + "\t" + 'DDR' + lastp + ' |= ' + buf + "; // set the bits as input\r\n"
            outfile = outfile + "\t" + 'PORT' + lastp + ' &= ~('+ buf + "); // set voltage low in case bits are set as output while scanning\r\n";
            buf = ''
        if buf != '':
            buf = buf + ' |'
        buf = buf + ' (1 << '+p[1]+')'
        lastp = p[0]
    outfile = outfile + "\t" + 'DDR' + lastp + ' |= ' + buf + "; // set the bits as input\r\n"
    outfile = outfile + "\t" + 'PORT' + lastp + ' &= ~('+ buf + "); // set voltage low in case bits are set as output while scanning\r\n";
    buf = ''
    lastp = ''
    outfile = outfile + "\r\n\t// read pins\r\n"
    for p in readpins:
        if lastp != p[0] and lastp != '':
            outfile = outfile + "\t" + 'DDR' + lastp + ' |= ' + buf + "; // set the bits as input\r\n"
            outfile = outfile + "\t" + 'PORT' + lastp + ' |= '+ buf + "; // activate pull-ups\r\n";
            buf = ''
        lastp = p[0]
        if buf != '':
            buf = buf + ' |'
        buf = buf + ' (1 << '+p[1]+')'
    outfile = outfile + "\t" + 'DDR' + lastp + ' |= ' + buf + "; // set the bits as input\r\n"
    outfile = outfile + "\t" + 'PORT' + lastp + ' |= '+ buf + "; // activate pull-ups\r\n";
    outfile = outfile + "}\r\n\r\n"
    
    print outfile
    
    print writepins
    print readpins
    
    

 which nicely generates:

init_kb_pins() {
        // write pins
        DDRB |=  (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3); // set the bits as input
        PORTB &= ~( (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)); // set voltage low in case bits are set as output while scanning
        DDRC |=  (1 << 6); // set the bits as input
        PORTC &= ~( (1 << 6)); // set voltage low in case bits are set as output while scanning
        DDRD |=  (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); // set the bits as input
        PORTD &= ~( (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)); // set voltage low in case bits are set as output while scanning
        // read pins
        DDRB |=  (1 << 5) | (1 << 6); // set the bits as input
        PORTB |=  (1 << 5) | (1 << 6); // activate pull-ups
        DDRC |=  (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5); // set the bits as input
        PORTC |=  (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5); // activate pull-ups
} 

Please don't punish me for all the code duplication... I really miss IntelliJ's "extract method" and other refactoring functionality. Perhaps I should rewrite it in Java, or try IDLE...

I also still have to find out if I used the correct bit fiddling operators, but I think I have it right.

Discussions