Created
April 8, 2022 11:32
-
-
Save nmwilk/4e5822870045452df20277294257e210 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <BleGamepad.h> // https://github.com/lemmingDev/ESP32-BLE-Gamepad | |
#include <Encoder.h> // Encoder - by Paul Stoffregen | |
BleGamepad bleGamepad("SimWheel"); | |
#define TIME unsigned int | |
#define ENCODER_PULSES_PER_STEP 2 | |
#define numOfRotaryButtons 10 // 5 rotaries x 2 (rotate left and right) | |
#define numOfhc165 3 | |
#define dataWidth numOfhc165 * 8 | |
#define pulseWidthUSec 5 | |
#define BytesValT unsigned int | |
byte previousButtonStates[dataWidth]; | |
byte currentButtonStates[dataWidth]; | |
byte previousRotaryStates[numOfRotaryButtons]; | |
byte currentRotaryStates[numOfRotaryButtons]; | |
BytesValT pinValues; | |
Encoder r1(13, 12); | |
Encoder r2(26, 4); | |
Encoder r3(16, 17); | |
Encoder r4(14, 27); | |
Encoder r5(33, 25); | |
int ploadPin165 = 15; | |
int cePin165 = 18; | |
int dataPin165 = 5; | |
int clockPin165 = 2; | |
bool firstConnected = true; | |
const float BattMin = 3.2; | |
const float BattMax = 4.28; | |
const float BattRange = BattMax - BattMin; | |
int readBatteryCounter = 0; | |
TIME lastUpdate = 0; | |
void setup() | |
{ | |
Serial.begin(9600); | |
bleGamepad.begin(numOfRotaryButtons + dataWidth); | |
bleGamepad.setAutoReport(false); | |
pinMode(ploadPin165, OUTPUT); | |
pinMode(cePin165, OUTPUT); | |
pinMode(clockPin165, OUTPUT); | |
pinMode(dataPin165, INPUT); | |
digitalWrite(clockPin165, LOW); | |
digitalWrite(ploadPin165, HIGH); | |
} | |
void loop() | |
{ | |
TIME ms = millis(); | |
bool bleGamepadConnected = bleGamepad.isConnected(); | |
if (bleGamepadConnected && firstConnected) { | |
Serial.println("set up setting battery level"); | |
firstConnected = false; | |
bleGamepad.setBatteryLevel(readBattery()); | |
Serial.println("set up complete"); | |
} | |
bool inputsChanged = processInput(bleGamepadConnected, ms); | |
if (bleGamepadConnected && inputsChanged) { | |
bleGamepad.sendReport(); | |
delay(20); | |
} | |
if (bleGamepadConnected && readBatteryCounter++ > 500) { | |
bleGamepad.setBatteryLevel(readBattery()); | |
readBatteryCounter = 0; | |
} | |
} | |
byte bitIsSet(BytesValT bytes, int bitNumber) { | |
return (bytes >> bitNumber) & 1; | |
} | |
bool processInput(bool gamePadConnected, TIME ms) { | |
pinValues = read165s(ms); | |
processRotary(&r1, 0, ENCODER_PULSES_PER_STEP); | |
processRotary(&r2, 2, ENCODER_PULSES_PER_STEP); | |
processRotary(&r3, 4, ENCODER_PULSES_PER_STEP); | |
processRotary(&r4, 6, ENCODER_PULSES_PER_STEP); | |
processRotary(&r5, 8, 4); | |
for (byte currentIndex = 0 ; currentIndex < dataWidth ; currentIndex++) | |
{ | |
currentButtonStates[currentIndex] = bitIsSet(pinValues, currentIndex); | |
if (!gamePadConnected) continue; | |
if (currentButtonStates[currentIndex] != previousButtonStates[currentIndex]) | |
{ | |
if (currentButtonStates[currentIndex] == HIGH) | |
{ | |
bleGamepad.press(numOfRotaryButtons + currentIndex + 1); | |
} | |
else | |
{ | |
bleGamepad.release(numOfRotaryButtons + currentIndex + 1); | |
} | |
} | |
} | |
if (gamePadConnected) { | |
bool buttonsChanged = currentButtonStates != previousButtonStates; | |
if (buttonsChanged) | |
{ | |
for (byte currentIndex = 0; currentIndex < dataWidth ; currentIndex++) | |
{ | |
previousButtonStates[currentIndex] = currentButtonStates[currentIndex]; | |
} | |
} | |
bool rotariesChanged = currentRotaryStates != previousRotaryStates; | |
for (byte currentIndex = 0 ; currentIndex < numOfRotaryButtons ; currentIndex++) | |
{ | |
if (currentRotaryStates[currentIndex] != previousRotaryStates[currentIndex]) | |
{ | |
if (currentRotaryStates[currentIndex] == HIGH) | |
{ | |
bleGamepad.press(currentIndex + 1); | |
} | |
else | |
{ | |
bleGamepad.release(currentIndex + 1); | |
} | |
} | |
} | |
for (byte currentIndex = 0 ; currentIndex < numOfRotaryButtons ; currentIndex++) { | |
previousRotaryStates[currentIndex] = currentRotaryStates[currentIndex]; | |
} | |
return rotariesChanged || buttonsChanged; | |
} else { | |
return false; | |
} | |
} | |
int readBattery() { | |
float voltage = readBatteryPin() / 4096.0 * 7.445; | |
int percentage = min(max(0, (int)round(((voltage - BattMin) / BattRange) * 100)), 100); | |
return percentage; | |
} | |
float readBatteryPin() { | |
return analogRead(35); | |
} | |
void processRotary(Encoder* encoder, int offset, int pulsesPerStep) { | |
long rVal = encoder->read(); | |
if (abs(rVal) >= pulsesPerStep) { | |
if (rVal > 0) { | |
currentRotaryStates[offset + 1] = HIGH; | |
currentRotaryStates[offset] = LOW; | |
} else { | |
currentRotaryStates[offset + 1] = LOW; | |
currentRotaryStates[offset] = HIGH; | |
} | |
encoder->write(0); | |
} else { | |
currentRotaryStates[offset] = LOW; | |
currentRotaryStates[offset + 1] = LOW; | |
} | |
} | |
BytesValT read165s(TIME ms) | |
{ | |
long bitVal; | |
BytesValT bytesVal = 0; | |
/* Trigger a parallel Load to latch the state of the data lines, | |
*/ | |
digitalWrite(cePin165, HIGH); | |
digitalWrite(ploadPin165, LOW); | |
delayMicroseconds(pulseWidthUSec); | |
digitalWrite(ploadPin165, HIGH); | |
digitalWrite(cePin165, LOW); | |
/* Loop to read each bit value from the serial out line | |
of the SN74HC165N. | |
*/ | |
for (int i = 0; i < dataWidth; i++) | |
{ | |
bitVal = digitalRead(dataPin165); | |
/* Set the corresponding bit in bytesVal. | |
*/ | |
bytesVal |= (bitVal << ((dataWidth - 1) - i)); | |
/* Pulse the Clock (rising edge shifts the next bit). | |
*/ | |
digitalWrite(clockPin165, HIGH); | |
delayMicroseconds(pulseWidthUSec); | |
digitalWrite(clockPin165, LOW); | |
} | |
if (ms - lastUpdate > 1000) { | |
lastUpdate = ms; | |
Serial.println(bytesVal, BIN); | |
} | |
return (bytesVal); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment