Nintendo Switch joycon support, sensitivity and enhanced refreshing interval

This commit is contained in:
LuiCat 2019-03-04 17:09:16 +01:00
parent 46bbd1c081
commit fa7c5b371d
6 changed files with 526 additions and 55 deletions

128
HIDReportData.h Normal file
View File

@ -0,0 +1,128 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
* \brief Constants for HID report item attributes.
*
* HID report item constants for report item attributes. Refer to the HID specification for
* details on each flag's meaning when applied to an IN, OUT or FEATURE item.
*/
/** \ingroup Group_HIDParser
* \defgroup Group_HIDReportItemConst HID Report Descriptor Item Constants
*
* General HID constant definitions for HID Report Descriptor elements.
*
* @{
*/
#ifndef __HIDREPORTDATA_H__
#define __HIDREPORTDATA_H__
#warning Modified LUFA header file. Remove the file if problematic.
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* Macros: */
#define HID_RI_DATA_SIZE_MASK 0x03
#define HID_RI_TYPE_MASK 0x0C
#define HID_RI_TAG_MASK 0xF0
#define HID_RI_TYPE_MAIN 0x00
#define HID_RI_TYPE_GLOBAL 0x04
#define HID_RI_TYPE_LOCAL 0x08
#define HID_RI_DATA_BITS_0 0x00
#define HID_RI_DATA_BITS_8 0x01
#define HID_RI_DATA_BITS_16 0x02
#define HID_RI_DATA_BITS_32 0x03
#define HID_RI_DATA_BITS(DataBits) HID_RI_DATA_BITS_ ## DataBits
#define _HID_RI_ENCODE_0(Data)
#define _HID_RI_ENCODE_8(Data) , (Data & 0xFF)
#define _HID_RI_ENCODE_16(Data) _HID_RI_ENCODE_8(Data) _HID_RI_ENCODE_8(Data >> 8)
#define _HID_RI_ENCODE_32(Data) _HID_RI_ENCODE_16(Data) _HID_RI_ENCODE_16(Data >> 16)
#define _HID_RI_ENCODE(DataBits, ...) _HID_RI_ENCODE_ ## DataBits(__VA_ARGS__)
#define _HID_RI_ENTRY(Type, Tag, DataBits, ...) (Type | Tag | HID_RI_DATA_BITS(DataBits)) _HID_RI_ENCODE(DataBits, (__VA_ARGS__))
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** \name HID Input, Output and Feature Report Descriptor Item Flags */
//@{
#define HID_IOF_CONSTANT (1 << 0)
#define HID_IOF_DATA (0 << 0)
#define HID_IOF_VARIABLE (1 << 1)
#define HID_IOF_ARRAY (0 << 1)
#define HID_IOF_RELATIVE (1 << 2)
#define HID_IOF_ABSOLUTE (0 << 2)
#define HID_IOF_WRAP (1 << 3)
#define HID_IOF_NO_WRAP (0 << 3)
#define HID_IOF_NON_LINEAR (1 << 4)
#define HID_IOF_LINEAR (0 << 4)
#define HID_IOF_NO_PREFERRED_STATE (1 << 5)
#define HID_IOF_PREFERRED_STATE (0 << 5)
#define HID_IOF_NULLSTATE (1 << 6)
#define HID_IOF_NO_NULL_POSITION (0 << 6)
#define HID_IOF_VOLATILE (1 << 7)
#define HID_IOF_NON_VOLATILE (0 << 7)
#define HID_IOF_BUFFERED_BYTES (1 << 8)
#define HID_IOF_BITFIELD (0 << 8)
//@}
/** \name HID Report Descriptor Item Macros */
//@{
#define HID_RI_INPUT(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_MAIN , 0x80, DataBits, __VA_ARGS__)
#define HID_RI_OUTPUT(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_MAIN , 0x90, DataBits, __VA_ARGS__)
#define HID_RI_COLLECTION(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_MAIN , 0xA0, DataBits, __VA_ARGS__)
#define HID_RI_FEATURE(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_MAIN , 0xB0, DataBits, __VA_ARGS__)
#define HID_RI_END_COLLECTION(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_MAIN , 0xC0, DataBits, __VA_ARGS__)
#define HID_RI_USAGE_PAGE(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x00, DataBits, __VA_ARGS__)
#define HID_RI_LOGICAL_MINIMUM(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x10, DataBits, __VA_ARGS__)
#define HID_RI_LOGICAL_MAXIMUM(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x20, DataBits, __VA_ARGS__)
#define HID_RI_PHYSICAL_MINIMUM(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x30, DataBits, __VA_ARGS__)
#define HID_RI_PHYSICAL_MAXIMUM(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x40, DataBits, __VA_ARGS__)
#define HID_RI_UNIT_EXPONENT(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x50, DataBits, __VA_ARGS__)
#define HID_RI_UNIT(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x60, DataBits, __VA_ARGS__)
#define HID_RI_REPORT_SIZE(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x70, DataBits, __VA_ARGS__)
#define HID_RI_REPORT_ID(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x80, DataBits, __VA_ARGS__)
#define HID_RI_REPORT_COUNT(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x90, DataBits, __VA_ARGS__)
#define HID_RI_PUSH(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0xA0, DataBits, __VA_ARGS__)
#define HID_RI_POP(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0xB0, DataBits, __VA_ARGS__)
#define HID_RI_USAGE(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_LOCAL , 0x00, DataBits, __VA_ARGS__)
#define HID_RI_USAGE_MINIMUM(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_LOCAL , 0x10, DataBits, __VA_ARGS__)
#define HID_RI_USAGE_MAXIMUM(DataBits, ...) _HID_RI_ENTRY(HID_RI_TYPE_LOCAL , 0x20, DataBits, __VA_ARGS__)
//@}
/** @} */
#endif

