diff --git a/hal/include/HAL/CanTalonSRX.h b/hal/include/HAL/CanTalonSRX.h index f04ce3c3a0..4060650b86 100644 --- a/hal/include/HAL/CanTalonSRX.h +++ b/hal/include/HAL/CanTalonSRX.h @@ -75,9 +75,21 @@ #include "ctre/CtreCanNode.h" #include //CAN Comm #include +#include class CanTalonSRX : public CtreCanNode { private: + // Use this for determining whether the default move constructor has been + // called; this prevents us from calling the destructor twice. + struct HasBeenMoved { + HasBeenMoved(HasBeenMoved&& other) { + other.moved = true; + moved = false; + } + HasBeenMoved() = default; + std::atomic moved{false}; + operator bool() const { return moved; } + } m_hasBeenMoved; /** just in case user wants to modify periods of certain status frames. * Default the vars to match the firmware default. */ @@ -211,7 +223,7 @@ public: eResetFlags=88, eFirmVers=89, eSettingsChanged=90, - eQuadFilterEn=91, + eQuadFilterEn=91, ePidIaccum=93, }param_t; /*---------------------setters and getters that use the solicated param request/response-------------*//** diff --git a/hal/lib/Athena/ctre/CanTalonSRX.cpp b/hal/lib/Athena/ctre/CanTalonSRX.cpp index a3177cd3ad..b416986858 100644 --- a/hal/lib/Athena/ctre/CanTalonSRX.cpp +++ b/hal/lib/Athena/ctre/CanTalonSRX.cpp @@ -268,6 +268,8 @@ CanTalonSRX::CanTalonSRX(int deviceNumber,int controlPeriodMs): CtreCanNode(devi */ CanTalonSRX::~CanTalonSRX() { + if (m_hasBeenMoved) return; + RegisterTx(CONTROL_1 | (UINT8)GetDeviceNumber(), 0); if(_can_h){ FRC_NetworkCommunication_CANSessionMux_closeStreamSession(_can_h); _can_h = 0; diff --git a/wpilibc/wpilibC++/include/Base.h b/wpilibc/wpilibC++/include/Base.h index 892dd5dd4c..7a7cc1266c 100644 --- a/wpilibc/wpilibC++/include/Base.h +++ b/wpilibc/wpilibC++/include/Base.h @@ -5,6 +5,16 @@ /*----------------------------------------------------------------------------*/ #pragma once +// MSVC 2013 doesn't allow "= default" on move constructors, but since we are +// (currently) only actually using the move constructors in non-MSVC situations +// (ie, wpilibC++Devices), we can just ignore it in MSVC. +#if !defined(_MSC_VER) +#define DEFAULT_MOVE_CONSTRUCTOR(ClassName) \ +ClassName(ClassName &&) = default +#else +#define DEFAULT_MOVE_CONSTRUCTOR(ClassName) +#endif + // A struct to use as a deleter when a std::shared_ptr must wrap a raw pointer // that is being deleted by someone else. // This should only be called in deprecated functions; using it anywhere else @@ -13,3 +23,19 @@ template struct [[deprecated]] NullDeleter { void operator()(T *) const noexcept {}; }; + +#include +// Use this for determining whether the default move constructor has been +// called on a containing object. This serves the purpose of allowing us to +// use the default move constructor of an object for moving all the data around +// while being able to use this to, for instance, chose not to de-allocate +// a PWM port in a destructor. +struct HasBeenMoved { + HasBeenMoved(HasBeenMoved&& other) { + other.moved = true; + moved = false; + } + HasBeenMoved() = default; + std::atomic moved{false}; + operator bool() const { return moved; } +}; diff --git a/wpilibc/wpilibC++Devices/include/CANTalon.h b/wpilibc/wpilibC++Devices/include/CANTalon.h index 3c2545938d..9108451b71 100644 --- a/wpilibc/wpilibC++Devices/include/CANTalon.h +++ b/wpilibc/wpilibC++Devices/include/CANTalon.h @@ -43,7 +43,8 @@ class CANTalon : public MotorSafety, }; explicit CANTalon(int deviceNumber); explicit CANTalon(int deviceNumber, int controlPeriodMs); - virtual ~CANTalon() = default; + DEFAULT_MOVE_CONSTRUCTOR(CANTalon); + virtual ~CANTalon(); // PIDOutput interface virtual void PIDWrite(float output) override; @@ -204,4 +205,6 @@ class CANTalon : public MotorSafety, // LiveWindow stuff. std::shared_ptr m_table; bool m_isInverted; + + HasBeenMoved m_hasBeenMoved; }; diff --git a/wpilibc/wpilibC++Devices/src/CANTalon.cpp b/wpilibc/wpilibC++Devices/src/CANTalon.cpp index 2b303e86ce..9b267eceaa 100644 --- a/wpilibc/wpilibC++Devices/src/CANTalon.cpp +++ b/wpilibc/wpilibC++Devices/src/CANTalon.cpp @@ -43,6 +43,11 @@ CANTalon::CANTalon(int deviceNumber, int controlPeriodMs) m_impl->SetProfileSlotSelect(m_profile); } +CANTalon::~CANTalon() { + if (m_hasBeenMoved) return; + Disable(); +} + /** * Write out the PID value as seen in the PIDOutput base object. * diff --git a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java index 0fc1190f00..4485ee541d 100644 --- a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java +++ b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java @@ -144,6 +144,7 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, PIDInterface } public void delete() { + disable(); m_impl.delete(); }