Using the Arduino library wrappers for the TMK firmware, its pretty simple to integrate hte keyboard's functionality into our sketch.
First, let's take a look at the setup() function for our sketch:
BluefruitHost host;
PS2MatrixCodeset3 matrix;
static uint16_t reset_press_time = 0;

void setup() {

    pinMode(KEY_LED_PIN, INPUT);
    pinMode(PAIR_LED_PIN, INPUT);

    digitalWrite(PAIR_BUTTON_PIN, LOW);            // write high for 5 seconds to reset pairing
    digitalWrite(RESET_BUTTON_PIN, LOW);           // pull low to reset the bluefruit module

    debug_enable = true;
    while (!Serial) ;

    dprint("started logging\n");    
    KeyboardFirmware.begin(host, matrix);
    digitalWrite(RESET_BUTTON_PIN, HIGH);  // turn on bluefruit
We have some straightforward code configuring the pins to interact with the Bluefruit module; we're connecting the pair and reset buttons to the Arduino because we'll map those to keys on the keyboard later. After that comes some setup for the debugging features of the TMK framework, and finally the call that makes the magic happen:

KeyboardFirmware.begin(host, matrix);

This function call will send the PS2 commands to handshake with the keyboard and it will initialize the firmware. The "host" and "matrix" were defined at the top of the above snippet; in this case the "host" is the Bluefruit module, so we're using a BluefruitHost object. On a different keyboard this might be called USBHost or PS2Host (although I don't have wrappers written for those yet). Back on the Research page I discussed the PS2 protocol and how it has different codesets; we put that to use here, as we determined that if we can properly implement a PS2 host for a codeset 3 device, we can support all of the Model M keyboards that were produced by IBM.

Next lets take a look at our loop():
void loop() {

    // this the main hook into the tmk firmware that handles all the heavy lifting
    // Now sync the pair button light with the output pin
    if (digitalRead(PAIR_LED_PIN) == HIGH) {
        digitalWrite(OUTPUT_LED_PIN, OUTPUT_LED_ON);
    } else {
        digitalWrite(OUTPUT_LED_PIN, OUTPUT_LED_OFF);
    // receive any messages from Bluefruit and output them if necessary
    unsigned char c;
    while (Serial1.available()) {
        c = (unsigned char);
        if (debug_enable) Serial.write(c);
    // next we'll check if the reset key was held down for 5 seconds
    if (reset_press_time && timer_elapsed(reset_press_time) > 5000) {
        dprintf("= setting reset low\n");
        digitalWrite(RESET_BUTTON_PIN, LOW);
        digitalWrite(RESET_BUTTON_PIN, HIGH);
        dprintf("= restored reset high\n");
        reset_press_time = 0;
This is very simple; the runTask() call is perhaps the most important call in the whole program, as that is the function that reads the state of the matrix, maps the matrix state to keycodes and/or macros, and then sends the state to the host.

The rest of the code in that block makes sure that the LED button on the keyboard stays in sync with the Pair LED of the Bluefruit, and also we are forwarding any output from Bluefruit's serial connection to the Arduino serial monitor for debugging purposes. Finally, we check the state of the "reset key" that we'll define on the keyboard, and if it has been held for 5 seconds we pull the reset pin on Bluefruit low for 10ms, which effectively reboots the module (without affecting the pairing).
Most of this code is pretty boilerplate, and relatively boring. In the next section you can be a bit more creative though...

This guide was first published on May 06, 2014. It was last updated on May 06, 2014.

This page (Integrating the Firmware) was last updated on Feb 28, 2014.

Text editor powered by tinymce.