v1.0.0-alpha3

This commit is contained in:
wiredopposite
2025-01-08 23:03:26 -07:00
parent b3bcbff50a
commit 380bbe7cf7
3 changed files with 256 additions and 63 deletions

250
Firmware/ESP32/main/Range.h Normal file
View File

@@ -0,0 +1,250 @@
#ifndef _RANGE_H_
#define _RANGE_H_
#include <cstdint>
#include <limits>
#include <type_traits>
#include "Board/ogxm_log.h"
namespace Range {
template <typename T>
requires std::is_integral_v<T>
constexpr T MAX = std::numeric_limits<T>::max();
template <typename T>
requires std::is_integral_v<T>
constexpr T MIN = std::numeric_limits<T>::min();
template <typename T>
requires std::is_integral_v<T>
constexpr T MID =
[] {
if constexpr (std::is_unsigned_v<T>)
{
return MAX<T> / 2 + 1;
}
return 0;
}();
static_assert(MID<uint8_t> == 128, "MID<uint8_t> != 128");
static_assert(MID<int8_t> == 0, "MID<int8_t> != 0");
template <typename T>
requires std::is_integral_v<T>
constexpr uint16_t NUM_BITS = sizeof(T) * 8;
//Maximum value for a given number of bits, result will be signed/unsigned depending on type
template<typename T, uint8_t bits>
requires std::is_integral_v<T>
constexpr T BITS_MAX()
{
static_assert(bits <= NUM_BITS<T>, "BITS_MAX: Return type cannot represet maximum bit value");
static_assert(bits <= 64, "BITS_MAX: Bits exceed 64");
if constexpr (std::is_unsigned_v<T>)
{
return (1ULL << bits) - 1;
}
return (1LL << (bits - 1)) - 1;
}
static_assert(BITS_MAX<int16_t, 10>() == 511, "BITS_MAX<int16_t>(10) != 511");
static_assert(BITS_MAX<uint16_t, 10>() == 1023, "BITS_MAX<uint16_t>(10) != 1023");
//Minimum value for a given number of bits, result will be signed/unsigned depending on type
template<typename T, uint8_t bits>
requires std::is_integral_v<T>
constexpr T BITS_MIN()
{
static_assert(bits <= NUM_BITS<T>, "BITS_MIN: Return type cannot represet minimum bit value");
static_assert(bits <= 64, "BITS_MIN: Bits exceed 64");
if constexpr (std::is_unsigned_v<T>)
{
return 0;
}
return static_cast<T>(-(1LL << (bits - 1)));
}
static_assert(BITS_MIN<int16_t, 10>() == -512, "BITS_MIN<int16_t>(10) != -512");
static_assert(BITS_MIN<uint16_t, 10>() == 0, "BITS_MIN<uint16_t>(10) != 0");
template <typename T>
static inline T invert(T value)
{
if constexpr (std::is_unsigned_v<T>)
{
return Range::MAX<T> - value;
}
return (value == Range::MIN<T>) ? Range::MAX<T> : -value;
}
template <typename To, typename From>
requires std::is_integral_v<To> && std::is_integral_v<From>
static inline To clamp(From value)
{
if constexpr (std::is_signed_v<From> != std::is_signed_v<To>)
{
using CommonType = std::common_type_t<To, From>;
return static_cast<To>((static_cast<CommonType>(value) < static_cast<CommonType>(Range::MIN<To>))
? Range::MIN<To>
: (static_cast<CommonType>(value) > static_cast<CommonType>(Range::MAX<To>))
? Range::MAX<To>
: static_cast<CommonType>(value));
}
else
{
return static_cast<To>((value < Range::MIN<To>)
? Range::MIN<To>
: (value > Range::MAX<To>)
? Range::MAX<To>
: value);
}
}
template <typename T>
requires std::is_integral_v<T>
static inline T clamp(T value, T min, T max)
{
return (value < min) ? min : (value > max) ? max : value;
}
template <typename To, typename From>
requires std::is_integral_v<To> && std::is_integral_v<From>
static inline To scale(From value, From min_from, From max_from, To min_to, To max_to)
{
if constexpr (std::is_unsigned_v<From> && std::is_unsigned_v<To>)
{
// Both unsigned
uint64_t scaled = static_cast<uint64_t>(value - min_from) *
(max_to - min_to) /
(max_from - min_from) + min_to;
return static_cast<To>(scaled);
}
else if constexpr (std::is_signed_v<From> && std::is_unsigned_v<To>)
{
// From signed, To unsigned
uint64_t shift_from = static_cast<uint64_t>(-min_from);
uint64_t u_value = static_cast<uint64_t>(value) + shift_from;
uint64_t u_min_from = static_cast<uint64_t>(min_from) + shift_from;
uint64_t u_max_from = static_cast<uint64_t>(max_from) + shift_from;
uint64_t scaled = (u_value - u_min_from) *
(max_to - min_to) /
(u_max_from - u_min_from) + min_to;
return static_cast<To>(scaled);
}
else if constexpr (std::is_unsigned_v<From> && std::is_signed_v<To>)
{
// From unsigned, To signed
uint64_t shift_to = static_cast<uint64_t>(-min_to);
uint64_t scaled = static_cast<uint64_t>(value - min_from) *
(static_cast<uint64_t>(max_to) + shift_to - static_cast<uint64_t>(min_to) - shift_to) /
(max_from - min_from) + static_cast<uint64_t>(min_to) + shift_to;
return static_cast<To>(scaled - shift_to);
}
else
{
// Both signed
int64_t shift_from = -min_from;
int64_t shift_to = -min_to;
int64_t scaled = (static_cast<int64_t>(value) + shift_from - (min_from + shift_from)) *
(max_to + shift_to - (min_to + shift_to)) /
(max_from - min_from) + (min_to + shift_to);
return static_cast<To>(scaled - shift_to);
}
}
template <typename To, typename From>
static inline To scale(From value)
{
return scale<To>(value, Range::MIN<From>, Range::MAX<From>, Range::MIN<To>, Range::MAX<To>);
}
template <typename To, typename From>
static inline To scale(From value, To min_to, To max_to)
{
return scale<To>(value, Range::MIN<From>, Range::MAX<From>, min_to, max_to);
}
//Cast value to signed/unsigned for accurate scaling
template <typename To, uint8_t bits, typename From>
static inline To scale_from_bits(From value)
{
return scale<To>(
value,
BITS_MIN<From, bits>(),
BITS_MAX<From, bits>(),
Range::MIN<To>,
Range::MAX<To>);
}
//Cast value to signed/unsigned for accurate scaling
template <typename To, uint8_t bits, typename From>
static inline To scale_to_bits(From value)
{
return scale<To>(
value,
Range::MIN<From>,
Range::MAX<From>,
BITS_MIN<To, bits>(),
BITS_MAX<To, bits>());
}
} // namespace Range
namespace Scale //Scale and invert values
{
static inline uint8_t int16_to_uint8(int16_t value)
{
uint16_t shifted_value = static_cast<uint16_t>(value + Range::MID<uint16_t>);
return static_cast<uint8_t>(shifted_value >> 8);
}
static inline uint16_t int16_to_uint16(int16_t value)
{
return static_cast<uint16_t>(value + Range::MID<uint16_t>);
}
static inline int8_t int16_to_int8(int16_t value)
{
return static_cast<int8_t>((value + Range::MID<uint16_t>) >> 8);
}
static inline uint8_t uint16_to_uint8(uint16_t value)
{
return static_cast<uint8_t>(value >> 8);
}
static inline int16_t uint16_to_int16(uint16_t value)
{
return static_cast<int16_t>(value - Range::MID<uint16_t>);
}
static inline int8_t uint16_to_int8(uint16_t value)
{
return static_cast<int8_t>((value >> 8) - Range::MID<uint8_t>);
}
static inline int16_t uint8_to_int16(uint8_t value)
{
return static_cast<int16_t>((static_cast<int32_t>(value) << 8) - Range::MID<uint16_t>);
}
static inline uint16_t uint8_to_uint16(uint8_t value)
{
return static_cast<uint16_t>(value) << 8;
}
static inline int8_t uint8_to_int8(uint8_t value)
{
return static_cast<int8_t>(value - Range::MID<uint8_t>);
}
static inline int16_t int8_to_int16(int8_t value)
{
return static_cast<int16_t>(value) << 8;
}
static inline uint16_t int8_to_uint16(int8_t value)
{
return static_cast<uint16_t>((value + Range::MID<uint8_t>) << 8);
}
static inline uint8_t int8_to_uint8(int8_t value)
{
return static_cast<uint8_t>(value + Range::MID<uint8_t>);
}
} // namespace Scale
#endif // _RANGE_H_

View File

@@ -105,28 +105,6 @@ namespace Range {
return (value < min) ? min : (value > max) ? max : value;
}
// //Scale value from one range to another, will clamp value to input range
// template <typename To, typename From>
// requires std::is_integral_v<To> && std::is_integral_v<From>
// static inline To scale(From value, From min_from, From max_from, To min_to, To max_to)
// {
// constexpr bool is_signed_from = std::is_signed_v<From>;
// constexpr bool is_signed_to = std::is_signed_v<To>;
// constexpr auto shift_from = is_signed_from ? static_cast<uint64_t>(0 - Range::MIN<From>) : 0;
// constexpr auto shift_to = is_signed_to ? static_cast<uint64_t>(0 - Range::MIN<To>) : 0;
// const uint64_t u_value = static_cast<uint64_t>(value) + shift_from;
// const uint64_t u_min_from = static_cast<uint64_t>(min_from) + shift_from;
// const uint64_t u_max_from = static_cast<uint64_t>(max_from) + shift_from;
// const uint64_t u_min_to = static_cast<uint64_t>(min_to) + shift_to;
// const uint64_t u_max_to = static_cast<uint64_t>(max_to) + shift_to;
// const uint64_t scaled = ((u_value - u_min_from) * (u_max_to - u_min_to)) / (u_max_from - u_min_from) + u_min_to;
// return static_cast<To>(scaled - (is_signed_to ? shift_to : 0));
// }
template <typename To, typename From>
requires std::is_integral_v<To> && std::is_integral_v<From>
static inline To scale(From value, From min_from, From max_from, To min_to, To max_to)
@@ -267,41 +245,6 @@ namespace Scale //Scale and invert values
return static_cast<uint8_t>(value + Range::MID<uint8_t>);
}
// static inline uint8_t int10_to_uint8(int32_t value)
// {
// return Range::scale<uint8_t>(value, 10);
// // return static_cast<uint8_t>(value >> 2);
// }
// static inline int16_t int10_to_int16(int32_t value)
// {
// return Range::scale<int16_t>(value, 10);
// // constexpr int32_t scale_factor = Range::MAX<int16_t> - Range::MIN<int16_t>;
// // constexpr int32_t range = INT_10::MAX - INT_10::MIN;
// // if (value >= INT_10::MAX)
// // {
// // return Range::MAX<int16_t>;
// // }
// // else if (value <= INT_10::MIN)
// // {
// // return Range::MIN<int16_t>;
// // }
// // int32_t scaled_value = (value - INT_10::MIN) * scale_factor;
// // return static_cast<int16_t>(scaled_value / range + Range::MIN<int16_t>);
// }
// static inline uint8_t uint10_to_uint8(int32_t value)
// {
// if (value > UINT_10::MAX)
// {
// value = UINT_10::MAX;
// }
// else if (value < 0)
// {
// value = 0;
// }
// return static_cast<uint8_t>(value >> 2);
// }
} // namespace Scale
#endif // _RANGE_H_

View File

@@ -1,9 +1,9 @@
# OGX-Mini
![OGX-Mini Boards](images/OGX-Mini-github.jpg "OGX-Mini Boards")
Firmware for the RP2040, capable of emulating gamepads for several game consoles. The firmware comes in many flavors, supported on the [Adafruit Feather USB Host board](https://www.adafruit.com/product/5723), Pi Pico, Pi Pico 2, Waveshare RP2040-Zero, Pi Pico W, RP2040/ESP32 hybrid, and a 4-Channel RP2040-Zero setup.
Firmware for the RP2040, capable of emulating gamepads for several game consoles. The firmware comes in many flavors, supported on the [Adafruit Feather USB Host board](https://www.adafruit.com/product/5723), Pi Pico, Pi Pico 2, Pi Pico W, Pi Pico 2 W, Waveshare RP2040-Zero, Pico/ESP32 hybrid, and a 4-Channel RP2040-Zero setup.
Visit the web app here: [**https://wiredopposite.github.io/OGX-Mini-WebApp/**](https://wiredopposite.github.io/OGX-Mini-WebApp/) to change your mappings and deadzone settings. To pair the OGX-Mini with the web app, plug your controller in, then connect it to your PC, hold **Start + Left Bumper + Right Bumper** to enter web app mode. Click "Connect" in the web app and select the OGX-Mini.
[**Visit the web app here**](https://wiredopposite.github.io/OGX-Mini-WebApp/) to change your mappings and deadzone settings. To pair the OGX-Mini with the web app, plug your controller in, then connect it to your PC, hold **Start + Left Bumper + Right Bumper** to enter web app mode. Click "Connect" in the web app and select the OGX-Mini.
## Supported platforms
- Original Xbox
@@ -59,7 +59,7 @@ Note: There are some third party controllers that can change their VID/PID, thes
- Most wireless adapters that present themselves as Switch/XInput/PlayStation controllers should work
### Wireless Bluetooth controllers (Pico W & ESP32)
Note: Bluetooth functionality is in early testing, some may have quirks.
**Note:** Bluetooth functionality is in early testing, some may have quirks.
- Xbox Series, One, and Elite 2
- Dualshock 3
- Dualshock 4
@@ -74,7 +74,7 @@ Please visit [**this page**](https://bluepad32.readthedocs.io/en/latest/supporte
## Features new to v1.0.0
- Bluetooth functionality for the Pico W and Pico+ESP32.
- Web application (connectable via USB or Bluetooth) for configuring deadzones and buttons mappings, supports up to 8 saved profiles.
- Pi Pico 2 (RP2350) support.
- Pi Pico 2 and Pico 2 W (RP2350) support.
- Reduced latency by about 3-4 ms, graphs showing comparisons are coming
- 4 channel functionality, connect 4 Picos and use one Xbox 360 wireless adapter to control all 4.
- Delayed USB mount until a controller is plugged in, useful for internal installation (non-Bluetooth boards only).
@@ -101,9 +101,9 @@ For Pi Pico, RP2040-Zero, 4 channel, and ESP32 configurations, please see the ha
I've designed a PCB for the RP2040-Zero so you can make a small form-factor adapter yourself. The gerber files, schematic, and BOM are in Hardware folder.
![OGX-Mini Boards](images/OGX-Mini-rpzero-int.jpg "OGX-Mini Boards")
<img src="images/OGX-Mini-rpzero-int.jpg" alt="OGX-Mini Boards" width="400">
If you would like a prebuilt unit, you can purchase one, with cable and Xbox adapter included, from my [Etsy store](https://www.etsy.com/listing/1426992904/ogx-mini-controller-adapter-for-original).
If you would like a prebuilt unit, you can purchase one, with cable and Xbox adapter included, from my [**Etsy store**](https://www.etsy.com/listing/1426992904/ogx-mini-controller-adapter-for-original).
## Adding supported controllers
If your third party controller isn't working, but the original version is listed above, send me the device's VID and PID and I'll add it so it's recognized properly.