Saturday, March 18, 2017

Terminal J - IBM Model M USB Keyboard Adapter with Arduino Source

Terminal J - An IBM Model M USB Teensy-based Codable Keyboard Adapter with Arduino Source Code

The goal of this project was to have a USB hardware converter for our IBM Model M and have our own source code. We wanted to have the code base to build upon (rather than use the Soarer's keyboard converter). The code below will compile and run on a Teensy 3.2.

The Teensy and the adapter is in the Ethernet jack below.



Image By Raymangold22 - Own work, CC0, https://commons.wikimedia.org/w/index.php?curid=37410391


Our hardware:

We used an Ethernet RJ45 Keystone jack because we didn't want to cut the plug off of the Model M.


Wiring:
  • Teensy to Ethernet Adapter
  • GND – (Ethernet 6) GND
  • Pin 2 – (Ethernet 5) CLK
  • Pin 3 – (Ethernet 4) Data
  • VIN – (Ethernet  3) 5V

Notes:
  • When you setup your Teensy, be sure to select USB Type: "Keyboard".
  • On the Ethernet jack, 1, 2, 7, and 8 are not used.   
  • Also Pin 2 and 3 may be reversed in the RJ45 in case yours is different. 

Many thanks to the Arduino and Teensy folks, and the authors of the PS2 library. We love the Teensy and look forward to doing more projects with it.

This post is also at: Wordpress, Google, GitHub.

The code:

/*

  IBM Model M Keyboard Scancode Converter

  By J Pagliaccio

  Parts of this code came from the PS2Keyboard library.

  PS2Keyboard.h - PS2Keyboard library
  Copyright (c) 2007 Free Software Foundation.  All right reserved.
  Written by Christian Weichel 

  ** Mostly rewritten Paul Stoffregen , June 2010
  ** Modified for use with Arduino 13 by L. Abraham Smith,  *
  ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan  **

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  For Jules.

  Notes
  --------------------------------------------------------

  This was written for the IBM Model M Keyboard - early version without the LEDs
  and the RJ-45 plug.

  This was written and tested using the Teensey 3.2.

  Use F1 to set debug mode and pressing escape unsets it.
  Its off by default staring in beta 00.00.01

  ESC - to escape from special keys mode

  Shift Hold is reboot
  ESC is debug off
  F1 is debug on
  Left Reset = ALT
  Right Reset is CTRL
  BLANK 1 is dump
  Blank 2 is clear
  ATTEN is Alex


  If you want no modifier keys pressed, use a zero.

  Keyboard.set_modifier(0);

  To press just one modifier is simple.

  Keyboard.set_modifier(MODIFIERKEY_SHIFT);

  To press more than one modifier, use the logic OR operator. For example:

  Keyboard.set_modifier(MODIFIERKEY_CTRL | MODIFIERKEY_ALT);


  Key send code
  57985 hibernate and shut down
  57986 sleep (quick)
  58509 win media center
  58592 Vol Up
  58594 Vol ???
  58601 vol up
  58602 vol down
  58755 media player
  58762 outlook email
  58770 calculator
  58772 open windows explorer - my computer
  58913 search
  58914 google search
*/

#define KEY_INTERNET_SEARCH 58915
#define KEY_CALCULATOR 58770
#define KEY_SLEEP 57986
#define KEY_SHUTDOWN 58000
#define KEY_VOL_UP 58592
#define KEY_VOL_DOWN 58602

//#include "PS2Keyboard.h"

#define PROGNAME "IBM Model M Keyboard Scancode Converter v00.00.01"

// Map the key to the decimal scan code and it works
// eg: #define KEY_VOL_UP 61447 is a lower case d,  Hex: F007

// 59600

// F9 Dec: 71,  E0 7A 57466
//#define KEY_VOL_UP 58000

// F10 Decimal in is 79,
//#define KEY_VOL_DN 57505
// 57394

const int ledPin = 13;
int clockPin = 2;
int dataPin = 3;
int first_bit_test = 0;
int counter = 0;
int numbits = 11;

bool debug = false;
static uint8_t incoming = 0;

//#define BUFFER_SIZE 45
//static volatile uint8_t buffer[BUFFER_SIZE];
//static volatile uint8_t head, tail;

bool shift = false;
bool ctrl = false;
bool alt = false;
bool caps = false;
bool ledState = false;

#define BUFMAX 9999

char keyBuffer[BUFMAX];
int keyBufferPos = 0;

unsigned long previousMillis = 0L;
unsigned long interval = 1000L;


// 58000
unsigned long b = 0;


//
// Setup
//----------------------------------------------------------
//
void setup() {
  pinMode(dataPin, INPUT);
  pinMode(clockPin, INPUT);
  pinMode(ledPin, OUTPUT);

  Serial.begin(115200);
  delay(10);

  Serial.println(PROGNAME);
  digitalWrite(ledPin, HIGH);
  delay(99);
  digitalWrite(ledPin, LOW);
  delay(99);
  digitalWrite(ledPin, HIGH);
  delay(99);
  digitalWrite(ledPin, LOW);

  Serial.print("KEY_PRINTSCREEN = ");
  Serial.println(KEY_PRINTSCREEN);

  attachInterrupt(clockPin, ps2interrupt, FALLING);
}

//
// The main loop
//----------------------------------------------------------
//
void loop() {

  if (digitalRead(clockPin) == LOW && first_bit_test == 0 && counter < numbits) {

    first_bit_test = 1;
    digitalWrite(ledPin, HIGH);
    //  data = data >> 1;
    //if (digitalRead(dataPin) == HIGH) {
    //  bitSet(data, 7);
    // }
    counter++;
  }

  if (digitalRead(clockPin) == HIGH && first_bit_test == 1) {
    first_bit_test = 0;
  }

  if (counter >= numbits) {

    if (debug) {
      Serial.print("Incoming decimal = ");
      Serial.println(incoming);
    }

    process_key(int(incoming));
    digitalWrite(ledPin, LOW);

    incoming = 0;
    counter = 0;
  }


  if (millis() - previousMillis > interval) {
    previousMillis = millis();

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}


//
// The interrupt service routine from the clock pin
//----------------------------------------------------------
//
void ps2interrupt(void)
{
  static uint8_t bitcount = 0;
  static uint32_t prev_millis = 0;
  uint32_t now_millis;
  uint8_t n, val;

  val = digitalRead(dataPin);

  // get the milliseconds since boot
  now_millis = millis();

  // See if its been more than one millisecond since we had an inturrupt
  if (now_millis - prev_millis > 1) {
    bitcount = 0;
    incoming = 0;
  }

  prev_millis = now_millis;
  n = bitcount - 1;

  if (n <= 7) {
    incoming |= (val << n);
  }

  bitcount++;

  // The scan code size
  if (bitcount == 11) {
    bitcount = 0;
  }
}

//
// Process - eg: remap the key inputs
//----------------------------------------------------------
//
void process_key(int r)
{
  long s = 0L;
  char c = 0;

  switch (r) {
    case 7: s = KEY_F1;
      debug = true;
      break;
    case 8: s = KEY_ESC; // escape
      debug = false;
      Keyboard.releaseAll();
      Keyboard.set_modifier(0);
      keyBufferPos = 0;
      c = 0;
      break;
    case 13: s = KEY_TAB; break;
    case 14: s = KEY_TILDE; break;
    case 17: // Left Enter is now LEFT_CTRL
      if (ctrl == false) {
        ctrl = true;
        //Keyboard.press(KEY_LEFT_CTRL);
        Keyboard.set_modifier(MODIFIERKEY_CTRL);
      } else {
        ctrl = false;
        //Keyboard.release(KEY_LEFT_CTRL);
        Keyboard.set_modifier(0);
        Keyboard.set_key1(0);
        Keyboard.send_now();
      }
      // see 240 for release all
      break;
    case 18: // Left Shift
      if (shift == false) {
        //Keyboard.press(KEY_LEFT_SHIFT);
        Keyboard.set_modifier(MODIFIERKEY_SHIFT);
        shift = true;
      } else {
        Keyboard.releaseAll();
        Keyboard.set_modifier(0);
        Keyboard.set_key1(0);
        Keyboard.send_now();
        shift = false;
      }
      break;
    case 20:
      s = KEY_CAPS_LOCK;
      break;
    case 21: s = KEY_Q; c = 'q'; break;
    case 22: s = KEY_1; c = '1'; break;
    case 25: // Left Alt
      if (alt == false) {
        Keyboard.set_modifier(MODIFIERKEY_ALT);
        alt = true;
      } else {
        Keyboard.set_modifier(0);
        Keyboard.set_key1(0);
        Keyboard.send_now();
        alt = false;
      }
      break; // ALT
    case 26: s = KEY_Z; c = 'z'; break;
    case 27: s = KEY_S; c = 's'; break;
    case 28: s = KEY_A; c = 'a'; break;
    case 29: s = KEY_W; c = 'w'; break;
    case 30: s = KEY_2; c = '2'; break;
    case 33: s = KEY_C; c = 'c'; break;
    case 34: s = KEY_X; c = 'x'; break;
    case 35: s = KEY_D; c = 'd'; break;
    case 36: s = KEY_E; c = 'e'; break;
    case 37: s = KEY_4; c = '4'; break;
    case 38: s = KEY_3; c = '3'; break;
    case 41: s = KEY_SPACE; c = ' '; break;
    case 42: s = KEY_V; c = 'v'; break;
    case 43: s = KEY_F; c = 'f'; break;
    case 44: s = KEY_T; c = 't'; break;
    case 45: s = KEY_R; c = 'r'; break;
    case 46: s = KEY_5; c = '5'; break;
    case 49: s = KEY_N; c = 'n'; break;
    case 50: s = KEY_B; c = 'b'; break;
    case 51: s = KEY_H; c = 'h'; break;
    case 52: s = KEY_G; c = 'g'; break;
    case 53: s = KEY_Y; c = 'y'; break;
    case 54: s = KEY_6; c = '6'; break;
    case 57: // Right ALT
      if (alt == false) {
        Keyboard.set_modifier(MODIFIERKEY_ALT);
        alt = true;
      } else {
        Keyboard.set_modifier(0);
        Keyboard.set_key1(0);
        Keyboard.send_now();
        alt = false;
      }
      break;
    case 58: s = KEY_M; c = 'm'; break;
    case 59: s = KEY_J; c = 'j'; break;
    case 60: s = KEY_U; c = 'u'; break;
    case 61: s = KEY_7; c = '7'; break;
    case 62: s = KEY_8; c = '8'; break;
    case 65: s = KEY_COMMA; c = ','; break;
    case 66: s = KEY_K; c = 'k'; break;
    case 67: s = KEY_I; c = 'i'; break;
    case 68: s = KEY_O; c = 'o'; break;
    case 69: s = KEY_0; c = '0'; break;
    case 70: s = KEY_9; c = '9'; break;
    case 71: // F9
      s = KEY_VOL_DOWN;
      c = '?';
      break;
    case 73: s = KEY_PERIOD; c = '.'; break;
    case 74: s = KEY_SLASH; c = '/'; break;
    case 75: s = KEY_L; c = 'l'; break;
    case 76: s = KEY_SEMICOLON; c = ';'; break;
    case 77: s = KEY_P; c = 'p'; break;
    case 78: s = KEY_MINUS; c = '-'; break;
    case 79: // F10
      s = KEY_VOL_UP;
      break;
    case 82: s = KEY_QUOTE; c = '"'; break;
    case 84: s = KEY_LEFT_BRACE; c = '['; break;
    case 85: s = KEY_EQUAL; c = '='; break;
    case 86: // F11
      s = KEY_INTERNET_SEARCH;
      break;
    case 87: s = KEY_PRINTSCREEN; break;
    case 88: // Right Reset is CTRL
      if (ctrl == false) {
        ctrl = true;
        Keyboard.set_modifier(MODIFIERKEY_CTRL);
      } else {
        ctrl = false;
        Keyboard.set_modifier(0);
        Keyboard.set_key1(0);
        Keyboard.send_now();
      }

      break;
    case 89: //Keyboard.press(KEY_RIGHT_SHIFT);
      if (shift == false) {
        Keyboard.set_modifier(MODIFIERKEY_SHIFT);
        shift = true;
      } else {
        Keyboard.set_modifier(0);
        Keyboard.set_key1(0);
        Keyboard.send_now();
        shift = false;
      }
      break;
    case 90: s = KEY_ENTER; c = '\n'; break;
    case 91: s = KEY_RIGHT_BRACE; c = ']'; break;
    case 92: s = KEY_BACKSLASH; c = '\\'; break;
    case 93: s = KEY_QUOTE; c = '"'; break;
    case 94: // F12
      s = KEY_CALCULATOR;
      break;
    case 95: s = KEY_PRINTSCREEN; break;
    case 96: s = KEY_DOWN_ARROW; break;
    case 97: s = KEY_LEFT_ARROW; break;
    case 98: // HOLD and Shift Hold Key
      if (shift) {
        SCB_AIRCR = 0x05FA0004; // software reset
      }
      break;
    case 99: s = KEY_UP_ARROW; break;
    case 100: s = KEY_DELETE; break;
    case 101: s = KEY_END; break;
    case 102: s = KEY_BACKSPACE; break;
    case 103: s = KEY_INSERT; break;
    case 105: s = KEY_1; c = '1'; break;
    case 106: s = KEY_RIGHT_ARROW; break;
    case 107: s = KEY_4; c = '4'; break;
    case 108: s = KEY_7; c = '7'; break;
    case 109: s = KEY_PAGE_DOWN; break;
    case 110: s = KEY_HOME; break;
    case 111: s = KEY_PAGE_UP; break;
    case 112: s = KEY_0; c = '0'; break;
    case 113: s = KEY_PERIOD; c = '.'; break;
    case 114: s = KEY_2; c = '2'; break;
    case 115: s = KEY_5; c = '5'; break;
    case 116: s = KEY_6; c = '6'; break;
    case 117: s = KEY_8; c = '8'; break;
    case 118:
      // Display the keystroke buffer to the output
      Keyboard.print(keyBuffer);
      break;
    case 119:
      // Empty the keystroke buffer
      keyBufferPos = 0;
      break;
    case 120: // F11
      s = KEY_INTERNET_SEARCH;
      break;
    //  case 121: s = KEY_PLUS; break;
    case 122: s = KEY_3; c = '3'; break;
    case 123: s = KEY_MINUS; c = '-'; break;
    case 125: s = KEY_9; c = '9'; break;
    case 126: s = KEY_SCROLL_LOCK; break;
    case 131: s = KEY_F7; break;
    case 132:

      Keyboard.print("Alex19 isn't so great? Are you kidding me? ");
      Keyboard.print("When was the last time you saw a player with such an ability and movement with fox? ");
      Keyboard.print("Alex puts the game in another level, and we will be blessed if we ever see a player with his skill ");
      Keyboard.print("and passion for the game again. mang0 breaks records. Armada breaks records. ");
      Keyboard.println("Alex19 breaks the rules. You can keep your statistics. I prefer the magic.");

      break;
    case 240: // the release of a modal key
      Keyboard.set_modifier(0);
      Keyboard.set_key1(0);
      Keyboard.send_now();
      Keyboard.releaseAll();
      break;
    default: break;
  }

  // save these keystrokes
  if (keyBufferPos < BUFMAX && c) {
    keyBuffer[keyBufferPos++] = c;
    keyBuffer[keyBufferPos + 1] = 0;
  }

  // If the scan code is not zero
  // It will be zero/null for the special keys and skip this
  if (s) {
    if (debug) {
      Serial.print(" Scan code = ");
      Serial.println(s);
    }

    // otherwise - for all normal keys we do this
    Keyboard.press(s);
    Keyboard.release(s);
  }
}
This is end of the main code.

Here is the "Full" include file. A lot of it is commented out or not used but it's good for reference.

This is the start of the header include file.

/*

  IBM Model M Keyboard scan code converter 

  Parts of this code came from the PS2Keyboard library    
  
  PS2Keyboard.h - PS2Keyboard library
  Copyright (c) 2007 Free Software Foundation.  All right reserved.
  Written by Christian Weichel 

  ** Mostly rewritten Paul Stoffregen , June 2010
  ** Modified for use with Arduino 13 by L. Abraham Smith,  * 
  ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan  **

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

Key  Hexadecimal value Decimal value
KEY_LEFT_CTRL 0x80  128
KEY_LEFT_SHIFT  0x81  129
KEY_LEFT_ALT  0x82  130
KEY_LEFT_GUI  0x83  131
KEY_RIGHT_CTRL  0x84  132
KEY_RIGHT_SHIFT 0x85  133
KEY_RIGHT_ALT 0x86  134
KEY_RIGHT_GUI 0x87  135
KEY_UP_ARROW  0xDA  218
KEY_DOWN_ARROW  0xD9  217
KEY_LEFT_ARROW  0xD8  216
KEY_RIGHT_ARROW 0xD7  215
KEY_BACKSPACE 0xB2  178
KEY_TAB 0xB3  179
KEY_RETURN  0xB0  176
KEY_ESC 0xB1  177
KEY_INSERT  0xD1  209
KEY_DELETE  0xD4  212
KEY_PAGE_UP 0xD3  211
KEY_PAGE_DOWN 0xD6  214
KEY_HOME  0xD2  210
KEY_END 0xD5  213
KEY_CAPS_LOCK 0xC1  193
KEY_F1  0xC2  194
KEY_F2  0xC3  195
KEY_F3  0xC4  196
KEY_F4  0xC5  197
KEY_F5  0xC6  198
KEY_F6  0xC7  199
KEY_F7  0xC8  200
KEY_F8  0xC9  201
KEY_F9  0xCA  202
KEY_F10 0xCB  203
KEY_F11 0xCC  204
KEY_F12 0xCD  205

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/


/* Modifier key bit values */

#define MODBIT_LEFT_CTRL        0x01
#define MODBIT_LEFT_SHIFT       0x02
#define MODBIT_LEFT_ALT         0x04
#define MODBIT_LEFT_GUI         0x08
#define MODBIT_RIGHT_CTRL       0x10
#define MODBIT_RIGHT_SHIFT      0x20
#define MODBIT_RIGHT_ALT        0x40
#define MODBIT_RIGHT_GUI        0x80

/* From USB HID Usage Tables Version 1.12, Section 10 */

#define KEY_NONE            0
#define KEY_ErrorRollOver   1
#define KEY_POSTFail        2
#define KEY_ErrorUndefined  3
#define KEY_A   4
#define KEY_B   5
#define KEY_C   6
#define KEY_D   7
#define KEY_E   8
#define KEY_F   9
#define KEY_G   10
#define KEY_H   11
#define KEY_I   12
#define KEY_J   13
#define KEY_K   14
#define KEY_L   15
#define KEY_M   16
#define KEY_N   17
#define KEY_O   18
#define KEY_P   19
#define KEY_Q   20
#define KEY_R   21
#define KEY_S   22
#define KEY_T   23
#define KEY_U   24
#define KEY_V   25
#define KEY_W   26
#define KEY_X   27
#define KEY_Y   28
#define KEY_Z   29
#define KEY_1   30
#define KEY_2   31
#define KEY_3   32
#define KEY_4   33
#define KEY_5   34
#define KEY_6   35
#define KEY_7   36
#define KEY_8   37
#define KEY_9   38
#define KEY_0   39

#define KEY_ENTER       40
#define KEY_ESC         41
#define KEY_BACKSPACE   42
#define KEY_TAB         43
#define KEY_SPACE       44
#define KEY_MINUS       45 /* And underscore */
#define KEY_EQUALS      46 /* And plus */
#define KEY_OPEN_SQUARE 47 /* And open-curly-bracket */
#define KEY_CLOSE_SQUARE    48 /* And close-curly-bracket */
#define KEY_BACKSLASH   49
#define KEY_HASH_TILDE  50
#define KEY_SEMICOLON   51
#define KEY_SINGLE_QUOTE    52
#define KEY_BACKTICK_TILDE  53
#define KEY_COMMA       54 /* And less-than */
#define KEY_PERIOD      55 /* And greater-than */
#define KEY_SLASH       56 /* And question-mark */
#define KEY_CAPS_LOCK   57

#define KEY_F1          58
#define KEY_F2          59
#define KEY_F3          60
#define KEY_F4          61
#define KEY_F5          62
#define KEY_F6          63
#define KEY_F7          64
#define KEY_F8          65
#define KEY_F9          66
#define KEY_F10         67
#define KEY_F11         68
#define KEY_F12         69

#define KEY_PRINT_SCREEN    70
#define KEY_SCROLL_LOCK     71
#define KEY_PAUSE       72
#define KEY_INSERT      73
#define KEY_HOME        74
#define KEY_PAGE_UP     75
#define KEY_DELETE      76 /* i.e. forward delete */
#define KEY_END         77
#define KEY_PAGE_DOWN   78
#define KEY_RIGHT_ARROW 79
#define KEY_LEFT_ARROW  80
#define KEY_DOWN_ARROW  81
#define KEY_UP_ARROW    82

/* TODO: keypad codes */

#define KEY_LEFT_CTRL       0xE0
#define KEY_LEFT_SHIFT      0xE1
#define KEY_LEFT_ALT        0xE2
#define KEY_LEFT_GUI        0xE3
#define KEY_RIGHT_CTRL      0xE4
#define KEY_RIGHT_SHIFT     0xE5
#define KEY_RIGHT_ALT       0xE6
#define KEY_RIGHT_GUI       0xE7

#define KEY_MODIFIERS_START 0xE0
#define KEY_MODIFIERS_END   0xE7
#define IS_MODIFIER(key) ((key) >= KEY_MODIFIERS_START && (key) <= KEY_MODIFIERS_END)
#define MODIFIER_BIT(key) (1 << ((key)-KEY_MODIFIERS_START))



//#endif /* USB_HID_KEYBOARD_H */
#ifndef USB_HID_KEYBOARD_H
#define USB_HID_KEYBOARD_H

/* Modifier key bit values */

#define MODBIT_LEFT_CTRL        0x01
#define MODBIT_LEFT_SHIFT       0x02
#define MODBIT_LEFT_ALT         0x04
#define MODBIT_LEFT_GUI         0x08
#define MODBIT_RIGHT_CTRL       0x10
#define MODBIT_RIGHT_SHIFT      0x20
#define MODBIT_RIGHT_ALT        0x40
#define MODBIT_RIGHT_GUI        0x80

/* From USB HID Usage Tables Version 1.12, Section 10 */

#define KEY_NONE            0
#define KEY_ErrorRollOver   1
#define KEY_POSTFail        2
#define KEY_ErrorUndefined  3
#define KEY_A   4
#define KEY_B   5
#define KEY_C   6
#define KEY_D   7
#define KEY_E   8
#define KEY_F   9
#define KEY_G   10
#define KEY_H   11
#define KEY_I   12
#define KEY_J   13
#define KEY_K   14
#define KEY_L   15
#define KEY_M   16
#define KEY_N   17
#define KEY_O   18
#define KEY_P   19
#define KEY_Q   20
#define KEY_R   21
#define KEY_S   22
#define KEY_T   23
#define KEY_U   24
#define KEY_V   25
#define KEY_W   26
#define KEY_X   27
#define KEY_Y   28
#define KEY_Z   29
#define KEY_1   30
#define KEY_2   31
#define KEY_3   32
#define KEY_4   33
#define KEY_5   34
#define KEY_6   35
#define KEY_7   36
#define KEY_8   37
#define KEY_9   38
#define KEY_0   39

#define KEY_ENTER       40
#define KEY_ESC         41
#define KEY_BACKSPACE   42
#define KEY_TAB         43
#define KEY_SPACE       44
#define KEY_MINUS       45 /* And underscore */
#define KEY_EQUALS      46 /* And plus */
#define KEY_OPEN_SQUARE 47 /* And open-curly-bracket */
#define KEY_CLOSE_SQUARE    48 /* And close-curly-bracket */
#define KEY_BACKSLASH   49
#define KEY_HASH_TILDE  50
#define KEY_SEMICOLON   51
#define KEY_SINGLE_QUOTE    52
#define KEY_BACKTICK_TILDE  53
#define KEY_COMMA       54 /* And less-than */
#define KEY_PERIOD      55 /* And greater-than */
#define KEY_SLASH       56 /* And question-mark */
#define KEY_CAPS_LOCK   57

#define KEY_F1          58
#define KEY_F2          59
#define KEY_F3          60
#define KEY_F4          61
#define KEY_F5          62
#define KEY_F6          63
#define KEY_F7          64
#define KEY_F8          65
#define KEY_F9          66
#define KEY_F10         67
#define KEY_F11         68
#define KEY_F12         69

#define KEY_PRINT_SCREEN   70
#define KEY_SCROLL_LOCK    71
#define KEY_PAUSE       72
#define KEY_INSERT      73
#define KEY_HOME        74
#define KEY_PAGE_UP     75
#define KEY_DELETE      76 /* i.e. forward delete */
#define KEY_END         77
#define KEY_PAGE_DOWN   78
#define KEY_RIGHT_ARROW 79
#define KEY_LEFT_ARROW  80
#define KEY_DOWN_ARROW  81
#define KEY_UP_ARROW    82

/* TODO: keypad codes */

#define KEY_LEFT_CTRL       0xE0
#define KEY_LEFT_SHIFT      0xE1
#define KEY_LEFT_ALT        0xE2
#define KEY_LEFT_GUI        0xE3
#define KEY_RIGHT_CTRL      0xE4
#define KEY_RIGHT_SHIFT     0xE5
#define KEY_RIGHT_ALT       0xE6
#define KEY_RIGHT_GUI       0xE7

#define KEY_MODIFIERS_START 0xE0
#define KEY_MODIFIERS_END   0xE7
#define IS_MODIFIER(key) ((key) >= KEY_MODIFIERS_START && (key) <= KEY_MODIFIERS_END)
#define MODIFIER_BIT(key) (1 << ((key)-KEY_MODIFIERS_START))



#endif /* USB_HID_KEYBOARD_H */
#ifndef USB_HID_KEYBOARD_H
#define USB_HID_KEYBOARD_H

/* Modifier key bit values */

#define MODBIT_LEFT_CTRL        0x01
#define MODBIT_LEFT_SHIFT       0x02
#define MODBIT_LEFT_ALT         0x04
#define MODBIT_LEFT_GUI         0x08
#define MODBIT_RIGHT_CTRL       0x10
#define MODBIT_RIGHT_SHIFT      0x20
#define MODBIT_RIGHT_ALT        0x40
#define MODBIT_RIGHT_GUI        0x80

/* From USB HID Usage Tables Version 1.12, Section 10 */

#define KEY_NONE            0
#define KEY_ErrorRollOver   1
#define KEY_POSTFail        2
#define KEY_ErrorUndefined  3
#define KEY_A   4
#define KEY_B   5
#define KEY_C   6
#define KEY_D   7
#define KEY_E   8
#define KEY_F   9
#define KEY_G   10
#define KEY_H   11
#define KEY_I   12
#define KEY_J   13
#define KEY_K   14
#define KEY_L   15
#define KEY_M   16
#define KEY_N   17
#define KEY_O   18
#define KEY_P   19
#define KEY_Q   20
#define KEY_R   21
#define KEY_S   22
#define KEY_T   23
#define KEY_U   24
#define KEY_V   25
#define KEY_W   26
#define KEY_X   27
#define KEY_Y   28
#define KEY_Z   29
#define KEY_1   30
#define KEY_2   31
#define KEY_3   32
#define KEY_4   33
#define KEY_5   34
#define KEY_6   35
#define KEY_7   36
#define KEY_8   37
#define KEY_9   38
#define KEY_0   39

#define KEY_ENTER       40
#define KEY_ESC         41
#define KEY_BACKSPACE   42
#define KEY_TAB         43
#define KEY_SPACE       44
#define KEY_MINUS       45 /* And underscore */
#define KEY_EQUALS      46 /* And plus */
#define KEY_OPEN_SQUARE 47 /* And open-curly-bracket */
#define KEY_CLOSE_SQUARE    48 /* And close-curly-bracket */
#define KEY_BACKSLASH   49
#define KEY_HASH_TILDE  50
#define KEY_SEMICOLON   51
#define KEY_SINGLE_QUOTE    52
#define KEY_BACKTICK_TILDE  53
#define KEY_COMMA       54 /* And less-than */
#define KEY_PERIOD      55 /* And greater-than */
#define KEY_SLASH       56 /* And question-mark */
#define KEY_CAPS_LOCK   57

#define KEY_F1          58
#define KEY_F2          59
#define KEY_F3          60
#define KEY_F4          61
#define KEY_F5          62
#define KEY_F6          63
#define KEY_F7          64
#define KEY_F8          65
#define KEY_F9          66
#define KEY_F10         67
#define KEY_F11         68
#define KEY_F12         69

#define KEY_PRINT_SCREEN    70
#define KEY_SCROLL_LOCK     71
#define KEY_PAUSE       72
#define KEY_INSERT      73
#define KEY_HOME        74
#define KEY_PAGE_UP     75
#define KEY_DELETE      76 /* i.e. forward delete */
#define KEY_END         77
#define KEY_PAGE_DOWN   78
#define KEY_RIGHT_ARROW 79
#define KEY_LEFT_ARROW  80
#define KEY_DOWN_ARROW  81
#define KEY_UP_ARROW    82

/* TODO: keypad codes */

#define KEY_LEFT_CTRL       0xE0
#define KEY_LEFT_SHIFT      0xE1
#define KEY_LEFT_ALT        0xE2
#define KEY_LEFT_GUI        0xE3
#define KEY_RIGHT_CTRL      0xE4
#define KEY_RIGHT_SHIFT     0xE5
#define KEY_RIGHT_ALT       0xE6
#define KEY_RIGHT_GUI       0xE7

#define KEY_MODIFIERS_START 0xE0
#define KEY_MODIFIERS_END   0xE7
#define IS_MODIFIER(key) ((key) >= KEY_MODIFIERS_START && (key) <= KEY_MODIFIERS_END)
#define MODIFIER_BIT(key) (1 << ((key)-KEY_MODIFIERS_START))



#endif /* USB_HID_KEYBOARD_H */



#ifndef PS2Keyboard_h
#define PS2Keyboard_h

#include 
#include 
#include 
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h" // for attachInterrupt, FALLING
#else
#include "WProgram.h"
#endif

// Every call to read() returns a single byte for each
// keystroke.  These configure what byte will be returned
// for each "special" key.  To ignore a key, use zero.
#define PS2_TAB    9
#define PS2_ENTER   13
#define PS2_LINEFEED   10
#define PS2_BACKSPACE   127
#define PS2_ESC    27
#define PS2_INSERT   0
#define PS2_DELETE   127
#define PS2_HOME   0
#define PS2_END    0
#define PS2_PAGEUP   25
#define PS2_PAGEDOWN   26
#define PS2_UPARROW   11
#define PS2_LEFTARROW   8
#define PS2_DOWNARROW   12
#define PS2_RIGHTARROW   21
#define PS2_F1    1
#define PS2_F2    2
#define PS2_F3    3
#define PS2_F4    4
#define PS2_F5    5
#define PS2_F6    6
#define PS2_F7    7
#define PS2_F8    8
#define PS2_F9    9
#define PS2_F10    10
#define PS2_F11    11
#define PS2_F12    12
#define PS2_SCROLL  0

#define PS2_INVERTED_EXCLAMATION 161 // ¡
#define PS2_CENT_SIGN   162 // ¢
#define PS2_POUND_SIGN   163 // £
#define PS2_CURRENCY_SIGN  164 // ¤
#define PS2_YEN_SIGN   165 // ¥
#define PS2_BROKEN_BAR                  166 // ¦
#define PS2_SECTION_SIGN  167 // §
#define PS2_DIAERESIS   168 // ¨
#define PS2_COPYRIGHT_SIGN  169 // ©
#define PS2_FEMININE_ORDINAL  170 // ª
#define PS2_LEFT_DOUBLE_ANGLE_QUOTE 171 // «
#define PS2_NOT_SIGN   172 // ¬
#define PS2_HYPHEN   173
#define PS2_REGISTERED_SIGN  174 // ®
#define PS2_MACRON   175 // ¯
#define PS2_DEGREE_SIGN   176 // °
#define PS2_PLUS_MINUS_SIGN  177 // ±
#define PS2_SUPERSCRIPT_TWO  178 // ²
#define PS2_SUPERSCRIPT_THREE  179 // ³
#define PS2_ACUTE_ACCENT  180 // ´
#define PS2_MICRO_SIGN   181 // µ
#define PS2_PILCROW_SIGN  182 // ¶
#define PS2_MIDDLE_DOT   183 // ·
#define PS2_CEDILLA   184 // ¸
#define PS2_SUPERSCRIPT_ONE  185 // ¹
#define PS2_MASCULINE_ORDINAL  186 // º
#define PS2_RIGHT_DOUBLE_ANGLE_QUOTE 187 // »
#define PS2_FRACTION_ONE_QUARTER 188 // ¼
#define PS2_FRACTION_ONE_HALF  189 // ½
#define PS2_FRACTION_THREE_QUARTERS 190 // ¾
#define PS2_INVERTED_QUESTION MARK 191 // ¿
#define PS2_A_GRAVE   192 // À
#define PS2_A_ACUTE   193 // Á
#define PS2_A_CIRCUMFLEX  194 // Â
#define PS2_A_TILDE   195 // Ã
#define PS2_A_DIAERESIS   196 // Ä
#define PS2_A_RING_ABOVE  197 // Å
#define PS2_AE    198 // Æ
#define PS2_C_CEDILLA   199 // Ç
#define PS2_E_GRAVE   200 // È
#define PS2_E_ACUTE   201 // É
#define PS2_E_CIRCUMFLEX  202 // Ê
#define PS2_E_DIAERESIS   203 // Ë
#define PS2_I_GRAVE   204 // Ì
#define PS2_I_ACUTE   205 // Í
#define PS2_I_CIRCUMFLEX  206 // Î
#define PS2_I_DIAERESIS   207 // Ï
#define PS2_ETH    208 // Ð
#define PS2_N_TILDE   209 // Ñ
#define PS2_O_GRAVE   210 // Ò
#define PS2_O_ACUTE   211 // Ó
#define PS2_O_CIRCUMFLEX  212 // Ô
#define PS2_O_TILDE   213 // Õ
#define PS2_O_DIAERESIS   214 // Ö
#define PS2_MULTIPLICATION  215 // ×
#define PS2_O_STROKE   216 // Ø
#define PS2_U_GRAVE   217 // Ù
#define PS2_U_ACUTE   218 // Ú
#define PS2_U_CIRCUMFLEX  219 // Û
#define PS2_U_DIAERESIS   220 // Ü
#define PS2_Y_ACUTE   221 // Ý
#define PS2_THORN   222 // Þ
#define PS2_SHARP_S   223 // ß
#define PS2_a_GRAVE   224 // à
#define PS2_a_ACUTE   225 // á
#define PS2_a_CIRCUMFLEX  226 // â
#define PS2_a_TILDE   227 // ã
#define PS2_a_DIAERESIS   228 // ä
#define PS2_a_RING_ABOVE  229 // å
#define PS2_ae    230 // æ
#define PS2_c_CEDILLA   231 // ç
#define PS2_e_GRAVE   232 // è
#define PS2_e_ACUTE   233 // é
#define PS2_e_CIRCUMFLEX  234 // ê
#define PS2_e_DIAERESIS   235 // ë
#define PS2_i_GRAVE   236 // ì
#define PS2_i_ACUTE   237 // í
#define PS2_i_CIRCUMFLEX  238 // î
#define PS2_i_DIAERESIS   239 // ï
#define PS2_eth    240 // ð
#define PS2_n_TILDE   241 // ñ
#define PS2_o_GRAVE   242 // ò
#define PS2_o_ACUTE   243 // ó
#define PS2_o_CIRCUMFLEX  244 // ô
#define PS2_o_TILDE   245 // õ
#define PS2_o_DIAERESIS   246 // ö
#define PS2_DIVISION   247 // ÷
#define PS2_o_STROKE   248 // ø
#define PS2_u_GRAVE   249 // ù
#define PS2_u_ACUTE   250 // ú
#define PS2_u_CIRCUMFLEX  251 // û
#define PS2_u_DIAERESIS   252 // ü
#define PS2_y_ACUTE   253 // ý
#define PS2_thorn   254 // þ
#define PS2_y_DIAERESIS   255 // ÿ


#define PS2_KEYMAP_SIZE 136

typedef struct {
 uint8_t noshift[PS2_KEYMAP_SIZE];
 uint8_t shift[PS2_KEYMAP_SIZE];
 uint8_t uses_altgr;
 uint8_t altgr[PS2_KEYMAP_SIZE];
} PS2Keymap_t;


extern const PROGMEM PS2Keymap_t PS2Keymap_US;


//
// 8 in each row starting with 0 
//

char keymap[] = 
  // without shift
  {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, 'F1', /* 7 */ 
  0, PS2_F10, PS2_F8, PS2_F6, '4', PS2_TAB, '`', 'F2', /* 15 */ 
  0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 'F3', /* 23 */ 
  0, 0, 'z', 's', 'a', 'w', '2', 0,
  0, 'c', 'x', 'd', 'e', '4', '3', 0,
  0, ' ', 'v', 'f', 't', 'r', '5', 0,
  0, 'n', 'b', 'h', 'g', 'y', '6', 0,
  0, 0, 'm', 'j', 'u', '7', '8', 0,
  0, ',', 'k', 'i', 'o', '0', '9', 0,
  0, '.', '/', 'l', ';', 'p', '-', 0,
  0, 0, '\'', 0, '[', '=', 0, 0,
  0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '\\', 0, 0,
  0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
  0, '1', 0, '4', '7', 0, 0, 0,
  '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  0, 0, 0, PS2_F7 };

  

  const PROGMEM char keymap1[] = 
  // with shift
  {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
  0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '~', 0,
  0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
  0, 0, 'Z', 'S', 'A', 'W', '@', 0,
  0, 'C', 'X', 'D', 'E', '$', '#', 0,
  0, ' ', 'V', 'F', 'T', 'R', '%', 0,
  0, 'N', 'B', 'H', 'G', 'Y', '^', 0,
  0, 0, 'M', 'J', 'U', '&', '*', 0,
  0, '<', 'K', 'I', 'O', ')', '(', 0,
  0, '>', '?', 'L', ':', 'P', '_', 0,
  0, 0, '"', 0, '{', '+', 0, 0,
  0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '}', 0, '|', 0, 0,
  0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
  0, '1', 0, '4', '7', 0, 0, 0,
  '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
  PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
  0, 0, 0, PS2_F7 
  };


/**
 * Purpose: Provides an easy access to PS2 keyboards
 * Author:  Christian Weichel
 */
class PS2Keyboard {
  public:
   /**
    * This constructor does basically nothing. Please call the begin(int,int)
    * method before using any other method of this class.
    */
    PS2Keyboard();
    
    /**
     * Starts the keyboard "service" by registering the external interrupt.
     * setting the pin modes correctly and driving those needed to high.
     * The propably best place to call this method is in the setup routine.
     */
    static void begin(uint8_t dataPin, uint8_t irq_pin, const PS2Keymap_t &map = PS2Keymap_US);
    
    /**
     * Returns true if there is a char to be read, false if not.
     */
    static bool available();
    
    /**
     * Returns the char last read from the keyboard.
     * If there is no char availble, -1 is returned.
     */
    static int read();
};

// interrupt pins for known boards
#if !defined(CORE_INT0_PIN)
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Arduino Mega
#define CORE_INT0_PIN  2
#define CORE_INT1_PIN  3
#define CORE_INT2_PIN  21
#define CORE_INT3_PIN  20
#define CORE_INT4_PIN  19
#define CORE_INT5_PIN  18
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino
#define CORE_INT0_PIN  10
#define CORE_INT1_PIN  11
#define CORE_INT2_PIN  2
#else  // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc...
#define CORE_INT0_PIN  2
#define CORE_INT1_PIN  3
#endif
#endif
#endif

Tuesday, May 13, 2014

SCADBoard Library and the SCADuino

SCADuino - a 3D Printed Breadboard Arduino
SCADBoard is a library for making 3D Printable Circuit Boards
SCADBoard is a library for OpenSCAD to make prototype circuit boards. It makes 3D models which can then be exported and printed using a 3D printer. SCADBoard is open source and fully customizable.


SCADuino is a 3D printed Breadboard Arduino
SCADuino is a 3D printable version of the Breadboard Arduino at Arduino.cc. Using OpenSCAD and the SCADBoard library it is easy to create a 3D printable breadboard like the Breadboard Arduino.

Saturday, December 17, 2011

Tide Clock for Android Version 1.2.0


Tide Clock is for boaters, fisherman, sailors, surfers, sun bathers, swimmers, kayakers, water skiers, paddle boarders, wind surfers, sheller's, and generally any non-landlubber or beach goers’. Tide Clock is just that - a clock that keeps track of the tides. The latest version is now super easy to set. 

"Do you know what tide it is?"

Version 1.2.0 – Now Easy to set with your finger

With version 1.2.0 you can now set the tide with a touch of your finger. Just enable Easy Tide Setting Mode in Settings, and with your finger move the tide hand to the location of the tide.

There are other minor fixes and enhancements as well as some enhancements for tablets.

Please remember, your Android Tide Clock is a clock. If the tides are consistent in your location you can go months or even years without needing to adjust it. At many locations, like the east coast of the United States, tide clocks can run accurately for years. Your location may be different. If you not sure, check with your local marina or boating supply store. They often sell desk and wall style tide clocks. 

Tide Clock is not for navigation purposes, but can be used to keep track of the tide for water and beach related activities. It is your responsibility to set and check your tide setting.


Tide Clock includes setting options, color themes, and a place for the name of your boat and your location. It does not use excessive battery, and does not require GPS or data downloads. It has been tested to work on tablets and phones alike.


Tide Clock is only $.99 US in Android Market.
From Coded by Elves

Available in Android Market

If you would like a branded version of Tide Clock for your company, boat or crew - with theme or logo, please feel free to email me.

See the new themes below... 

SETTING YOUR TIDE CLOCK
Now, setting the Android Tide Clock is super easy. Simply observe the tide and adjust the clock with a swipe of your finger.

You can also use the time of the next high tide and adjust the clock using the Next High value.

TO SET YOUR TIDE CLOCK

1) Press your Settings button and then press Tide Clock Settings.

2) Select the EASY TIDE SETTING MODE checkbox as shown below and then hit return.   
                                        
3) With your finger, drag the clock hand to the location that matches your observed tide or use the Next high tide window.
             
4) Press Set when you are done.  
             
Depending the consistency of the tides at your location, occasionally adjust this setting to keep your tide clock accurate. TideClock is easiest to set when high tide is only a few hours away.

The numbers on the right side of the clock are hours until low tide. The numbers on the left are hours until high tide.




     

Themes: Skinny Dipper | Map Blue | White Caps | Knock Knock

   

Themes: Sea Cucumber | Jellyfish | Red Nun | Ship Wreck



The Android Tide Clock site is also at: https://sites.google.com/site/codedbyelves/home

We use: The Gimp Eclipse Inkscape