103
Joystick.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "Joystick.h"
#include "HIDReportData.h"
/***
* All enum, class and descriptor definitions are originally written by progmem in library Switch-Fightstick(https://github.com/progmem/Switch-Fightstick).
* Original code can be found in:
* progmem/Switch-Fightstick/Joystick.h
* https://github.com/progmem/Switch-Fightstick/blob/master/Joystick.h
***/
// Functions added to HID_ class
// Don't forget to add definitions in HID.h, which is located at:
// <arduino installation path>\hardware\arduino\avr\libraries\HID\src\
void HID_::PrependDescriptor(HIDSubDescriptor *node)
{
node->next = rootNode;
rootNode = node;
descriptorSize += node->length;
}
int HID_::SendRaw(const void* data, int len)
{
return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len);
}
/***
* Descriptor modified from
* progmem/Switch-Fightstick/Joystick.c
* https://github.com/progmem/Switch-Fightstick/blob/master/Joystick.h
***/
static const uint8_t _hidReportDescriptor[] PROGMEM = {
HID_RI_USAGE_PAGE(8,1), /* Generic Desktop */
HID_RI_USAGE(8,5), /* Joystick */
HID_RI_COLLECTION(8,1), /* Application */
// Report ID
HID_RI_REPORT_ID(8,3),
// Buttons (2 bytes)
HID_RI_LOGICAL_MINIMUM(8,0),
HID_RI_LOGICAL_MAXIMUM(8,1),
HID_RI_PHYSICAL_MINIMUM(8,0),
HID_RI_PHYSICAL_MAXIMUM(8,1),
// The Switch will allow us to expand the original HORI descriptors to a full 16 buttons.
// The Switch will make use of 14 of those buttons.
HID_RI_REPORT_SIZE(8,1),
HID_RI_REPORT_COUNT(8,16),
HID_RI_USAGE_PAGE(8,9),
HID_RI_USAGE_MINIMUM(8,1),
HID_RI_USAGE_MAXIMUM(8,16),
HID_RI_INPUT(8,2),
// HAT Switch (1 nibble)
HID_RI_USAGE_PAGE(8,1),
HID_RI_LOGICAL_MAXIMUM(8,7),
HID_RI_PHYSICAL_MAXIMUM(16,315),
HID_RI_REPORT_SIZE(8,4),
HID_RI_REPORT_COUNT(8,1),
HID_RI_UNIT(8,20),
HID_RI_USAGE(8,57),
HID_RI_INPUT(8,66),
// There's an additional nibble here that's utilized as part of the Switch Pro Controller.
// I believe this -might- be separate U/D/L/R bits on the Switch Pro Controller, as they're utilized as four button descriptors on the Switch Pro Controller.
HID_RI_UNIT(8,0),
HID_RI_REPORT_COUNT(8,1),
HID_RI_INPUT(8,1),
// Joystick (4 bytes)
HID_RI_LOGICAL_MAXIMUM(16,255),
HID_RI_PHYSICAL_MAXIMUM(16,255),
HID_RI_USAGE(8,48),
HID_RI_USAGE(8,49),
HID_RI_USAGE(8,50),
HID_RI_USAGE(8,53),
HID_RI_REPORT_SIZE(8,8),
HID_RI_REPORT_COUNT(8,4),
HID_RI_INPUT(8,2),
// ??? Vendor Specific (1 byte)
// This byte requires additional investigation.
HID_RI_USAGE_PAGE(16,65280),
HID_RI_USAGE(8,32),
HID_RI_REPORT_COUNT(8,1),
HID_RI_INPUT(8,2),
// Output (8 bytes)
// Original observation of this suggests it to be a mirror of the inputs that we sent.
// The Switch requires us to have these descriptors available.
HID_RI_USAGE(16,9761),
HID_RI_REPORT_COUNT(8,8),
HID_RI_OUTPUT(8,2),
HID_RI_END_COLLECTION(0),
};
Joystick_::Joystick_()
{
static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
HID().PrependDescriptor(&node); // This descriptor need to be the first one so that the device can be recognized by Switch
}
void Joystick_::sendState()
{
HID().SendRaw(this, 8); // No sending report ID. Switch doesn't deal with that properly.
}
Joystick_ Joystick;

61
Joystick.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef JOYSTICK_h
#define JOYSTICK_h
#include <HID.h>
/***
* All enum, class and descriptor definitions are originally written by progmem in library Switch-Fightstick(https://github.com/progmem/Switch-Fightstick).
* Original code can be found in:
* progmem/Switch-Fightstick/Joystick.h
* https://github.com/progmem/Switch-Fightstick/blob/master/Joystick.h
***/
// Enumeration for joystick buttons.
typedef enum {
SWITCH_BTN_NONE = 0x00,
SWITCH_BTN_Y = 0x01,
SWITCH_BTN_B = 0x02,
SWITCH_BTN_A = 0x04,
SWITCH_BTN_X = 0x08,
SWITCH_BTN_L = 0x10,
SWITCH_BTN_R = 0x20,
SWITCH_BTN_ZL = 0x40,
SWITCH_BTN_ZR = 0x80,
SWITCH_BTN_SELECT = 0x100,
SWITCH_BTN_START = 0x200,
SWITCH_BTN_LCLICK = 0x400,
SWITCH_BTN_RCLICK = 0x800,
SWITCH_BTN_HOME = 0x1000,
SWITCH_BTN_CAPTURE = 0x2000,
} JoystickButtons_t;
// Enumeration for joystick hats.
typedef enum {
SWITCH_HAT_U = 0x00,
SWITCH_HAT_UR = 0x01,
SWITCH_HAT_R = 0x02,
SWITCH_HAT_DR = 0x03,
SWITCH_HAT_D = 0x04,
SWITCH_HAT_DL = 0x05,
SWITCH_HAT_L = 0x06,
SWITCH_HAT_UL = 0x07,
SWITCH_HAT_CENTER = 0x08,
} JoystickHats_t;
struct Joystick_
{
uint16_t Button = SWITCH_BTN_NONE; // 16 buttons; see JoystickButtons_t for bit mapping
uint8_t HAT = SWITCH_HAT_CENTER; // HAT switch; one nibble w/ unused nibble
uint8_t LX = 128; // Left Stick X
uint8_t LY = 128; // Left Stick Y
uint8_t RX = 128; // Right Stick X
uint8_t RY = 128; // Right Stick Y
uint8_t VendorSpec = 0;
Joystick_();
void sendState();
};
extern Joystick_ Joystick;
#endif

