Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/BUTTON/button.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class Button
// Properties
uint8_t getCount() const { return _pressCount; }
uint8_t getLongCount() const { return _longCount; }
bool isPressed() const { return _state == STATE_HELD; }
bool isIdle() const { return _state == STATE_IDLE; }

Button() :
_lastCheck(0), _lastFallingEdge(0), _state(STATE_IDLE),
Expand Down
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extra_configs =
targets/fusion.ini
targets/hdzero.ini
targets/orqa.ini
targets/pedal.ini
targets/rapidfire.ini
targets/rx5808.ini
targets/skyzone.ini
Expand Down
8 changes: 7 additions & 1 deletion src/Vrx_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#include "devWIFI.h"
#include "devButton.h"
#include "devLED.h"
#if defined(HAS_HEADTRACKING)
#include "devHeadTracker.h"
#endif

#ifdef RAPIDFIRE_BACKPACK
#include "rapidfire.h"
Expand All @@ -43,6 +45,8 @@
#include "module_aat.h"
#elif defined(CROSSBOW_BACKPACK)
#include "mfd_crossbow.h"
#elif defined(PEDAL_BACKPACK)
#include "module_pedal.h"
#endif

/////////// DEFINES ///////////
Expand Down Expand Up @@ -124,6 +128,8 @@ VrxBackpackConfig config;
AatModule vrxModule(Serial);
#elif defined(CROSSBOW_BACKPACK)
MFDCrossbow vrxModule(&Serial);
#elif defined(PEDAL_BACKPACK)
PedalModule vrxModule;
#endif

/////////// FUNCTION DEFS ///////////
Expand Down Expand Up @@ -341,7 +347,7 @@ void SetSoftMACAddress()

void RequestVTXPacket()
{
#if !defined(AAT_BACKPACK) and !defined(CROSSBOW_BACKPACK)
#if !defined(AAT_BACKPACK) && !defined(CROSSBOW_BACKPACK) && !defined(PEDAL_BACKPACK)
mspPacket_t packet;
packet.reset();
packet.makeCommand();
Expand Down
123 changes: 123 additions & 0 deletions src/module_pedal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#if defined(PEDAL_BACKPACK)

#include "module_pedal.h"
#include "common.h"
#include "msptypes.h"
#if defined(PIN_LED)
#include "devLED.h"
#endif

void sendMSPViaEspnow(mspPacket_t *packet);
bool BindingExpired(uint32_t now);

PedalModule::PedalModule()
: _lastTxValue(false), _lastNow(0), _lastTxMs(0), _lastPedalChangeMs(0)
{
_btnBind.OnLongPress = std::bind(&PedalModule::button_OnLongPress, this);
}

PedalModule::~PedalModule()
{
detachInterrupt(PIN_BUTTON_PEDAL);
}

void PedalModule::Init()
{
_pedalSemaphore = xSemaphoreCreateBinary();
attachInterruptArg(PIN_BUTTON_PEDAL, &PedalModule::button_interrupt, this, CHANGE);
}

void PedalModule::Loop(uint32_t now)
{
// Need to store what the main loop thinks is "now" in case the button
// event is going to use it to set the bindstart time, otherwise millis()
// could be in the future (compared to now) and timeout immediately
_lastNow = now;
if (BindingExpired(_lastNow))
{
connectionState = running;
}

// Pause here to lower power usage (C3 drops from 100mA to 90mA)
// If button is currently transitioning or pressed just consume the semaphore, else delay until an interrupt
xSemaphoreTake(_pedalSemaphore, _btnPedal.isIdle() ? pdMS_TO_TICKS(20) : 0);
_btnPedal.update();
_btnBind.update();

// Don't TX if binding/wifi
if (connectionState != running)
return;
// Don't TX on startup
if (_lastTxMs == 0 && _lastNow < STARTUP_MS)
return;

checkSendPedalPos();
}

void PedalModule::checkSendPedalPos()
{
bool pedalPressed = _btnPedal.isPressed();
bool pedalChanged = pedalPressed != _lastTxValue;

if (pedalChanged)
{
_lastPedalChangeMs = _lastNow;
}

// Send the pedal position frequently after last change, until it is unchanged for one UNCHANGED_MS interval
uint32_t txIntervalMs = (_lastNow - _lastPedalChangeMs < PEDAL_INTERVAL_UNCHANGED_MS) ? PEDAL_INTERVAL_CHANGED_MS : PEDAL_INTERVAL_UNCHANGED_MS;
if (pedalChanged || _lastNow - _lastTxMs > txIntervalMs)
{
_lastTxMs = _lastNow;
_lastTxValue = pedalPressed;
DBGLN("%u pedal %u", _lastNow, pedalPressed);

// Pedal is 1000us if not pressed, 2000us if pressed
uint16_t pedalState = pedalPressed ? CRSF_CHANNEL_VALUE_2000 : CRSF_CHANNEL_VALUE_1000;
mspPacket_t packet;
packet.reset();
packet.makeCommand();
packet.function = MSP_ELRS_BACKPACK_SET_PTR;
packet.addByte(pedalState & 0xFF); // CH0
packet.addByte(pedalState >> 8);
// ExpressLRS 4.0 supports only sending as many channels as needed, but for 3.x compatibility
// 6 total payload bytes are required. A channel value of 0xffff means "do not update" in 4.0
packet.addByte(0xff); // CH1
packet.addByte(0xff);
packet.addByte(0xff); // CH2
packet.addByte(0xff);
sendMSPViaEspnow(&packet);
yield();

#if defined(PIN_LED)
// Flash the LED to indicate the high-speed pedal update mode
if (pedalPressed)
blinkLED();
#endif
}
}

void IRAM_ATTR PedalModule::button_interrupt(void *instance)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(((PedalModule *)instance)->_pedalSemaphore, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR();
}

void PedalModule::button_OnLongPress()
{
// Long press of the bind button for 5s takes the pedal into binding mode
if (_btnBind.getLongCount() >= 10 && connectionState == running)
{
bindingStart = _lastNow;
connectionState = binding;
}
// Long press of bind button for 10s goes from binding to wifi
else if (_btnBind.getLongCount() >= 20 && connectionState == binding)
{
connectionState = wifiUpdate;
}
}

#endif /* PEDAL_BACKPACK */
41 changes: 41 additions & 0 deletions src/module_pedal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#if defined(PEDAL_BACKPACK)
#include "module_base.h"
#include "logging.h"
#include "button.h"

// For wake
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"

class PedalModule : public ModuleBase
{
public:
PedalModule();
~PedalModule();

void Init();
void Loop(uint32_t now);
private:
static void button_interrupt(void *instance);

// Don't send updates on for a short time after bootup
static constexpr uint32_t STARTUP_MS = 2000U;
// Transmit interval differs based on how recently the pedal changed position
static constexpr uint32_t PEDAL_INTERVAL_UNCHANGED_MS = 750U;
static constexpr uint32_t PEDAL_INTERVAL_CHANGED_MS = 100U;

void button_OnLongPress();
void checkSendPedalPos();

Button<PIN_BUTTON_PEDAL, false> _btnPedal;
Button<PIN_BUTTON_BIND, false> _btnBind;
SemaphoreHandle_t _pedalSemaphore;
bool _lastTxValue;
uint32_t _lastNow;
uint32_t _lastTxMs;
uint32_t _lastPedalChangeMs;
};

#endif /* PEDAL_BACKPACK */
2 changes: 1 addition & 1 deletion targets/aat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ build_flags =
lib_deps =
${env.lib_deps}
adafruit/Adafruit SSD1306 @ 2.5.9
build_src_filter = ${common_env_data.build_src_filter} -<Tx_main.cpp> -<rapidfire.*> -<rx5808.*> -<steadyview.*> -<Timer_main.cpp> -<mfd_crossbow.*>
build_src_filter = ${common_env_data.build_src_filter} -<Tx_main.cpp> -<rapidfire.*> -<rx5808.*> -<steadyview.*> -<hdzero.*> -<skyzone_msp.*> -<orqa.*> -<Timer_main.cpp> -<mfd_crossbow.*>

[env:AAT_ESP_Backpack_via_WIFI]
extends = env:AAT_ESP_Backpack_via_UART
23 changes: 12 additions & 11 deletions targets/common.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ lib_deps =
ottowinter/ESPAsyncWebServer-esphome @ 3.2.2
esphome/AsyncTCP-esphome @ 2.1.3 # use specific version - an update to this library breaks the build
bblanchon/ArduinoJson @ 7.1.0
monitor_filters = esp8266_exception_decoder


[common_env_data]
Expand All @@ -26,6 +25,7 @@ board_build.ldscript = eagle.flash.1m.ld
upload_speed = 460800
monitor_speed = 460800
board_build.f_cpu = 160000000L
monitor_filters = esp8266_exception_decoder
build_flags =
-D PLATFORM_ESP8266=1

Expand All @@ -36,6 +36,7 @@ board_build.ldscript = eagle.flash.1m.ld
upload_speed = 921600
monitor_speed = 460800
board_build.f_cpu = 160000000L
monitor_filters = esp8266_exception_decoder
build_flags =
-D PLATFORM_ESP8266=1

Expand Down Expand Up @@ -90,7 +91,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand All @@ -110,7 +111,7 @@ build_src_filter =
; -<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand All @@ -130,7 +131,7 @@ build_src_filter =
-<rapidfire.*>
; -<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand All @@ -150,7 +151,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
; -<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand All @@ -170,7 +171,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
; -<fusion.*>
; -<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand All @@ -190,7 +191,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
; -<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand All @@ -210,7 +211,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
; -<skyzone_msp.*>
-<orqa.*>
Expand All @@ -230,7 +231,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
; -<orqa.*>
Expand All @@ -249,7 +250,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand All @@ -269,7 +270,7 @@ build_src_filter =
-<rapidfire.*>
-<rx5808.*>
-<steadyview.*>
-<fusion.*>
-<tbs_fusion.*>
-<hdzero.*>
-<skyzone_msp.*>
-<orqa.*>
Expand Down
Loading