formatting and bug fixes

This commit is contained in:
tyler miller 2025-01-13 13:52:57 -05:00
parent 5a8a1500eb
commit d5777031e4
6 changed files with 436 additions and 414 deletions

10
.clang-format Normal file
View file

@ -0,0 +1,10 @@
BasedOnStyle: Chromium
IndentWidth: 4
Language: Cpp
ColumnLimit: 100
UseTab: Never
BreakBeforeBraces: Custom
FixNamespaceComments: true
ShortNamespaceLines: 0
BraceWrapping:
BeforeElse: true

View file

@ -10,13 +10,13 @@
@details @details
AlignedJoy is a class written in C++ for Arduino to interface classic analog joysticks. AlignedJoy is a class written in C++ for Arduino to interface classic analog joysticks.
Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of this class? Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of
Through the methods of the class you can calibrate one or more joysticks, read and memorize the calibration points. this class? Through the methods of the class you can calibrate one or more joysticks, read and
For dynamic applications, calibrated points can be stored in eeprom. Or once the calibration points are obtained, memorize the calibration points. For dynamic applications, calibrated points can be stored in
they can be set in constant mode. See description of methods. eeprom. Or once the calibration points are obtained, they can be set in constant mode. See
The strength of the class is that having the calibration parameters is able to align the values of the axes description of methods. The strength of the class is that having the calibration parameters is able
of the respective joysticks. Its very useful when you want to manage something with a certain precision and to align the values of the axes of the respective joysticks. Its very useful when you want to
when you have a joystick with misaligned axis values. manage something with a certain precision and when you have a joystick with misaligned axis values.
# LICENSE # # LICENSE #
@ -45,232 +45,203 @@
#include "AlignedJoy.h" #include "AlignedJoy.h"
AlignedJoy::AlignedJoy(uint8_t xPin, uint8_t yPin) AlignedJoy::AlignedJoy(uint8_t xPin, uint8_t yPin) {
{ this->xPin = xPin;
this->xPin = xPin; this->yPin = yPin;
this->yPin = yPin; this->joystickCentered = false;
this->joystickCentered = false; this->joystickFullCalibrated = false;
this->joystickFullCalibrated = false;
pinMode(this->xPin,INPUT); pinMode(this->xPin, INPUT);
pinMode(this->yPin,INPUT); pinMode(this->yPin, INPUT);
}; };
void AlignedJoy::axesAlign(void) void AlignedJoy::axesAlign(void) {
{ // Imposed the smallest value between the two calibrated minima.
// Imposed the smallest value between the two calibrated minima. this->alignMin = min(this->xAxisCalibMinimum, this->yAxisCalibMinimum);
this->alignMin = min(this->xAxisCalibMinimum, this->yAxisCalibMinimum); // Imposed the largest value between the two calibrated maxima.
// Imposed the largest value between the two calibrated maxima. this->alignMax = max(this->xAxisCalibMaximum, this->yAxisCalibMaximum);
this->alignMax = max(this->xAxisCalibMaximum, this->yAxisCalibMaximum);
} }
void AlignedJoy::middleCalibration(uint16_t timeOfCal) void AlignedJoy::middleCalibration(uint16_t timeOfCal) {
{
// New istance of the timer
calibrationTimer TIME_CAL_1;
// Repeat for the required time
while(TIME_CAL_1 < timeOfCal)
{
// Assigns the value to each loop.
this->xAxisCalibCenter = analogRead(this->xPin);
this->yAxisCalibCenter = analogRead(this->yPin);
}
// set flag true
this->joystickCentered = true;
}
bool AlignedJoy::axesCalibration(uint16_t timeOfCal)
{
if(joystickCentered)
{
// New values for comparison
static uint16_t last_X_min = this->xAxisCalibCenter;
static uint16_t last_X_max = this->xAxisCalibCenter;
static uint16_t last_Y_min = this->yAxisCalibCenter;
static uint16_t last_Y_max = this->yAxisCalibCenter;
// New istance of the timer // New istance of the timer
calibrationTimer TIME_CAL_2; calibrationTimer TIME_CAL_1;
// Repeat for the required time // Repeat for the required time
while(TIME_CAL_2 < timeOfCal) while (TIME_CAL_1 < timeOfCal) {
{ // Assigns the value to each loop.
// Read analog value this->xAxisCalibCenter = analogRead(this->xPin);
uint16_t x = analogRead(this->xPin); this->yAxisCalibCenter = analogRead(this->yPin);
uint16_t y = analogRead(this->yPin);
// Logic acquisition. Assigns the lowest or highest values to each loop.
if(x < this->xAxisCalibCenter && x < last_X_min)
{
last_X_min = this->xAxisCalibMinimum = x;
}
if(x > this->xAxisCalibCenter && x > last_X_max)
{
last_X_max = this->xAxisCalibMaximum = x;
}
if(y < this->yAxisCalibCenter && y < last_Y_min)
{
last_Y_min = this->yAxisCalibMinimum = y;
}
if(y > this->yAxisCalibCenter && y > last_Y_max)
{
last_Y_max = this->yAxisCalibMaximum = y;
}
} }
// set flag true
// verify that there is the minimum excursion between the minimum and the maximum of each axis. this->joystickCentered = true;
if((this->xAxisCalibMaximum - this->xAxisCalibMinimum) >= AXIS_TRAVEL &&
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL)
{
// set flag true
this->joystickFullCalibrated = true;
// align axes
axesAlign();
return true;
}
else
{
return false;
}
}
else
{
return false;
}
} }
void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointValue) bool AlignedJoy::axesCalibration(uint16_t timeOfCal) {
{ if (joystickCentered) {
switch(point) // New values for comparison
{ static uint16_t last_X_min = this->xAxisCalibCenter;
case MIN: static uint16_t last_X_max = this->xAxisCalibCenter;
switch(axis) static uint16_t last_Y_min = this->yAxisCalibCenter;
{ static uint16_t last_Y_max = this->yAxisCalibCenter;
case X:
this->xAxisCalibMinimum = pointValue;
break;
case Y:
this->yAxisCalibMinimum = pointValue;
break;
}
break;
case MID: // New istance of the timer
switch(axis) calibrationTimer TIME_CAL_2;
{
case X:
this->xAxisCalibCenter = pointValue;
break;
case Y:
this->yAxisCalibCenter = pointValue;
break;
}
break;
case MAX: // Repeat for the required time
switch(axis) while (TIME_CAL_2 < timeOfCal) {
{ // Read analog value
case X: uint16_t x = analogRead(this->xPin);
this->xAxisCalibMaximum = pointValue; uint16_t y = analogRead(this->yPin);
break;
case Y: // Logic acquisition. Assigns the lowest or highest values to each loop.
this->yAxisCalibMaximum = pointValue; if (x < this->xAxisCalibCenter && x < last_X_min) {
break; last_X_min = this->xAxisCalibMinimum = x;
}
if (x > this->xAxisCalibCenter && x > last_X_max) {
last_X_max = this->xAxisCalibMaximum = x;
}
if (y < this->yAxisCalibCenter && y < last_Y_min) {
last_Y_min = this->yAxisCalibMinimum = y;
}
if (y > this->yAxisCalibCenter && y > last_Y_max) {
last_Y_max = this->yAxisCalibMaximum = y;
}
}
// verify that there is the minimum excursion between the minimum and the maximum of each
// axis.
if ((this->xAxisCalibMaximum - this->xAxisCalibMinimum) >= AXIS_TRAVEL &&
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL) {
// set flag true
this->joystickFullCalibrated = true;
// align axes
axesAlign();
return true;
}
else {
return false;
} }
break;
} }
// verify that there is the minimum excursion between the minimum and the maximum of each axis. else {
if((this->xAxisCalibMaximum - this->xAxisCalibMinimum) >= AXIS_TRAVEL && return false;
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL) }
{ }
void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointValue) {
switch (point) {
case MIN:
switch (axis) {
case X:
this->xAxisCalibMinimum = pointValue;
break;
case Y:
this->yAxisCalibMinimum = pointValue;
break;
}
break;
case MID:
switch (axis) {
case X:
this->xAxisCalibCenter = pointValue;
break;
case Y:
this->yAxisCalibCenter = pointValue;
break;
}
break;
case MAX:
switch (axis) {
case X:
this->xAxisCalibMaximum = pointValue;
break;
case Y:
this->yAxisCalibMaximum = pointValue;
break;
}
break;
}
// verify that there is the minimum excursion between the minimum and the maximum of each axis.
if ((this->xAxisCalibMaximum - this->xAxisCalibMinimum) >= AXIS_TRAVEL &&
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL) {
// set flag true // set flag true
this->joystickFullCalibrated = true; this->joystickFullCalibrated = true;
// align axes // align axes
axesAlign(); axesAlign();
}
}
uint16_t AlignedJoy::getCalibratedPoint(axis_t axis, point_t point)
{
uint16_t pointValue;
switch(point)
{
case MIN:
switch(axis)
{
case X:
pointValue = this->xAxisCalibMinimum;
break;
case Y:
pointValue = this->yAxisCalibMinimum;
break;
}
break;
case MID:
switch(axis)
{
case X:
pointValue = this->xAxisCalibCenter;
break;
case Y:
pointValue = this->yAxisCalibCenter;
break;
}
break;
case MAX:
switch(axis)
{
case X:
pointValue = this->xAxisCalibMaximum;
break;
case Y:
pointValue = this->yAxisCalibMaximum;
break;
}
break;
} }
return pointValue;
} }
uint16_t AlignedJoy::read(axis_t axis) uint16_t AlignedJoy::getCalibratedPoint(axis_t axis, point_t point) {
{ uint16_t pointValue;
uint16_t axisValue;
switch(axis) switch (point) {
{ case MIN:
case X: switch (axis) {
if(joystickFullCalibrated) case X:
{ pointValue = this->xAxisCalibMinimum;
axisValue = map(analogRead(this->xPin), this->xAxisCalibMinimum, this->xAxisCalibMaximum, this->alignMin, this->alignMax); break;
} case Y:
else pointValue = this->yAxisCalibMinimum;
{ break;
axisValue = analogRead(this->xPin); }
} break;
break;
case Y: case MID:
if(joystickFullCalibrated) switch (axis) {
{ case X:
axisValue = map(analogRead(this->yPin), this->yAxisCalibMinimum, this->yAxisCalibMaximum, this->alignMin, this->alignMax); pointValue = this->xAxisCalibCenter;
} break;
else case Y:
{ pointValue = this->yAxisCalibCenter;
axisValue = analogRead(this->yPin); break;
} }
break; break;
case MAX:
switch (axis) {
case X:
pointValue = this->xAxisCalibMaximum;
break;
case Y:
pointValue = this->yAxisCalibMaximum;
break;
}
break;
} }
return axisValue; return pointValue;
} }
uint16_t AlignedJoy::read(axis_t axis, int32_t out_min, int32_t out_max) uint16_t AlignedJoy::read(axis_t axis) {
{ uint16_t axisValue;
return map(read(axis), this->alignMin, this->alignMax, out_min, out_max);
switch (axis) {
case X:
if (joystickFullCalibrated) {
axisValue = map(analogRead(this->xPin), this->xAxisCalibMinimum,
this->xAxisCalibMaximum, this->alignMin, this->alignMax);
}
else {
axisValue = analogRead(this->xPin);
}
break;
case Y:
if (joystickFullCalibrated) {
axisValue = map(analogRead(this->yPin), this->yAxisCalibMinimum,
this->yAxisCalibMaximum, this->alignMin, this->alignMax);
}
else {
axisValue = analogRead(this->yPin);
}
break;
}
return axisValue;
}
uint16_t AlignedJoy::read(axis_t axis, int32_t out_min, int32_t out_max) {
return map(read(axis), this->alignMin, this->alignMax, out_min, out_max);
} }

View file

@ -10,13 +10,13 @@
@details @details
AlignedJoy is a class written in C++ for Arduino to interface classic analog joysticks. AlignedJoy is a class written in C++ for Arduino to interface classic analog joysticks.
Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of this class? Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of
Through the methods of the class you can calibrate one or more joysticks, read and memorize the calibration points. this class? Through the methods of the class you can calibrate one or more joysticks, read and
For dynamic applications, calibrated points can be stored in eeprom. Or once the calibration points are obtained, memorize the calibration points. For dynamic applications, calibrated points can be stored in
they can be set in constant mode. See description of methods. eeprom. Or once the calibration points are obtained, they can be set in constant mode. See
The strength of the class is that having the calibration parameters is able to align the values of the axes description of methods. The strength of the class is that having the calibration parameters is able
of the respective joysticks. Its very useful when you want to manage something with a certain precision and to align the values of the axes of the respective joysticks. Its very useful when you want to
when you have a joystick with misaligned axis values. manage something with a certain precision and when you have a joystick with misaligned axis values.
# LICENSE # # LICENSE #
@ -61,127 +61,131 @@ AXIS_TRAVEL CONSTANT
#define AXIS_TRAVEL 550 #define AXIS_TRAVEL 550
/// @brief axes flags /// @brief axes flags
typedef enum axis:uint8_t {X=0, Y} axis_t; typedef enum axis : uint8_t { X = 0, Y } axis_t;
/// @brief calibration point flags /// @brief calibration point flags
typedef enum point:uint8_t{ typedef enum point : uint8_t {
/// minimum point /// minimum point
MIN=0, MIN = 0,
/// middle point /// middle point
MID, MID,
/// maximum point /// maximum point
MAX MAX
} point_t; } point_t;
class AlignedJoy class AlignedJoy {
{ public:
public: /**
@brief Class onstructor. Create a new object of the joystick and set the axes (X/Y) pin to input
mode
@param xPin (x analog port pin of the device)
@param yPin (y analog port pin of the device)
*/
AlignedJoy(uint8_t xPin, uint8_t yPin);
/// Class destructor
~AlignedJoy() {};
/** /**
@brief Class onstructor. Create a new object of the joystick and set the axes (X/Y) pin to input mode @brief Start calibration of the joystick in center position.
@param xPin (x analog port pin of the device) @details
@param yPin (y analog port pin of the device) Use this method only if the calibration of the axles is desired.
*/ Calibration is divided into two steps to allow defining the desired functionality
AlignedJoy(uint8_t xPin, uint8_t yPin); (messages, delays, etc.) between the two phases.
/// Class destructor @param timeOfCal is the calibration time in milliseconds.
~AlignedJoy(){}; @return true o false.
*/
void middleCalibration(uint16_t timeOfCal);
/** /**
@brief Start calibration of the joystick in center position. @brief Calibration of the axes at the extreme points (min end max for each axis).
@details @details
Use this method only if the calibration of the axles is desired. It is recommended to rotate the joystick in a circular way along its perimeter (maximum radius
Calibration is divided into two steps to allow defining the desired functionality for each axis) throughout the calibration time.
(messages, delays, etc.) between the two phases. @param timeOfCal is the calibration time in milliseconds.
@param timeOfCal is the calibration time in milliseconds. @return true o false.
@return true o false. */
*/ bool axesCalibration(uint16_t timeOfCal);
void middleCalibration(uint16_t timeOfCal);
/** /**
@brief Calibration of the axes at the extreme points (min end max for each axis). @brief Method that allows you to set the minimum and maximum calibration points for each axis.
@details @details
It is recommended to rotate the joystick in a circular way along its perimeter (maximum radius Useful to set the values read by eeprom. Allows you to set the values individually,
for each axis) throughout the calibration time. useful for making changes in run time.
@param timeOfCal is the calibration time in milliseconds. @warning
@return true o false. All calibration points (min and maximum) for each axis (x and y) must be defined to
*/ obtain a scale reading of the two axes.
bool axesCalibration(uint16_t timeOfCal); Only the extreme calibration points can be set, the center point is defined only for
calibration purposes.
@param axis X or Y axle enumerator flag.
@param point MIN, MID or MAX enumertor flag of the calibration point.
@param value point value to set. For example to set value (876) of the X MAX
@code
objectname.setCalibratedPoint(X, MAX, 876);
@endcode
*/
void setCalibratedPoint(axis_t axis, point_t point, uint16_t value);
/** /**
@brief Method that allows you to set the minimum and maximum calibration points for each axis. @brief This method returns the value of the required axis and point.
@details @details
Useful to set the values read by eeprom. Allows you to set the values individually, It can be used to compare the saved values with the new ones, to read the values saved in
useful for making changes in run time. the eeprom with the "setCalibratedPoint" function or for debug.
@warning @see https://github.com/PalladinoMarco/AlignedJoystick/wiki wiki documentation for more
All calibration points (min and maximum) for each axis (x and y) must be defined to details.
obtain a scale reading of the two axes. @param axis X or Y axle enumerator flag.
Only the extreme calibration points can be set, the center point is defined only for calibration purposes. @param point MIN, MID or MAX enumertor flag of the calibration point.
@param axis X or Y axle enumerator flag. @return calibrated point of the axis request. For example to get the calibrated point of Y MIN
@param point MIN, MID or MAX enumertor flag of the calibration point. @code
@param value point value to set. For example to set value (876) of the X MAX objectname.getCalibratedPoint(Y, MIN);
@code @endcode
objectname.setCalibratedPoint(X, MAX, 876); */
@endcode uint16_t getCalibratedPoint(axis_t axis, point_t point);
*/
void setCalibratedPoint(axis_t axis, point_t point, uint16_t value);
/** /**
@brief This method returns the value of the required axis and point. @brief This method returns the required axis value. If calibrated, returns the aligned axis
@details values.
It can be used to compare the saved values with the new ones, to read the values saved in @param axis X or Y axle enumerator flag.
the eeprom with the "setCalibratedPoint" function or for debug. @return analog read of the axis request. For example to read Y axis @code objectname.read(Y);
@see https://github.com/PalladinoMarco/AlignedJoystick/wiki wiki documentation for more details. @endcode
@param axis X or Y axle enumerator flag. */
@param point MIN, MID or MAX enumertor flag of the calibration point. uint16_t read(axis_t axis);
@return calibrated point of the axis request. For example to get the calibrated point of Y MIN
@code
objectname.getCalibratedPoint(Y, MIN);
@endcode
*/
uint16_t getCalibratedPoint(axis_t axis, point_t point);
/** /**
@brief This method returns the required axis value. If calibrated, returns the aligned axis values. @brief This method returns the required joystick axis values in the set range (map functions)
@param axis X or Y axle enumerator flag. @details
@return analog read of the axis request. For example to read Y axis @code objectname.read(Y); @endcode If you want to get a mapping by keeping the scale of calibrated values do not use the arduino
*/ map unction (already included in the method) but use the optional parameters "out_min" and
uint16_t read(axis_t axis); "out_max" of the read method. For arduino map @see
https://www.arduino.cc/reference/en/language/functions/math/map/
@param axis X or Y axle enumerator flag.
@param out_min minimum range output value.
@param out_max maximum range output value.
@return analog read of the relative axis in map mode, for example to control a servo motor, do
this:
@code
objectname.read(X, 1000, 2000);
objectname.read(Y, 1000, 2000);
@endcode
*/
uint16_t read(axis_t axis, int32_t out_min, int32_t out_max);
/** private:
@brief This method returns the required joystick axis values in the set range (map functions) /*
@details sets a single minimum and maximum value, equal for each axis of the joystick to scale them.
If you want to get a mapping by keeping the scale of calibrated values do not use the arduino map */
unction (already included in the method) but use the optional parameters "out_min" and "out_max" void axesAlign();
of the read method. uint8_t xPin;
For arduino map @see https://www.arduino.cc/reference/en/language/functions/math/map/ uint8_t yPin;
@param axis X or Y axle enumerator flag. uint16_t alignMin;
@param out_min minimum range output value. uint16_t alignMax;
@param out_max maximum range output value. uint16_t xAxisCalibCenter;
@return analog read of the relative axis in map mode, for example to control a servo motor, do this: uint16_t xAxisCalibMinimum;
@code uint16_t xAxisCalibMaximum;
objectname.read(X, 1000, 2000); uint16_t yAxisCalibCenter;
objectname.read(Y, 1000, 2000); uint16_t yAxisCalibMinimum;
@endcode uint16_t yAxisCalibMaximum;
*/ bool joystickCentered;
uint16_t read(axis_t axis, int32_t out_min, int32_t out_max); bool joystickFullCalibrated;
private:
/*
sets a single minimum and maximum value, equal for each axis of the joystick to scale them.
*/
void axesAlign();
uint8_t xPin;
uint8_t yPin;
uint16_t alignMin;
uint16_t alignMax;
uint16_t xAxisCalibCenter;
uint16_t xAxisCalibMinimum;
uint16_t xAxisCalibMaximum;
uint16_t yAxisCalibCenter;
uint16_t yAxisCalibMinimum;
uint16_t yAxisCalibMaximum;
bool joystickCentered;
bool joystickFullCalibrated;
}; };
// class from elapsed-Millis // class from elapsed-Millis
@ -209,25 +213,69 @@ class AlignedJoy
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
class calibrationTimer class calibrationTimer {
{ private:
private: unsigned long ms;
unsigned long ms;
public: public:
calibrationTimer(void) { ms = millis(); } calibrationTimer(void) { ms = millis(); }
calibrationTimer(unsigned long val) { ms = millis() - val; } calibrationTimer(unsigned long val) { ms = millis() - val; }
calibrationTimer(const calibrationTimer &orig) { ms = orig.ms; } calibrationTimer(const calibrationTimer& orig) { ms = orig.ms; }
operator unsigned long () const { return millis() - ms; } operator unsigned long() const { return millis() - ms; }
calibrationTimer & operator = (const calibrationTimer &rhs) { ms = rhs.ms; return *this; } calibrationTimer& operator=(const calibrationTimer& rhs) {
calibrationTimer & operator = (unsigned long val) { ms = millis() - val; return *this; } ms = rhs.ms;
calibrationTimer & operator -= (unsigned long val) { ms += val ; return *this; } return *this;
calibrationTimer & operator += (unsigned long val) { ms -= val ; return *this; } }
calibrationTimer operator - (int val) const { calibrationTimer r(*this); r.ms += val; return r; } calibrationTimer& operator=(unsigned long val) {
calibrationTimer operator - (unsigned int val) const { calibrationTimer r(*this); r.ms += val; return r; } ms = millis() - val;
calibrationTimer operator - (long val) const { calibrationTimer r(*this); r.ms += val; return r; } return *this;
calibrationTimer operator - (unsigned long val) const { calibrationTimer r(*this); r.ms += val; return r; } }
calibrationTimer operator + (int val) const { calibrationTimer r(*this); r.ms -= val; return r; } calibrationTimer& operator-=(unsigned long val) {
calibrationTimer operator + (unsigned int val) const { calibrationTimer r(*this); r.ms -= val; return r; } ms += val;
calibrationTimer operator + (long val) const { calibrationTimer r(*this); r.ms -= val; return r; } return *this;
calibrationTimer operator + (unsigned long val) const { calibrationTimer r(*this); r.ms -= val; return r; } }
calibrationTimer& operator+=(unsigned long val) {
ms -= val;
return *this;
}
calibrationTimer operator-(int val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator-(unsigned int val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator-(long val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator-(unsigned long val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator+(int val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
calibrationTimer operator+(unsigned int val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
calibrationTimer operator+(long val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
calibrationTimer operator+(unsigned long val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
}; };

View file

@ -10,25 +10,21 @@ bool JoystickAxisCalibration::valid() const {
return min < mid < max; return min < mid < max;
} }
void writeNvm(const NonVolatileMemory &nvm) void writeNvm(const NonVolatileMemory& nvm) {
{ for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++) {
for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++)
{
EEPROM.write(ii, nvm.rawBytes[ii]); EEPROM.write(ii, nvm.rawBytes[ii]);
} }
} }
void writeCalibration(const JoystickCalibration &cal) { void writeCalibration(const JoystickCalibration& cal) {
NonVolatileMemory nvm = {}; NonVolatileMemory nvm = {};
nvm.joystickCal = cal; nvm.calData.joystickCal = cal;
writeNvm(nvm); writeNvm(nvm);
} }
void readNvm(NonVolatileMemory &nvm) void readNvm(NonVolatileMemory& nvm) {
{
nvm.calData.validMarker = 0; nvm.calData.validMarker = 0;
for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++) for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++) {
{
nvm.rawBytes[ii] = EEPROM.read(ii); nvm.rawBytes[ii] = EEPROM.read(ii);
} }
} }

View file

@ -9,8 +9,7 @@
#define __NVMEEPROM_H__ #define __NVMEEPROM_H__
#include <cstdint> #include <cstdint>
struct JoystickAxisCalibration struct JoystickAxisCalibration {
{
/// Minimum value axis could be /// Minimum value axis could be
uint16_t min; uint16_t min;
/// average center point of axis /// average center point of axis
@ -23,7 +22,6 @@ struct JoystickAxisCalibration
bool valid() const; bool valid() const;
} __attribute__((packed)); } __attribute__((packed));
/// calibration of min/max for single axis analog signals with no mid point /// calibration of min/max for single axis analog signals with no mid point
/// ie: a potentiometer /// ie: a potentiometer
struct LinearAnalogCalibration { struct LinearAnalogCalibration {
@ -32,33 +30,31 @@ struct LinearAnalogCalibration {
inline bool valid() const { return min < max; } inline bool valid() const { return min < max; }
} __attribute__((packed)); } __attribute__((packed));
struct JoystickCalibration struct JoystickCalibration {
{
JoystickAxisCalibration x; JoystickAxisCalibration x;
JoystickAxisCalibration y; JoystickAxisCalibration y;
} __attribute__((packed)); } __attribute__((packed));
static constexpr uint32_t VALID_MARKER_DEFAULT = 0xcafecall; static constexpr uint32_t VALID_MARKER_DEFAULT = 0xcafecall;
union NonVolatileMemory union NonVolatileMemory {
{ /// place hard-coded start marker at the beginning of the data
/// to indicate validity
uint32_t validMarker = VALID_MARKER_DEFAULT;
struct Calibration { struct Calibration {
/// place hard-coded start marker at the beginning of the data
/// to indicate validity
uint32_t validMarker = VALID_MARKER_DEFAULT;
JoystickCalibration joystickCal; JoystickCalibration joystickCal;
LinearAnalogCalibration linearCal; LinearAnalogCalibration linearCal;
} __attribute__((packed)) calData; } __attribute__((packed)) calData;
uint8_t rawBytes[NonVolatileMemory::Calibration] = {}; uint8_t rawBytes[sizeof(NonVolatileMemory::Calibration)] = {};
inline bool valid() const { return calData.validMarker == VALID_MARKER_DEFAULT; } inline bool valid() const { return calData.validMarker == VALID_MARKER_DEFAULT; }
}; };
/// @brief Write the provided struct to EEPROM /// @brief Write the provided struct to EEPROM
void writeNvm(const NonVolatileMemory &nvm); void writeNvm(const NonVolatileMemory& nvm);
void writeCalibration(const JoystickCalibration&cal); void writeCalibration(const JoystickCalibration& cal);
void readNvm(NonVolatileMemory &nvm); void readNvm(NonVolatileMemory& nvm);
#endif /* __NVMEEPROM_H__ */ #endif /* __NVMEEPROM_H__ */

View file

@ -1,32 +1,35 @@
#include <Arduino.h>
#include <AlignedJoy.h> #include <AlignedJoy.h>
#include "NvmEeprom.hpp" #include <Arduino.h>
#include "Arduino_LED_Matrix.h" #include "Arduino_LED_Matrix.h"
#include "NvmEeprom.hpp"
// joystick calibration // joystick calibration
#define TIME_CAL_1 2000 #define TIME_CAL_1 2000
#define TIME_CAL_2 3000 #define TIME_CAL_2 3000
// static objects // static objects
AlignedJoy joystick_1(0, 1); /// X on A0, Y on A1 AlignedJoy joystick_1(0, 1); /// X on A0, Y on A1
ArduinoLEDMatrix ledMatrix; ArduinoLEDMatrix ledMatrix;
/// Run calibration on the provided joystick. Save the results to the provided calibration /// Run calibration on the provided joystick. Save the results to the provided calibration
bool runJoystickCalibrationRoutine(AlignedJoy &joy, JoystickCalibration &cal) bool runJoystickCalibrationRoutine(AlignedJoy& joy, JoystickCalibration& cal) {
{
/* /*
* Start the joystick calibration in the center position. Use this method only if the calibration of the axles is desired (axesCalibration). * Start the joystick calibration in the center position. Use this method only if the
* calibration of the axles is desired (axesCalibration).
*/ */
// CALIBRATION 1 // CALIBRATION 1
Serial.print("Center Joystick Calibration \n\nLeave the joystick in the centre position during the calibration\ntime which is set to "); Serial.print(
"Center Joystick Calibration \n\nLeave the joystick in the centre position during the "
"calibration\ntime which is set to ");
Serial.print(TIME_CAL_1); Serial.print(TIME_CAL_1);
Serial.println(" milliseconds."); Serial.println(" milliseconds.");
delay(5000); delay(5000);
Serial.println("Calibration started!"); Serial.println("Calibration started!");
delay(500); delay(500);
/* /*
* for calibrate the joystick center point use "centerCalibration" method; objectname.centerCalibration(uint16_t timeOfCal). * for calibrate the joystick center point use "centerCalibration" method;
* "timeOfCal" is the calibration time in milliseconds * objectname.centerCalibration(uint16_t timeOfCal). "timeOfCal" is the calibration time in
* milliseconds
*/ */
joy.middleCalibration(TIME_CAL_1); joy.middleCalibration(TIME_CAL_1);
Serial.println("Joystick Centered!"); Serial.println("Joystick Centered!");
@ -38,34 +41,36 @@ bool runJoystickCalibrationRoutine(AlignedJoy &joy, JoystickCalibration &cal)
* It is recommended to rotate the joystick in a circular way along its circumference throughout * It is recommended to rotate the joystick in a circular way along its circumference throughout
* the calibration time. * the calibration time.
*/ */
Serial.print("Start axes Calibration \n\nRotate the joystick in a circular way along its circumference\nthroughout the calibration time ("); Serial.print(
"Start axes Calibration \n\nRotate the joystick in a circular way along its "
"circumference\nthroughout the calibration time (");
Serial.print(TIME_CAL_2); Serial.print(TIME_CAL_2);
Serial.println(" milliseconds)."); Serial.println(" milliseconds).");
delay(5000); delay(5000);
Serial.println("Calibration started!"); Serial.println("Calibration started!");
delay(500); delay(500);
/* /*
* for calibrate the joystick axes points use "axesCalibration" method (bool type); objectname.axesCalibration(uint16_t timeOfCal). * for calibrate the joystick axes points use "axesCalibration" method (bool type);
* "timeOfCal" is the calibration time in milliseconds. * objectname.axesCalibration(uint16_t timeOfCal). "timeOfCal" is the calibration time in
* milliseconds.
*/ */
if (joy.axesCalibration(TIME_CAL_2)) if (joy.axesCalibration(TIME_CAL_2)) {
{ Serial.println("Calibration succesfull!");
Serial.println("Calibration succesfull!!");
} }
else else {
{ Serial.println("Calibration failed!");
Serial.println("Calibration failed!!");
return false; return false;
} }
// Print all points calibrated // Print all points calibrated
/* /*
* You can use these values to save them to eeprom memory. In this way you will avoid requiring the joystick calibration at each boot time. * You can use these values to save them to eeprom memory. In this way you will avoid requiring
* To set the parameters read by eeprom you have to use the "setCalibratedPoint" method. * the joystick calibration at each boot time. To set the parameters read by eeprom you have to
* If your project does not require the re-calibration of the joystick then you can make a sketch like this only to display the calibrated * use the "setCalibratedPoint" method. If your project does not require the re-calibration of
* values to set them in the final project using the "setCalibratedPoint" method. * the joystick then you can make a sketch like this only to display the calibrated values to
* To get the calibrated point values use getCalibratedPoint(axis_t axis, point_t point). * set them in the final project using the "setCalibratedPoint" method. To get the calibrated
* The parameters: the labels of the "axis_t" shall be X and Y; the labels of "point_t" is MIN, MID and MAX. * point values use getCalibratedPoint(axis_t axis, point_t point). The parameters: the labels
* of the "axis_t" shall be X and Y; the labels of "point_t" is MIN, MID and MAX.
*/ */
Serial.print("X min -> "); Serial.print("X min -> ");
Serial.print(joy.getCalibratedPoint(X, MIN)); Serial.print(joy.getCalibratedPoint(X, MIN));
@ -90,15 +95,12 @@ bool runJoystickCalibrationRoutine(AlignedJoy &joy, JoystickCalibration &cal)
return true; return true;
} }
void setup() void setup() {
{
// SERIAL INITIALIZE // SERIAL INITIALIZE
Serial.begin(115200); Serial.begin(115200);
ledMatrix.loadSequence(LEDMATRIX_ANIMATION_STARTUP); ledMatrix.loadSequence(LEDMATRIX_ANIMATION_STARTUP);
ledMatrix.begin(); ledMatrix.begin();
while (!Serial) while (!Serial) {
{
} }
ledMatrix.play(true); ledMatrix.play(true);
@ -109,9 +111,11 @@ void setup()
// run joystick calibration if needed // run joystick calibration if needed
bool calibrationInvalid = nvm.valid(); bool calibrationInvalid = nvm.valid();
do { do {
calibrationInvalid |= !nvm.joystickCal.x.valid() || !nvm.joystickCal.y.valid(); calibrationInvalid |=
!nvm.calData.joystickCal.x.valid() || !nvm.calData.joystickCal.y.valid();
if (calibrationInvalid) { if (calibrationInvalid) {
calibrationInvalid |= !runJoystickCalibrationRoutine(joystick_1, nvm.calData.joystickCal); calibrationInvalid |=
!runJoystickCalibrationRoutine(joystick_1, nvm.calData.joystickCal);
} }
} while (calibrationInvalid); } while (calibrationInvalid);
// ensure calibration has been applied // ensure calibration has been applied
@ -125,14 +129,11 @@ void setup()
// run analog lever calibration if needed // run analog lever calibration if needed
// write NVM in the event any values were updated // write NVM in the event any values were updated
writeNvm(nvm); writeNvm(nvm);
} }
void loop() void loop() {
{
// print joystick axes value // print joystick axes value
Serial.print("joystick_1 X -> "); Serial.print("joystick_1 X -> ");
Serial.print(joystick_1.read(X)); Serial.print(joystick_1.read(X));