Initial upload of the Physical Flick keyboard files.

This commit is contained in:
yamaguchi-am
2016-04-01 00:04:23 +09:00
parent 45d465b9ce
commit a7241d1900
5 changed files with 298 additions and 0 deletions

93
mozc-furikku/README.md Normal file
View File

@@ -0,0 +1,93 @@
Copyright 2016 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Summary
=====================================
Circuit diagram and firmware of Google Japanese Input physical flick version.
Files
=====================================
* README.md -- this file
* arduino/flick/* -- firmware source code (Arduino sketch)
* circuit.png -- circuit diagram
Building your device
=====================================
## Electronic parts
* Arduino Nano * 1
* RN-42-I/RM * 1
* SJoys 2-axes joystick module (Sainsmart) * 12
* 0.1uF ceramic capacitor * 4
* 470 ohm resistor * 1
* 1k ohm resistor * 1
* Connectors
## RN42 configuration
This step is required for the first time, or when changing the device's name.
See Microchip's documents for detail.
1. Run a terminal emulator and open the serial port for Arduino.
2. Type '!' to enter pass-through mode.
3. Type '$$$'.
4. Configure the module by these commands:
* * * * * *
SU,115k
SM,6
SA,2
S~,6
SH,0000
SN,MY_PHYSICAL_FLICK_KEYBOARD
R,1
* * * * * *
MY\_PHYSICAL\_FLICK\_KEYBOARD is a device name that will appear when you scan
Bluetooth devices, and can be replaced by your preferred name.
The commands will configure the module as follows:
* 115200bps
* Pairing mode
* SSP "just works" mode
* SPP profile
* HID flag register = 0 (keyboard)
Using flick input
=====================================
## Power supply
When operating the device, supply power by USB cables to Arduino Nano.
## Bluetooth pairing
Using your device (e.g. Android phone), scan Bluetooth devices and you will
find MY\_PHYSICAL\_FLICK\_KEYBOARD (or the name you set up) in the available
device list.
After pairing, find the device in the "physical keyboard" section and choose
"English - U.S." keyboard layout for it.
## How to input
Switch the Japanese IME on the paired device to romaji input mode.
Characters will be input as flick or press a key.

View File

@@ -0,0 +1,110 @@
#include <SPI.h>
#include "flick_keyboard.h"
// Number of A/D converter ICs.
const int kNumAdcIc = 3;
const int kCsPins[kNumAdcIc] = {10, 9, 8};
const int kButtonPins[12] = {
// If you use Arduino Nano version 2, use A6 and A7 instead of A0 and A1.
// (which are actually port C, thus used as digital input)
A0, A1, A2, A3, A4, A5,
7, 6, 5, 4, 3, 2
};
FlickKeyboard keyboard;
void setup() {
Serial.begin(115200);
for (size_t i = 0; i < kNumAdcIc; i++) {
pinMode(kCsPins[i], OUTPUT);
digitalWrite(kCsPins[i], HIGH);
}
for (size_t i = 0; i < 12; i++) {
pinMode(kButtonPins[i], INPUT_PULLUP);
}
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
}
void SelectChip(uint8_t id) {
if (id > kNumAdcIc) {
return;
}
for (size_t i = 0; i < kNumAdcIc; i++) {
digitalWrite(kCsPins[i], HIGH);
}
digitalWrite(kCsPins[id], LOW);
}
void DeselectChips() {
for (size_t i = 0; i < kNumAdcIc; i++) {
digitalWrite(kCsPins[i], HIGH);
}
}
// Fetch a ADC result of a specified channel from a MCP3208.
int16_t ReadMcp3208Adc(uint8_t chipId, uint8_t channel) {
SelectChip(chipId);
// MCP3208 receives only 5 bits for start.
// Since the SPI library only supports bytewise tramsmission,
// we send dummy (high-level) bits before the start bit.
// Send data :
// 3 dummy bits (000)
// start bit (1)
// select single-end (1)
// 3 address bits: d2, d1, d0
SPI.transfer(0x18 | channel);
uint16_t b0 = SPI.transfer(0x00);
uint16_t b1 = SPI.transfer(0x00);
DeselectChips();
// The first output bit is high-Z (sampling period).
// The second bit is always 0.
// Then the ADC value follows in MSB first format.
// Therefore the first received byte contains 6 bits from MSB,
// and the second byte contains the remainder.
return ((b0 & 0x3f) << 6) | ((b1 & 0xfc) >> 2);
}
void ReadSwitches(bool* button) {
for (size_t i = 0; i < 12; i++) {
button[i] = (digitalRead(kButtonPins[i]) == LOW);
}
}
void ReadVolumes(uint16_t* data) {
byte inByte = 0;
for (uint8_t j = 0; j < kNumAdcIc; j++) {
for (uint8_t i = 0; i < 8; i++) {
data[j * 8 + i] = ReadMcp3208Adc(j, i);
}
}
}
// Passes through any serial input to the output.
// This mode can be used to configure RN-42 using serial terminal
// connected to Arduino.
void EchoBackMode() {
while (true) {
if (Serial.available()) {
Serial.print((char)Serial.read());
}
}
}
void loop() {
if (Serial.available() && Serial.read() == '!') {
EchoBackMode();
}
SensorData keys;
ReadVolumes(keys.axes);
ReadSwitches(keys.button);
int nOutputs;
const char* outputs[COLS];
keyboard.ProcessSensorData(keys, COLS, outputs, &nOutputs);
for (size_t i = 0; i < nOutputs; i++) {
Serial.print(outputs[i]);
}
}

View File

@@ -0,0 +1,67 @@
#include "flick_keyboard.h"
#include <stdint.h>
#define ADC_BITS 12
void FlickKeyboard::ProcessSensorData(const SensorData& data, size_t maxKeyNum,
const char** outputStrings, int* nOutputs) {
const char* characters[COLS][ROWS] = {
{"a", "i", "u", "e", "o"},
{"ka", "ki", "ku", "ke", "ko"},
{"sa", "si", "su", "se", "so"},
{"ta", "ti", "tu", "te", "to"},
{"na", "ni", "nu", "ne", "no"},
{"ha", "hi", "hu", "he", "ho"},
{"ma", "mi", "mu", "me", "mo"},
{"ya", "(", "yu", ")", "yo"},
{"ra", "ri", "ru", "re", "ro"},
{"\n", "\b", "", " ", ""},
{"wa", "wo", "nn", "-", "~"},
{",", ".", "?", "!", "..."}
};
*nOutputs = 0;
for (size_t i = 0; i < COLS; i++) {
Direction s = ConvertToFlickState(data.axes[i * 2 + 1],
data.axes[i * 2], data.button[i]);
if (lastState[i] == NONE && s != NONE) {
if (*nOutputs < maxKeyNum) {
outputStrings[(*nOutputs)++] = characters[i][s];
}
}
lastState[i] = s;
}
}
FlickKeyboard::FlickKeyboard() {
for (size_t i = 0; i < COLS; i++) {
lastState[i] = NONE;
}
}
Direction FlickKeyboard::ConvertToFlickState(
int16_t x, int16_t y, bool buttonPressed) {
const int16_t adScale = 1 << ADC_BITS;
const int16_t adCenter = adScale / 2;
const int16_t threshold = adScale * 0.4;
int16_t diffX = x - adCenter;
int16_t diffY = y - adCenter;
if (buttonPressed) {
return CENTER;
}
if (abs(diffX) > abs(diffY)) {
if (diffX < -threshold) {
return LEFT;
} else if (diffX > threshold) {
return RIGHT;
}
} else {
if (diffY < -threshold) {
return UP;
} else if (diffY > threshold) {
return DOWN;
}
}
return NONE;
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
#define ROWS 5
#define COLS 12 // Equals to the number of the keys.
enum Direction {
CENTER, LEFT, UP, RIGHT, DOWN, NONE
};
struct SensorData {
uint16_t axes[COLS * 2];
bool button[COLS];
};
class FlickKeyboard {
private:
Direction lastState[COLS];
Direction ConvertToFlickState(int16_t x, int16_t y,
bool buttonPressed);
public:
FlickKeyboard();
void ProcessSensorData(const SensorData& data, size_t maxKeyNum,
const char** outputStrings, int* nOutputs);
};

BIN
mozc-furikku/circuit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB