Skip to content

Commit

Permalink
Merge pull request #17 from dmadison/unused-pin
Browse files Browse the repository at this point in the history
Unused pin rework
  • Loading branch information
dmadison authored Jun 6, 2024
2 parents 053c24c + 1da6619 commit 41403d1
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 56 deletions.
71 changes: 45 additions & 26 deletions src/SimRacing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@

namespace SimRacing {

/**
* Take a pin number as an input and sanitize it to a known working value
*
* In an ideal world this would check against the available pins on the micro,
* but as far as I know the Arduino API does not have a "valid pin" function.
* Instead, we'll just accept any positive number as a pin and reject any
* negative number as invalid ("Unused").
*
* @param pin the pin number to sanitize
* @returns the pin number, or UnusedPin
*/
static constexpr PinNum sanitizePin(PinNum pin) {
return pin < 0 ? UnusedPin : pin;
}


/**
* Invert an input value so it's at the same relative position
Expand Down Expand Up @@ -161,9 +176,9 @@ static void readFloat(float& value, Stream& client) {
// DeviceConnection #
//#########################################################

DeviceConnection::DeviceConnection(uint8_t pin, bool invert, unsigned long detectTime)
DeviceConnection::DeviceConnection(PinNum pin, bool invert, unsigned long detectTime)
:
Pin(pin), Inverted(invert), stablePeriod(detectTime), // constants(ish)
pin(sanitizePin(pin)), inverted(invert), stablePeriod(detectTime), // constants(ish)

/* Assume we're connected on first call
*/
Expand All @@ -177,7 +192,7 @@ DeviceConnection::DeviceConnection(uint8_t pin, bool invert, unsigned long detec
* the device to be read as connected as soon as the board turns on, without
* having to wait an arbitrary amount.
*/
pinState(!Inverted),
pinState(!inverted),

/* Set the last pin change to right now minus the stable period so it's
* read as being already stable. Again, this will make the class return
Expand All @@ -186,7 +201,9 @@ DeviceConnection::DeviceConnection(uint8_t pin, bool invert, unsigned long detec
lastChange(millis() - detectTime)

{
pinMode(Pin, INPUT); // set pin as input, *no* pull-up
if (pin != UnusedPin) {
pinMode(pin, INPUT); // set pin as input, *no* pull-up
}
}

void DeviceConnection::poll() {
Expand Down Expand Up @@ -248,30 +265,30 @@ void DeviceConnection::setStablePeriod(unsigned long t) {
}

bool DeviceConnection::readPin() const {
if (Pin == NOT_A_PIN) return HIGH; // if no pin is set, we're always connected
const bool state = digitalRead(Pin);
return Inverted ? !state : state;
if (pin == UnusedPin) return HIGH; // if no pin is set, we're always connected
const bool state = digitalRead(pin);
return inverted ? !state : state;
}

//#########################################################
// AnalogInput #
//#########################################################


AnalogInput::AnalogInput(uint8_t p)
: Pin(p), position(AnalogInput::Min), cal({AnalogInput::Min, AnalogInput::Max})
AnalogInput::AnalogInput(PinNum pin)
: pin(sanitizePin(pin)), position(AnalogInput::Min), cal({AnalogInput::Min, AnalogInput::Max})
{
if (Pin != NOT_A_PIN) {
pinMode(Pin, INPUT);
if (pin != UnusedPin) {
pinMode(pin, INPUT);
}
}

bool AnalogInput::read() {
bool changed = false;

if (Pin != NOT_A_PIN) {
if (pin != UnusedPin) {
const int previous = this->position;
this->position = analogRead(Pin);
this->position = analogRead(pin);

// check if value is different for 'changed' flag
if (previous != this->position) {
Expand Down Expand Up @@ -333,7 +350,7 @@ void AnalogInput::setCalibration(AnalogInput::Calibration newCal) {
// Pedals #
//#########################################################

Pedals::Pedals(AnalogInput* dataPtr, uint8_t nPedals, uint8_t detectPin)
Pedals::Pedals(AnalogInput* dataPtr, uint8_t nPedals, PinNum detectPin)
:
pedalData(dataPtr),
NumPedals(nPedals),
Expand Down Expand Up @@ -538,7 +555,7 @@ void Pedals::serialCalibration(Stream& iface) {
}


TwoPedals::TwoPedals(uint8_t gasPin, uint8_t brakePin, uint8_t detectPin)
TwoPedals::TwoPedals(PinNum gasPin, PinNum brakePin, PinNum detectPin)
: Pedals(pedalData, NumPedals, detectPin),
pedalData{ AnalogInput(gasPin), AnalogInput(brakePin) }
{}
Expand All @@ -549,7 +566,7 @@ void TwoPedals::setCalibration(AnalogInput::Calibration gasCal, AnalogInput::Cal
}


ThreePedals::ThreePedals(uint8_t gasPin, uint8_t brakePin, uint8_t clutchPin, uint8_t detectPin)
ThreePedals::ThreePedals(PinNum gasPin, PinNum brakePin, PinNum clutchPin, PinNum detectPin)
: Pedals(pedalData, NumPedals, detectPin),
pedalData{ AnalogInput(gasPin), AnalogInput(brakePin), AnalogInput(clutchPin) }
{}
Expand All @@ -562,7 +579,7 @@ void ThreePedals::setCalibration(AnalogInput::Calibration gasCal, AnalogInput::C



LogitechPedals::LogitechPedals(uint8_t gasPin, uint8_t brakePin, uint8_t clutchPin, uint8_t detectPin)
LogitechPedals::LogitechPedals(PinNum gasPin, PinNum brakePin, PinNum clutchPin, PinNum detectPin)
: ThreePedals(gasPin, brakePin, clutchPin, detectPin)
{
// taken from calibrating my own pedals. the springs are pretty stiff so while
Expand All @@ -571,7 +588,7 @@ LogitechPedals::LogitechPedals(uint8_t gasPin, uint8_t brakePin, uint8_t clutchP
this->setCalibration({ 904, 48 }, { 944, 286 }, { 881, 59 });
}

LogitechDrivingForceGT_Pedals::LogitechDrivingForceGT_Pedals(uint8_t gasPin, uint8_t brakePin, uint8_t detectPin)
LogitechDrivingForceGT_Pedals::LogitechDrivingForceGT_Pedals(PinNum gasPin, PinNum brakePin, PinNum detectPin)
: TwoPedals(gasPin, brakePin, detectPin)
{
this->setCalibration({ 646, 0 }, { 473, 1023 }); // taken from calibrating my own pedals
Expand Down Expand Up @@ -657,22 +674,24 @@ const float AnalogShifter::CalEngagementPoint = 0.70;
const float AnalogShifter::CalReleasePoint = 0.50;
const float AnalogShifter::CalEdgeOffset = 0.60;

AnalogShifter::AnalogShifter(uint8_t pinX, uint8_t pinY, uint8_t pinRev, uint8_t detectPin)
AnalogShifter::AnalogShifter(PinNum pinX, PinNum pinY, PinNum pinRev, PinNum detectPin)
:
/* In initializing the Shifter, the lowest gear is going to be '-1' if a pin
* exists for reverse, otherwise it's going to be '0' (neutral).
*/
Shifter(pinRev != NOT_A_PIN ? -1 : 0, 6),
Shifter(sanitizePin(pinRev) != UnusedPin ? -1 : 0, 6),

/* Two axes, X and Y */
analogAxis{ AnalogInput(pinX), AnalogInput(pinY) },

PinReverse(pinRev),
pinReverse(sanitizePin(pinRev)),
detector(detectPin, false) // not inverted
{}

void AnalogShifter::begin() {
pinMode(PinReverse, INPUT);
if (this->pinReverse != UnusedPin) {
pinMode(pinReverse, INPUT);
}
update(); // set initial gear position
}

Expand Down Expand Up @@ -777,10 +796,10 @@ int AnalogShifter::getPositionRaw(Axis ax) const {
bool AnalogShifter::getReverseButton() const {
// if the reverse pin is not set *or* if the device is not currently
// connected, avoid reading the floating input and just return 'false'
if (PinReverse == NOT_A_PIN || detector.getState() != DeviceConnection::Connected) {
if (pinReverse == UnusedPin || detector.getState() != DeviceConnection::Connected) {
return false;
}
return digitalRead(PinReverse);
return digitalRead(pinReverse);
}

void AnalogShifter::setCalibration(
Expand Down Expand Up @@ -977,7 +996,7 @@ void AnalogShifter::serialCalibration(Stream& iface) {
iface.println(F("\n\nCalibration complete! :)\n"));
}

LogitechShifter::LogitechShifter(uint8_t pinX, uint8_t pinY, uint8_t pinRev, uint8_t detectPin)
LogitechShifter::LogitechShifter(PinNum pinX, PinNum pinY, PinNum pinRev, PinNum detectPin)
: AnalogShifter(pinX, pinY, pinRev, detectPin)
{
this->setCalibration({ 490, 440 }, { 253, 799 }, { 262, 86 }, { 460, 826 }, { 470, 76 }, { 664, 841 }, { 677, 77 });
Expand All @@ -987,7 +1006,7 @@ LogitechShifter::LogitechShifter(uint8_t pinX, uint8_t pinY, uint8_t pinRev, uin
// Handbrake #
//#########################################################

Handbrake::Handbrake(uint8_t pinAx, uint8_t detectPin)
Handbrake::Handbrake(PinNum pinAx, PinNum detectPin)
:
analogAxis(pinAx),
detector(detectPin),
Expand Down
72 changes: 42 additions & 30 deletions src/SimRacing.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
*/

namespace SimRacing {
/**
* Type alias for pin numbers, using Arduino numbering
*/
using PinNum = int16_t;

/**
* Dummy pin number signaling that a pin is unused
* and can be safely ignored
*/
const PinNum UnusedPin = -1;


/**
* Enumeration for analog axis names, mapped to integers
*/
Expand Down Expand Up @@ -63,12 +75,12 @@ namespace SimRacing {
/**
* Class constructor
*
* @param pin the pin number being read. Can be 'NOT_A_PIN' to disable.
* @param pin the pin number being read. Can be 'UnusedPin' to disable.
* @param invert whether the input is inverted, so 'LOW' is detected instead of 'HIGH'
* @param detectTime the amount of time, in ms, the input must be stable for
* before it's interpreted as 'detected'
*/
DeviceConnection(uint8_t pin, bool invert = false, unsigned long detectTime = 250);
DeviceConnection(PinNum pin, bool invert = false, unsigned long detectTime = 250);

/**
* Checks if the pin detects a connection. This polls the input and checks
Expand Down Expand Up @@ -108,13 +120,13 @@ namespace SimRacing {
*/
bool readPin() const;

const uint8_t Pin; ///< The pin number being read from. Can be 'NOT_A_PIN' to disable
const bool Inverted; ///< Whether the input is inverted, so 'LOW' is detected instead of 'HIGH'
PinNum pin; ///< The pin number being read from. Can be 'UnusedPin' to disable
bool inverted; ///< Whether the input is inverted, so 'LOW' is detected instead of 'HIGH'
unsigned long stablePeriod; ///< The amount of time the input must be stable for (ms)

ConnectionState state; ///< The current state of the connection
bool pinState; ///< Buffered state of the input pin, accounting for inversion
unsigned long lastChange; ///< Timestamp of the last pin change, in ms (using millis())
ConnectionState state; ///< The current state of the connection
bool pinState; ///< Buffered state of the input pin, accounting for inversion
unsigned long lastChange; ///< Timestamp of the last pin change, in ms (using millis())
};


Expand All @@ -129,9 +141,9 @@ namespace SimRacing {
/**
* Class constructor
*
* @param p the I/O pin for this input (Arduino numbering)
* @param pin the I/O pin for this input (Arduino numbering)
*/
AnalogInput(uint8_t p);
AnalogInput(PinNum pin);

/**
* Updates the current value of the axis by polling the ADC
Expand Down Expand Up @@ -225,9 +237,9 @@ namespace SimRacing {
void setCalibration(Calibration newCal);

private:
const uint8_t Pin = NOT_A_PIN; ///< the digital pin number for this input
int position; ///< the axis' position in its range, buffered
Calibration cal; ///< the calibration values for the axis
PinNum pin; ///< the digital pin number for this input
int position; ///< the axis' position in its range, buffered
Calibration cal; ///< the calibration values for the axis
};


Expand Down Expand Up @@ -285,7 +297,7 @@ namespace SimRacing {
* @param nPedals the number of pedals stored in said data pointer
* @param detectPin the digital pin for device detection (high is detected)
*/
Pedals(AnalogInput* dataPtr, uint8_t nPedals, uint8_t detectPin);
Pedals(AnalogInput* dataPtr, uint8_t nPedals, PinNum detectPin);

/** @copydoc Peripheral::begin() */
virtual void begin();
Expand Down Expand Up @@ -381,11 +393,11 @@ namespace SimRacing {
/**
* Class constructor
*
* @param gasPin the analog pin for the gas pedal potentiometer
* @param brakePin the analog pin for the brake pedal potentiometer
* @param detectPin the digital pin for device detection (high is detected)
* @param pinGas the analog pin for the gas pedal potentiometer
* @param pinBrake the analog pin for the brake pedal potentiometer
* @param pinDetect the digital pin for device detection (high is detected)
*/
TwoPedals(uint8_t gasPin, uint8_t brakePin, uint8_t detectPin = NOT_A_PIN);
TwoPedals(PinNum pinGas, PinNum pinBrake, PinNum pinDetect = UnusedPin);

/**
* Sets the calibration data (min/max) for the pedals
Expand All @@ -409,12 +421,12 @@ namespace SimRacing {
/**
* Class constructor
*
* @param gasPin the analog pin for the gas pedal potentiometer
* @param brakePin the analog pin for the brake pedal potentiometer
* @param clutchPin the analog pin for the clutch pedal potentiometer
* @param detectPin the digital pin for device detection (high is detected)
* @param pinGas the analog pin for the gas pedal potentiometer
* @param pinBrake the analog pin for the brake pedal potentiometer
* @param pinClutch the analog pin for the clutch pedal potentiometer
* @param pinDetect the digital pin for device detection (high is detected)
*/
ThreePedals(uint8_t gasPin, uint8_t brakePin, uint8_t clutchPin, uint8_t detectPin = NOT_A_PIN);
ThreePedals(PinNum pinGas, PinNum pinBrake, PinNum pinClutch, PinNum pinDetect = UnusedPin);

/**
* Sets the calibration data (min/max) for the pedals
Expand Down Expand Up @@ -540,9 +552,9 @@ namespace SimRacing {
* @param pinX the analog input pin for the X axis
* @param pinY the analog input pin for the Y axis
* @param pinRev the digital input pin for the 'reverse' button
* @param detectPin the digital pin for device detection (high is detected)
* @param pinDetect the digital pin for device detection (high is detected)
*/
AnalogShifter(uint8_t pinX, uint8_t pinY, uint8_t pinRev = NOT_A_PIN, uint8_t detectPin = NOT_A_PIN);
AnalogShifter(PinNum pinX, PinNum pinY, PinNum pinRev = UnusedPin, PinNum pinDetect = UnusedPin);

/**
* Initializes the hardware pins for reading the gear states.
Expand Down Expand Up @@ -663,7 +675,7 @@ namespace SimRacing {
} calibration;

AnalogInput analogAxis[2]; ///< Axis data for X and Y
const uint8_t PinReverse; ///< The pin for the reverse gear button
PinNum pinReverse; ///< The pin for the reverse gear button
DeviceConnection detector; ///< detector instance for checking if the shifter is connected
};

Expand All @@ -679,9 +691,9 @@ namespace SimRacing {
* Class constructor
*
* @param pinAx analog pin number for the handbrake axis
* @param detectPin the digital pin for device detection (high is detected)
* @param pinDetect the digital pin for device detection (high is detected)
*/
Handbrake(uint8_t pinAx, uint8_t detectPin = NOT_A_PIN);
Handbrake(PinNum pinAx, PinNum pinDetect = UnusedPin);

/**
* Initializes the pin for reading from the handbrake.
Expand Down Expand Up @@ -748,7 +760,7 @@ namespace SimRacing {
class LogitechPedals : public ThreePedals {
public:
/** @copydoc ThreePedals::ThreePedals */
LogitechPedals(uint8_t gasPin, uint8_t brakePin, uint8_t clutchPin, uint8_t detectPin = NOT_A_PIN);
LogitechPedals(PinNum pinGas, PinNum pinBrake, PinNum pinClutch, PinNum pinDetect = UnusedPin);
};

/**
Expand All @@ -763,7 +775,7 @@ namespace SimRacing {
class LogitechDrivingForceGT_Pedals : public TwoPedals {
public:
/** @copydoc TwoPedals::TwoPedals */
LogitechDrivingForceGT_Pedals(uint8_t gasPin, uint8_t brakePin, uint8_t detectPin = NOT_A_PIN);
LogitechDrivingForceGT_Pedals(PinNum pinGas, PinNum pinBrake, PinNum pinDetect = UnusedPin);
};

/**
Expand All @@ -775,7 +787,7 @@ namespace SimRacing {
class LogitechShifter : public AnalogShifter {
public:
/** @copydoc AnalogShifter::AnalogShifter */
LogitechShifter(uint8_t pinX, uint8_t pinY, uint8_t pinRev = NOT_A_PIN, uint8_t detectPin = NOT_A_PIN);
LogitechShifter(PinNum pinX, PinNum pinY, PinNum pinRev = UnusedPin, PinNum pinDetect = UnusedPin);
};


Expand Down

0 comments on commit 41403d1

Please sign in to comment.