Merge pull request #117 from wind-rider/surface_dial

Add Surface Dial support
This commit is contained in:
Nico 2017-08-31 20:21:36 +02:00 committed by GitHub
commit 3c5000c4b6
8 changed files with 376 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

View file

@ -0,0 +1,85 @@
/*
Copyright (c) 2017 wind-rider
See the readme for credit to other people.
Surface dial example
Use an encoder and a button to create a Surface Dial-compatible device.
See the connection diagram how to wire it up.
Please note that:
- I tested it using an Arduino Pro Micro; TinkerCad didn't have that in its component library
- you obviously don't need a motor, but TinkerCad didn't have a separate encoder
The encoder processing code is coming from https://www.allwinedesigns.com/blog/pocketnc-jog-wheel
*/
#include "HID-Project.h"
// input pins for encoder channel A and channel B
int pinA = 2;
int pinB = 3;
// input pin for pushbutton
int pinButton = 4;
volatile bool previousButtonValue = false;
volatile int previous = 0;
volatile int counter = 0;
void setup() {
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
pinMode(pinButton, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinA), changed, CHANGE);
attachInterrupt(digitalPinToInterrupt(pinB), changed, CHANGE);
SurfaceDial.begin();
}
void changed() {
int A = digitalRead(pinA);
int B = digitalRead(pinB);
int current = (A << 1) | B;
int combined = (previous << 2) | current;
if(combined == 0b0010 ||
combined == 0b1011 ||
combined == 0b1101 ||
combined == 0b0100) {
counter++;
}
if(combined == 0b0001 ||
combined == 0b0111 ||
combined == 0b1110 ||
combined == 0b1000) {
counter--;
}
previous = current;
}
void loop(){
bool buttonValue = digitalRead(pinButton);
if(buttonValue != previousButtonValue){
if(buttonValue) {
SurfaceDial.press();
} else {
SurfaceDial.release();
}
previousButtonValue = buttonValue;
}
if(counter >= 4) {
SurfaceDial.rotate(10);
counter -= 4;
} else if(counter <= -4) {
SurfaceDial.rotate(-10);
counter += 4;
}
}

View file

@ -0,0 +1,66 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Include guard
#pragma once
#include <Arduino.h>
#include "HID-Settings.h"
typedef union{
// SurfaceDial report: 1 button, 15-bit rotation, position
uint8_t whole8[0];
uint16_t whole16[0];
uint32_t whole32[0];
struct{
uint16_t button: 1;
uint16_t rotation: 15;
//int8_t xAxis;
//int8_t yAxis;
};
} HID_SurfaceDialReport_Data_t;
class SurfaceDialAPI
{
public:
inline SurfaceDialAPI(void);
inline void begin(void);
inline void end(void);
inline void click(void);
inline void rotate(int16_t rotation);
inline void press(void);
inline void release(void);
inline void releaseAll(void);
inline bool isPressed();
// Sending is public in the base class for advanced users.
virtual void SendReport(void* data, int length) = 0;
protected:
bool _button;
inline void button(bool b);
};
// Implementation is inline
#include "SurfaceDialAPI.hpp"

View file

@ -0,0 +1,90 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Include guard
#pragma once
SurfaceDialAPI::SurfaceDialAPI(void) : _button(false)
{
// Empty
}
void SurfaceDialAPI::begin(void)
{
end();
}
void SurfaceDialAPI::end(void)
{
_button = false;
rotate(0);
}
void SurfaceDialAPI::click(void)
{
_button = true;
rotate(0);
_button = false;
rotate(0);
}
void SurfaceDialAPI::rotate(int16_t rotation)
{
HID_SurfaceDialReport_Data_t report;
report.button = _button;
report.rotation = rotation;
//report.xAxis = x;
//report.yAxis = y;
SendReport(&report, sizeof(report));
}
void SurfaceDialAPI::button(bool b)
{
if (b != _button)
{
_button = b;
rotate(0);
}
}
void SurfaceDialAPI::press(void)
{
button(true);
}
void SurfaceDialAPI::release(void)
{
button(false);
}
void SurfaceDialAPI::releaseAll(void)
{
_button = false;
rotate(0);
}
bool SurfaceDialAPI::isPressed()
{
return _button;
}

View file

@ -51,6 +51,7 @@ THE SOFTWARE.
#include "MultiReport/ImprovedKeyboard.h"
#include "SingleReport/SingleNKROKeyboard.h"
#include "MultiReport/NKROKeyboard.h"
#include "MultiReport/SurfaceDial.h"
// Include Teensy HID afterwards to overwrite key definitions if used
// TODO include Teensy API if non english keyboard layout was used

View file

@ -108,3 +108,7 @@ THE SOFTWARE.
#ifndef HID_REPORTID_TEENSY_KEYBOARD
#define HID_REPORTID_TEENSY_KEYBOARD 9
#endif
#ifndef HID_REPORTID_SURFACEDIAL
#define HID_REPORTID_SURFACEDIAL 10
#endif

View file

@ -0,0 +1,87 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "SurfaceDial.h"
static const uint8_t _hidMultiReportDescriptorSurfaceDial[] PROGMEM = {
// Integrated Radial Controller TLC
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x0e, // USAGE (System Multi-Axis Controller)
0xa1, 0x01, // COLLECTION (Application)
0x85, HID_REPORTID_SURFACEDIAL, // REPORT_ID (Radial Controller)
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x21, // USAGE (Puck)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Buttons)
0x09, 0x01, // USAGE (Button 1)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x01, // REPORT_SIZE (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x37, // USAGE (Dial)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x0f, // REPORT_SIZE (15)
0x55, 0x0f, // UNIT_EXPONENT (-1)
0x65, 0x14, // UNIT (Degrees, English Rotation)
0x36, 0xf0, 0xf1, // PHYSICAL_MINIMUM (-3600)
0x46, 0x10, 0x0e, // PHYSICAL_MAXIMUM (3600)
0x16, 0xf0, 0xf1, // LOGICAL_MINIMUM (-3600)
0x26, 0x10, 0x0e, // LOGICAL_MAXIMUM (3600)
0x81, 0x06, // INPUT (Data,Var,Rel)
// 0x09, 0x30, // USAGE (X)
// 0x75, 0x10, // REPORT_SIZE (16)
// 0x55, 0x0d, // UNIT_EXPONENT (-3)
// 0x65, 0x13, // UNIT (Inch,EngLinear)
// 0x35, 0x00, // PHYSICAL_MINIMUM (0)
// 0x46, 0xc0, 0x5d, // PHYSICAL_MAXIMUM (24000)
// 0x15, 0x00, // LOGICAL_MINIMUM (0)
// 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
// 0x81, 0x02, // INPUT (Data,Var,Abs)
// 0x09, 0x31, // USAGE (Y)
// 0x46, 0xb0, 0x36, // PHYSICAL_MAXIMUM (14000)
// 0x81, 0x02, // INPUT (Data,Var,Abs)
// 0x05, 0x0d, // USAGE_PAGE (Digitizers)
// 0x09, 0x48, // USAGE (Width)
// 0x36, 0xb8, 0x0b, // PHYSICAL_MINIMUM (3000)
// 0x46, 0xb8, 0x0b, // PHYSICAL_MAXIMUM (3000)
// 0x16, 0xb8, 0x0b, // LOGICAL_MINIMUM (3000)
// 0x26, 0xb8, 0x0b, // LOGICAL_MAXIMUM (3000)
// 0x81, 0x03 // INPUT (Cnst,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
SurfaceDial_::SurfaceDial_(void)
{
static HIDSubDescriptor node(_hidMultiReportDescriptorSurfaceDial, sizeof(_hidMultiReportDescriptorSurfaceDial));
HID().AppendDescriptor(&node);
}
void SurfaceDial_::SendReport(void *data, int length)
{
HID().SendReport(HID_REPORTID_SURFACEDIAL, data, length);
}
SurfaceDial_ SurfaceDial;

View file

@ -0,0 +1,43 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Include guard
#pragma once
#include <Arduino.h>
#include "PluggableUSB.h"
#include "HID.h"
#include "HID-Settings.h"
#include "../HID-APIs/SurfaceDialAPI.h"
class SurfaceDial_ : public SurfaceDialAPI
{
public:
SurfaceDial_(void);
protected:
virtual inline void SendReport(void* data, int length) override;
};
extern SurfaceDial_ SurfaceDial;