diff --git a/mozc-furikku/README.md b/mozc-furikku/README.md new file mode 100644 index 0000000..2dc123a --- /dev/null +++ b/mozc-furikku/README.md @@ -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. diff --git a/mozc-furikku/arduino/flick/flick.ino b/mozc-furikku/arduino/flick/flick.ino new file mode 100644 index 0000000..80f0010 --- /dev/null +++ b/mozc-furikku/arduino/flick/flick.ino @@ -0,0 +1,110 @@ +#include +#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]); + } +} + diff --git a/mozc-furikku/arduino/flick/flick_keyboard.cpp b/mozc-furikku/arduino/flick/flick_keyboard.cpp new file mode 100644 index 0000000..88c4ad9 --- /dev/null +++ b/mozc-furikku/arduino/flick/flick_keyboard.cpp @@ -0,0 +1,67 @@ +#include "flick_keyboard.h" +#include + +#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; +} + diff --git a/mozc-furikku/arduino/flick/flick_keyboard.h b/mozc-furikku/arduino/flick/flick_keyboard.h new file mode 100644 index 0000000..5412fc9 --- /dev/null +++ b/mozc-furikku/arduino/flick/flick_keyboard.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#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); +}; + diff --git a/mozc-furikku/circuit.png b/mozc-furikku/circuit.png new file mode 100644 index 0000000..42b69c0 Binary files /dev/null and b/mozc-furikku/circuit.png differ