24
LUFA_LICENSE Normal file
View File

@ -0,0 +1,24 @@
LUFA Library
Copyright (C) Dean Camera, 2014.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose is hereby granted without
fee, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.

21
Switch_Fightstick_LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 @progmem
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.

View File

@ -1,17 +1,46 @@
#include <Keyboard.h>
//#define DEBUG_OUTPUT
//#define DEBUG_OUTPUT_LIVE
//#define ENABLE_KEYBOARD
const int min_threshold = 20;
const long cd_length = 8000;
const long cd_antireso_length = 8000;
const float k_antireso = 0.85;
const float k_decay = 0.96;
#define ENABLE_NS_JOYSTICK
const int pin[4] = {A3, A0, A2, A1};
const int key[4] = {'d', 'f', 'j', 'k'};
#ifdef ENABLE_KEYBOARD
#include <Keyboard.h>
#endif
const int key_next[4] = {1, 3, 0, 2};
#ifdef ENABLE_NS_JOYSTICK
#include "Joystick.h"
const int led_pin[4] = {8, 9, 10, 11};
const int sensor_button[4] = {SWITCH_BTN_ZL, SWITCH_BTN_LCLICK, SWITCH_BTN_RCLICK, SWITCH_BTN_ZR};
const int button[16] = {
0 /*SWITCH_HAT_U*/, 0 /*SWITCH_HAT_R*/, 0 /*SWITCH_HAT_D*/, 0 /*SWITCH_HAT_L*/,
SWITCH_BTN_X, SWITCH_BTN_A, SWITCH_BTN_B, SWITCH_BTN_Y,
SWITCH_BTN_L, SWITCH_BTN_R, SWITCH_BTN_SELECT, SWITCH_BTN_START,
SWITCH_BTN_CAPTURE, SWITCH_BTN_HOME, 0 /*Fn1*/, 0 /*Fn2*/
};
const int hat_mapping[16] = {
SWITCH_HAT_CENTER, SWITCH_HAT_U, SWITCH_HAT_R, SWITCH_HAT_UR,
SWITCH_HAT_D, SWITCH_HAT_CENTER, SWITCH_HAT_DR, SWITCH_HAT_R,
SWITCH_HAT_L, SWITCH_HAT_UL, SWITCH_HAT_CENTER, SWITCH_HAT_U,
SWITCH_HAT_DL, SWITCH_HAT_L, SWITCH_HAT_D, SWITCH_HAT_CENTER,
};
int button_state[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int button_cd[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#endif
const int min_threshold = 10;
const long cd_length = 16000;
const long cd_antireso_length = 16000;
const float k_threshold = 1.5;
const float k_antireso = 1.5;
const float k_decay = 0.983;
const int pin[4] = {A0, A3, A1, A2};
const int key[4] = {'d', '
f', 'j', 'k'};
const float sens[4] = {1.0, 1.0, 0.8, 0.8};
const int key_next[4] = {2, 0, 3, 1};
const long cd_stageselect = 200000;
@ -20,11 +49,16 @@ bool stageresult = false;
float threshold[4] = {20, 20, 20, 20};
int raw[4] = {0, 0, 0, 0};
int level[4] = {0, 0, 0, 0};
float level[4] = {0, 0, 0, 0};
long cd[4] = {0, 0, 0, 0};
bool down[4] = {false, false, false, false};
#ifdef ENABLE_NS_JOYSTICK
bool pressed[4] = {false, false, false, false};
int t0 = 0;
int dt = 0, sdt = 0;
#endif
typedef unsigned long time_t;
time_t t0 = 0;
time_t dt = 0, sdt = 0;
void sample() {
int prev[4] = {raw[0], raw[1], raw[2], raw[3]};
@ -33,20 +67,26 @@ void sample() {
raw[2] = analogRead(pin[2]);
raw[3] = analogRead(pin[3]);
for (int i=0; i<4; ++i)
level[i] = abs(raw[i] - prev[i]);
level[i] = abs(raw[i] - prev[i]) * sens[i];
}
void sampleSingle(int i) {
int prev = raw[i];
raw[i] = analogRead(pin[i]);
level[i] = abs(raw[i] - prev);
level[i] = abs(raw[i] - prev) * sens[i];
}
void setup() {
analogReference(DEFAULT); // use internal 1.1v as reference voltage
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
#ifdef ENABLE_NS_JOYSTICK
for (int i = 0; i < 8; ++i) pinMode(i, INPUT_PULLUP);
for (int i = 0; i < 4; ++i) { digitalWrite(led_pin[i], HIGH); pinMode(led_pin[i], OUTPUT); }
#endif
#ifdef ENABLE_KEYBOARD
Keyboard.begin();
#endif
t0 = micros();
Serial.begin(9600);
}
@ -78,32 +118,65 @@ void parseSerial() {
}
}
void loop_test() {
sampleSingle(0);
Serial.print(level[0]);
Serial.print("\t");
delayMicroseconds(500);
sampleSingle(1);
Serial.print(level[1]);
Serial.print("\t");
delayMicroseconds(500);
sampleSingle(2);
Serial.print(level[2]);
Serial.print("\t");
delayMicroseconds(500);
sampleSingle(3);
Serial.print(level[3]);
Serial.println();
delayMicroseconds(500);
}
void loop_test2() {
Serial.print(analogRead(pin[0]));
Serial.print("\t");
delayMicroseconds(500);
Serial.print(analogRead(pin[1]));
Serial.print("\t");
delayMicroseconds(500);
Serial.print(analogRead(pin[2]));
Serial.print("\t");
delayMicroseconds(500);
Serial.print(analogRead(pin[3]));
Serial.println();
delayMicroseconds(500);
}
void loop() {
//loop_test2(); return;
static int si = 0;
parseSerial();
int t1 = micros();
time_t t1 = micros();
dt = t1 - t0;
sdt += dt;
t0 = t1;
while (sdt >= 1000) {
sdt -= 1000;
for (int i = 0; i != 4; ++i)
threshold[i] *= k_decay;
}
for (int i = 0; i != 4; ++i)
threshold[i] *= k_decay;
for (int i = 0; i != 4; ++i) {
if (cd[i] > 0) {
cd[i] -= dt;
if (cd[i] <= 0) {
cd[i] = 0;
if (pressed[i]) {
#ifndef DEBUG_OUTPUT
if (down[i]) {
#ifdef ENABLE_KEYBOARD
Keyboard.release(stageresult ? KEY_ESC : key[i]);
#endif
pressed[i] = false;
down[i] = false;
}
}
}
@ -121,15 +194,18 @@ void loop() {
if (i_max == si && level_max >= min_threshold) {
if (cd[i_max] == 0) {
if (!pressed[i_max]) {
#ifndef DEBUG_OUTPUT
if (!down[i_max]) {
#ifdef ENABLE_KEYBOARD
if (stageresult) {
Keyboard.press(KEY_ESC);
} else {
Keyboard.press(key[i_max]);
}
#endif
down[i_max] = true;
#ifdef ENABLE_NS_JOYSTICK
pressed[i_max] = true;
#endif
}
for (int i = 0; i != 4; ++i)
cd[i] = cd_antireso_length;
@ -138,44 +214,102 @@ void loop() {
float level_antireso = level_max * k_antireso;
for (int i = 0; i != 4; ++i)
threshold[i] = max(threshold[i], level_antireso);
threshold[i_max] = (cd[i_max] == 0 ? level_max : level_max * 1.5);
threshold[i_max] = level_max * k_threshold;
sdt = 0;
}
#ifdef ENABLE_NS_JOYSTICK
// 4x4 button scan, one row per cycle
static int bi = 3;
pinMode(bi+4, INPUT_PULLUP);
bi = ((bi+1)&3);
pinMode(bi+4, OUTPUT);
digitalWrite(bi+4, LOW);
static time_t ct = 0;
static int cc = 0;
ct += dt;
cc += 1;
int state;
int* bs = button_state + (bi << 2);
int* bc = button_cd + (bi << 2);
for (int i = 0; i < 4; ++i) {
state = (digitalRead(i) == LOW);
//digitalWrite(led_pin[i], state ? LOW : HIGH);
if (bc[i] != 0) {
bc[i] -= ct;
if (bc[i] < 0) bc[i] = 0;
}
if (state != bs[i] && bc[i] == 0) {
bs[i] = state;
bc[i] = 15000;
}
Joystick.Button |= (bs[i] ? button[(bi << 2) + i] : SWITCH_BTN_NONE);
}
if (ct > 32000 || (ct > 8000 && (pressed[0] || pressed[1] || pressed[2] || pressed[3]))) {
for (int i = 0; i < 4; ++i) { // Sensors
Joystick.Button |= (pressed[i] ? sensor_button[i] : SWITCH_BTN_NONE);
digitalWrite(led_pin[i], pressed[i] ? LOW : HIGH);
}
state = 0;
for (int i = 0; i < 4; ++i) { // Buttons for hats
state |= (button_state[i] ? 1 << i : 0);
}
Joystick.HAT = hat_mapping[state];
Joystick.sendState();
Joystick.Button = SWITCH_BTN_NONE;
memset(pressed, 0, sizeof(pressed));
//Serial.print(ct);
//Serial.print('\t');
Serial.println((float)ct/cc);
ct = 0;
cc = 0;
}
#endif
#ifdef DEBUG_OUTPUT
static bool printing = false;
if (si == 0) {
if (level[0]+level[1]+level[2]+level[3] >= min_threshold || cd[0] || cd[1] || cd[2] || cd[3]){
Serial.print(level[0]);
Serial.print("\t");
Serial.print(level[1]);
Serial.print("\t");
Serial.print(level[2]);
Serial.print("\t");
Serial.print(level[3]);
Serial.print("\t| ");
Serial.print(cd[0] == 0 ? " " : pressed[0] ? "# " : "* ");
Serial.print(cd[1] == 0 ? " " : pressed[1] ? "# " : "* ");
Serial.print(cd[2] == 0 ? " " : pressed[2] ? "# " : "* ");
Serial.print(cd[3] == 0 ? " " : pressed[3] ? "# " : "* ");
Serial.print("|\t");
Serial.print((int)threshold[0]);
Serial.print("\t");
Serial.print((int)threshold[1]);
Serial.print("\t");
Serial.print((int)threshold[2]);
Serial.print("\t");
Serial.print((int)threshold[3]);
Serial.println();
printing = true;
}else if(printing){
Serial.println("=============================================================================");
printing = false;
}
#ifdef DEBUG_OUTPUT_LIVE
if (true)
#else
if (threshold[0] > min_threshold || threshold[1] > min_threshold ||
threshold[2] > min_threshold || threshold[3] > min_threshold)
#endif
{
Serial.print(level[0], 1);
Serial.print("\t");
Serial.print(level[1], 1);
Serial.print("\t");
Serial.print(level[2], 1);
Serial.print("\t");
Serial.print(level[3], 1);
Serial.print("\t| ");
Serial.print(cd[0] == 0 ? " " : down[0] ? "# " : "* ");
Serial.print(cd[1] == 0 ? " " : down[1] ? "# " : "* ");
Serial.print(cd[2] == 0 ? " " : down[2] ? "# " : "* ");
Serial.print(cd[3] == 0 ? " " : down[3] ? "# " : "* ");
Serial.print("|\t");
Serial.print(threshold[0], 1);
Serial.print("\t");
Serial.print(threshold[1], 1);
Serial.print("\t");
Serial.print(threshold[2], 1);
Serial.print("\t");
Serial.print(threshold[3], 1);
Serial.println();
printing = true;
}else if(printing){
Serial.println("=============================================================================");
printing = false;
}
#endif
sampleSingle(si);
si = key_next[si];
long ddt = 300 - (micros() - t0);
if(ddt > 3) delayMicroseconds(ddt);
}