USB_Laptop_Keyboard_Controller/GRID 1550/Grid_Mouse.ino
2019-11-05 09:18:08 -08:00

156 lines
8.4 KiB
C++

/* Copyright 2019 Frank Adams
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.
*/
// This software reads the 6 logic signals from a Grid 1550 laptop "mouse" and converts it to USB.
// The Grid 1550 laptop has a shaft in place of a touchpad. The shaft is rolled forward or backwards
// which moves the cursor up or down. Likewise the entire shaft can be slid left or right to move the cursor left or right.
// There are two buttons on the left of the shaft and two buttons on the right of the shaft.
// The two buttons closest to the shaft act like normal left mouse buttons.
// The two buttons furthest from the shaft are right mouse buttons.
// Pins 3 and 4 are active for up/down movement. Pins 5 and 6 are active for left/right movement.
// The pin pairs use a rotational encoding scheme that is described in the following wiki page:
// https://en.wikipedia.org/wiki/Rotary_encoder
//
// I/O pins 0 & 1 are used to enable/disable the mouse and to adjust its speed
// I/O 1 I/O 0 Result
// High High Count by 1
// High Low Count by 2
// Low High Count by 3
// Low Low Mouse disabled
//
// Revision History
// Rev 1.0 - Nov 3, 2019 - Original Release
// Rev 1.1 - Nov 4, 2019 - Fixed swapped mouse buttons
// Rev 1.2 - Nov 4, 2019 - Added speed controls
//
#include <TimerOne.h> // used for making a 24msec timer
//
#define SPEED_PIN0 0 // Input with pullup - Can be driven by the Teensy controlling the keyboard
#define SPEED_PIN1 1 // Input with pullup - Can be driven by the Teensy controlling the keyboard
// Connect the Teensy I/O's 3 thru 8 to the Grid mouse connector pins 3 thru 8
#define MOUSE_PIN3 3 // Left/Right Encoder signal A
#define MOUSE_PIN4 4 // Left/Right Encoder signal B
#define MOUSE_PIN5 5 // Up/Down Encoder signal A
#define MOUSE_PIN6 6 // Up/Down Encoder signal B
#define MOUSE_PIN7 7 // Right Mouse Button
#define MOUSE_PIN8 8 // Left Mouse Button
//
// Declare and initialize variables
boolean left_button = 0; // on/off variable for left button, 1 = pushed
boolean right_button = 0; // on/off variable for right button, 1 = pushed
boolean old_left_button = 0; // on/off variable for left button from the previous cycle
boolean old_right_button = 0; // on/off variable for right button from the previous cycle
boolean button_change = 0; // Shows when the left or right buttons have changed, 1 = change
volatile int8_t x_count = 0; // left/right movement. 8 bit signed. Volatile because used in ISR
volatile int8_t y_count = 0; // up or down movement. 8 bit signed. Volatile because used in ISR
boolean x_A; // holds the state of pin 3
boolean x_A_Last; // holds the previous state of pin 3
boolean y_A; // holds the state of pin 5
boolean y_A_Last; // holds the previous state of pin 5
boolean mouse_on = 1; // high when mouse is turned on, low when turned off
boolean speed0 = 1; // result of reading pin 0
boolean speed1 = 1; // result of reading pin 1
int8_t count_by = 1; // value to add or substract from x & y counters (1, 2, or 3 depending on SPEED_PIN0 & 1)
//
// USB Interrupt Service Routine (ISR) Activates every 24msec when timer1 ticks
void sendUSB(void) {
// send the x and y data back to the host via usb if either counter is non-zero.
// if the mouse is turned off, the counters can't increment so they will both be zero.
if ((x_count != 0x00) || (y_count != 0x00)) {
Mouse.move(x_count,y_count);
x_count = 0; // clear the x and y counters
y_count = 0;
}
// read the touchpad left and right buttons
if (!digitalRead(MOUSE_PIN7)) { // check if right button is low (low = pushed)
right_button = 1; // save state of button
}
else { // clear right button
right_button = 0; // save state of button
}
if (!digitalRead(MOUSE_PIN8)) { // check if left button is low (low = pushed)
left_button = 1; // save state of button
}
else { // clear left button
left_button = 0; // save state of button
}
// Determine if the left or right mouse buttons have changed (using XOR) since the last cycle
button_change = (left_button ^ old_left_button) | (right_button ^ old_right_button);
// Don't send button status if there's no change since last time or if the mouse is turned off.
if (button_change && mouse_on){
Mouse.set_buttons(left_button, 0, right_button); // send button status over USB
}
old_left_button = left_button; // remember button status for the next cycle
old_right_button = right_button;
}
// *****************Setup the timer and input pins***********************************************
void setup() {
Timer1.initialize(24000); // 24msec timer
Timer1.attachInterrupt(sendUSB); // sendUSB function will run every 24 milliseconds
pinMode(SPEED_PIN0, INPUT_PULLUP); // both speed controls are inputs with pullups
pinMode(SPEED_PIN1, INPUT_PULLUP); // if left floating, both will be 1's to give count_by 1
pinMode(MOUSE_PIN3, INPUT); // teensy I/O 3 is an input for left/right signal A
pinMode(MOUSE_PIN4, INPUT); // teensy I/O 4 is an input for left/right signal B
pinMode(MOUSE_PIN5, INPUT); // teensy I/O 5 is an input for up/down signal A
pinMode(MOUSE_PIN6, INPUT); // teensy I/O 6 is an input for up/down signal B
pinMode(MOUSE_PIN7, INPUT); // teensy I/O 7 is an input for right mouse button
pinMode(MOUSE_PIN8, INPUT); // teensy I/O 8 is an input for left mouse button
x_A_Last = digitalRead(MOUSE_PIN3); // save logic state of pin 3
y_A_Last = digitalRead(MOUSE_PIN5); // save logic state of pin 5
}
// *********Main Loop constantly watches for activity on pins 3 and 5 plus status on pins 0 & 1*********
void loop() {
// adjust the x counter if pin 3 changes (i.e. has an up or down edge)
x_A = digitalRead(MOUSE_PIN3); // Read the current state of pin 3
if (x_A != x_A_Last){ // If pin 3 is different than the previous pin 3, an edge has occured.
noInterrupts(); // disable the timer interrupt while modifying the x counter
if (digitalRead(MOUSE_PIN4) != x_A) { // see if pin 4 equals pin 3
x_count = x_count + count_by; // pin 3 is ahead of pin 4 so move the cursor to the right by increasing the counter
}
else {
x_count = x_count - count_by; // pin 3 is behind pin 4 so move the cursor to the left by decreasing the counter
}
interrupts(); // enable the timer interrupt
}
x_A_Last = x_A; // save the state of pin 3 for the next loop
// adjust the y counter if pin 5 has an up or down edge
y_A = digitalRead(MOUSE_PIN5); // Reads the current state of pin 5
if (y_A != y_A_Last){ // If pin 5 is different than the previous pin 5, an edge has occured.
noInterrupts(); // disable the timer interrupt while modifying the y counter
if (digitalRead(MOUSE_PIN6) != y_A) { // see if pin 6 equals pin 5
y_count = y_count + count_by; // pin 5 is ahead of pin 6 so move the cursor down by increasing the counter
}
else {
y_count = y_count - count_by; // pin 5 is behind pin 6 so move the cursor up by decreasing the counter
}
interrupts(); // enable the timer interrupt
}
y_A_Last = y_A; // save the state of pin 5 for the next loop
// Read speed pins 0 & 1 to adjust count and on/off control
speed0 = digitalRead(SPEED_PIN0);
speed1 = digitalRead(SPEED_PIN1);
if (speed0 && speed1) { // this is the high & high case
count_by = 1; // slow speed movement
mouse_on = 1; // turn mouse on
}
else if (!speed0 && speed1) { // this is the low & high case
count_by = 2; // middle speed movement
mouse_on = 1; // turn mouse on
}
else if (speed0 && !speed1){ // this is the high & low case
count_by = 3; // high speed movement
mouse_on = 1; // turn mouse on
}
else { // this is the low & low case
count_by = 0; // no movement
mouse_on = 0; // turn mouse off
}
}