Squashed 'third_party/Phoenix-frc-lib/' content from commit 666d176
Change-Id: Ibaca2fc8ffb1177e786576cc1e4cc9f7a8c98f13
git-subtree-dir: third_party/Phoenix-frc-lib
git-subtree-split: 666d176a08151793044ab74e0005f13d3732ed96
diff --git a/cpp/include/ctre/Phoenix.h b/cpp/include/ctre/Phoenix.h
new file mode 100644
index 0000000..ff1cb68
--- /dev/null
+++ b/cpp/include/ctre/Phoenix.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "ctre/phoenix/CANifier.h"
+#include "ctre/phoenix/ErrorCode.h"
+#include "ctre/phoenix/paramEnum.h"
+#include "ctre/phoenix/HsvToRgb.h"
+#include "ctre/phoenix/LinearInterpolation.h"
+#include "ctre/phoenix/Motion/MotionProfileStatus.h"
+#include "ctre/phoenix/Motion/TrajectoryPoint.h"
+#include "ctre/phoenix/MotorControl/CAN/TalonSRX.h"
+#include "ctre/phoenix/MotorControl/CAN/VictorSPX.h"
+#include "ctre/phoenix/MotorControl/CAN/WPI_TalonSRX.h"
+#include "ctre/phoenix/MotorControl/CAN/WPI_VictorSPX.h"
+#include "ctre/phoenix/MotorControl/DemandType.h"
+#include "ctre/phoenix/MotorControl/Faults.h"
+#include "ctre/phoenix/MotorControl/FollowerType.h"
+#include "ctre/phoenix/MotorControl/SensorCollection.h"
+#include "ctre/phoenix/MotorControl/IMotorController.h"
+#include "ctre/phoenix/MotorControl/IMotorControllerEnhanced.h"
+#include "ctre/phoenix/Sensors/PigeonIMU.h"
+#include "ctre/phoenix/Signals/MovingAverage.h"
+#include "ctre/phoenix/Tasking/Schedulers/ConcurrentScheduler.h"
+#include "ctre/phoenix/Tasking/ILoopable.h"
+#include "ctre/phoenix/Tasking/IProcessable.h"
+#include "ctre/phoenix/Tasking/ButtonMonitor.h"
+#include "ctre/phoenix/Utilities.h"
+
+using namespace ctre;
+using namespace ctre::phoenix;
+using namespace ctre::phoenix::motion;
+using namespace ctre::phoenix::motorcontrol;
+using namespace ctre::phoenix::motorcontrol::can;
+using namespace ctre::phoenix::sensors;
+using namespace ctre::phoenix::signals;
+using namespace ctre::phoenix::tasking;
+using namespace ctre::phoenix::tasking::schedulers;
diff --git a/cpp/include/ctre/phoenix/CANifier.h b/cpp/include/ctre/phoenix/CANifier.h
new file mode 100644
index 0000000..5e83b22
--- /dev/null
+++ b/cpp/include/ctre/phoenix/CANifier.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+
+#include <cstdint>
+#include "ctre/phoenix/LowLevel/CANBusAddressable.h"
+#include "ctre/phoenix/ErrorCode.h"
+#include "ctre/phoenix/paramEnum.h"
+#include "ctre/phoenix/CANifierControlFrame.h"
+#include "ctre/phoenix/CANifierStatusFrame.h"
+#include "ctre/phoenix/CANifierStickyFaults.h"
+#include "ctre/phoenix/CANifierFaults.h"
+#include "ctre/phoenix/CANifierVelocityMeasPeriod.h"
+
+namespace ctre {namespace phoenix {
+ /**
+ * CTRE CANifier
+ *
+ * Device for interfacing common devices to the CAN bus.
+ */
+class CANifier: public CANBusAddressable {
+public:
+ /**
+ * Enum for the LED Output Channels
+ */
+ enum LEDChannel {
+ LEDChannelA = 0, LEDChannelB = 1, LEDChannelC = 2,
+ };
+
+ /**
+ * Enum for the PWM Input Channels
+ */
+ enum PWMChannel {
+ PWMChannel0 = 0, PWMChannel1 = 1, PWMChannel2 = 2, PWMChannel3 = 3,
+ };
+ const int PWMChannelCount = 4;
+
+ /**
+ * General IO Pins on the CANifier
+ */
+ enum GeneralPin {
+ QUAD_IDX = 0, //----- Must match CANifier_CCI enums -----//
+ QUAD_B = 1,
+ QUAD_A = 2,
+ LIMR = 3,
+ LIMF = 4,
+ SDA = 5,
+ SCL = 6,
+ SPI_CS = 7,
+ SPI_MISO_PWM2P = 8,
+ SPI_MOSI_PWM1P = 9,
+ SPI_CLK_PWM0P = 10,
+ };
+
+ /**
+ * Structure to hold the pin values.
+ */
+ struct PinValues {
+ bool QUAD_IDX;
+ bool QUAD_B;
+ bool QUAD_A;
+ bool LIMR;
+ bool LIMF;
+ bool SDA;
+ bool SCL;
+ bool SPI_CS_PWM3;
+ bool SPI_MISO_PWM2;
+ bool SPI_MOSI_PWM1;
+ bool SPI_CLK_PWM0;
+ };
+
+ CANifier(int deviceNumber);
+ ErrorCode SetLEDOutput(double percentOutput, LEDChannel ledChannel);
+ ErrorCode SetGeneralOutput(GeneralPin outputPin, bool outputValue, bool outputEnable);
+ ErrorCode SetGeneralOutputs(int outputBits, int isOutputBits);
+ ErrorCode GetGeneralInputs(PinValues &allPins);
+ bool GetGeneralInput(GeneralPin inputPin);
+ int GetQuadraturePosition();
+ int GetQuadratureVelocity();
+ ErrorCode SetQuadraturePosition(int newPosition, int timeoutMs);
+ ErrorCode ConfigVelocityMeasurementPeriod(
+ CANifierVelocityMeasPeriod period, int timeoutMs);
+ ErrorCode ConfigVelocityMeasurementWindow(int windowSize, int timeoutMs);
+ /**
+ * Gets the bus voltage seen by the motor controller.
+ *
+ * @return The bus voltage value (in volts).
+ */
+ double GetBusVoltage();
+ ErrorCode GetLastError();
+ ErrorCode SetPWMOutput(int pwmChannel, double dutyCycle);
+ ErrorCode EnablePWMOutput(int pwmChannel, bool bEnable);
+ ErrorCode GetPWMInput(PWMChannel pwmChannel, double dutyCycleAndPeriod[]);
+
+ //------ Custom Persistent Params ----------//
+ ErrorCode ConfigSetCustomParam(int newValue, int paramIndex,
+ int timeoutMs);
+ int ConfigGetCustomParam(int paramIndex,
+ int timeoutMs);
+ //------ Generic Param API, typically not used ----------//
+ ErrorCode ConfigSetParameter(ParamEnum param, double value,
+ uint8_t subValue, int ordinal, int timeoutMs);
+ double ConfigGetParameter(ParamEnum param, int ordinal, int timeoutMs);
+
+
+ ErrorCode SetStatusFramePeriod(CANifierStatusFrame statusFrame,
+ int periodMs, int timeoutMs);
+ /**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+ * Timeout value in ms. @see #ConfigOpenLoopRamp
+ * @return Period of the given status frame.
+ */
+ int GetStatusFramePeriod(CANifierStatusFrame frame, int timeoutMs);
+ ErrorCode SetControlFramePeriod(CANifierControlFrame frame, int periodMs);
+ /**
+ * Gets the firmware version of the device.
+ *
+ * @return Firmware version of device.
+ */
+ int GetFirmwareVersion();
+ /**
+ * Returns true if the device has reset since last call.
+ *
+ * @return Has a Device Reset Occurred?
+ */
+ bool HasResetOccurred();
+ ErrorCode GetFaults(CANifierFaults & toFill);
+ ErrorCode GetStickyFaults(CANifierStickyFaults & toFill);
+ ErrorCode ClearStickyFaults(int timeoutMs);
+
+private:
+ void* m_handle;
+ bool _tempPins[11];
+};
+}}
+#endif // CTR_EXCLUDE_WPILIB_CLASSES
diff --git a/cpp/include/ctre/phoenix/CTRLogger.h b/cpp/include/ctre/phoenix/CTRLogger.h
new file mode 100644
index 0000000..91f8d43
--- /dev/null
+++ b/cpp/include/ctre/phoenix/CTRLogger.h
@@ -0,0 +1,16 @@
+#include "ctre/phoenix/ErrorCode.h" // ErrorCode
+#include <string>
+
+namespace ctre {
+namespace phoenix {
+
+class CTRLogger {
+public:
+ static void Close();
+ static ErrorCode Log(ErrorCode code, std::string origin);
+ static void Open(int language);
+ //static void Description(ErrorCode code, const char *&shrt, const char *&lng);
+};
+
+}
+}
diff --git a/cpp/include/ctre/phoenix/HsvToRgb.h b/cpp/include/ctre/phoenix/HsvToRgb.h
new file mode 100644
index 0000000..90a89ad
--- /dev/null
+++ b/cpp/include/ctre/phoenix/HsvToRgb.h
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace ctre {
+namespace phoenix {
+
+class HsvToRgb {
+public:
+ static void Convert(double hDegrees, double S, double V, float* r, float* g,
+ float* b);
+};
+
+}
+}
diff --git a/cpp/include/ctre/phoenix/LinearInterpolation.h b/cpp/include/ctre/phoenix/LinearInterpolation.h
new file mode 100644
index 0000000..f445852
--- /dev/null
+++ b/cpp/include/ctre/phoenix/LinearInterpolation.h
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace ctre {
+namespace phoenix {
+
+class LinearInterpolation {
+public:
+ static float Calculate(float x, float x1, float y1, float x2, float y2);
+};
+
+}}
+
diff --git a/cpp/include/ctre/phoenix/MotorControl/CAN/BaseMotorController.h b/cpp/include/ctre/phoenix/MotorControl/CAN/BaseMotorController.h
new file mode 100644
index 0000000..6378f6f
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/CAN/BaseMotorController.h
@@ -0,0 +1,236 @@
+#pragma once
+
+#include "ctre/phoenix/ErrorCode.h"
+#include "ctre/phoenix/paramEnum.h"
+#include "ctre/phoenix/core/GadgeteerUartClient.h"
+#include "ctre/phoenix/MotorControl/IMotorController.h"
+#include "ctre/phoenix/MotorControl/ControlMode.h"
+#include "ctre/phoenix/MotorControl/DemandType.h"
+#include "ctre/phoenix/MotorControl/Faults.h"
+#include "ctre/phoenix/MotorControl/FollowerType.h"
+#include "ctre/phoenix/MotorControl/StickyFaults.h"
+#include "ctre/phoenix/MotorControl/VelocityMeasPeriod.h"
+#include "ctre/phoenix/Motion/TrajectoryPoint.h"
+#include "ctre/phoenix/Motion/MotionProfileStatus.h"
+/* WPILIB */
+#include "SpeedController.h"
+
+/* forward proto's */
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+namespace lowlevel {
+class MotControllerWithBuffer_LowLevel;
+class MotController_LowLevel;
+}
+}
+}
+}
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+class SensorCollection;
+}
+}
+}
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+namespace can {
+/**
+ * Base motor controller features for all CTRE CAN motor controllers.
+ */
+class BaseMotorController: public virtual IMotorController {
+private:
+ ControlMode m_controlMode = ControlMode::PercentOutput;
+ ControlMode m_sendMode = ControlMode::PercentOutput;
+
+ int _arbId = 0;
+ double m_setPoint = 0;
+ bool _invert = false;
+
+ ctre::phoenix::motorcontrol::SensorCollection * _sensorColl;
+protected:
+ void* m_handle;
+ void* GetHandle();
+public:
+ BaseMotorController(int arbId);
+ ~BaseMotorController();
+ BaseMotorController() = delete;
+ BaseMotorController(BaseMotorController const&) = delete;
+ BaseMotorController& operator=(BaseMotorController const&) = delete;
+ int GetDeviceID();
+ virtual void Set(ControlMode Mode, double value);
+ virtual void Set(ControlMode mode, double demand0, double demand1);
+ virtual void Set(ControlMode mode, double demand0, DemandType demand1Type, double demand1);
+ virtual void NeutralOutput();
+ virtual void SetNeutralMode(NeutralMode neutralMode);
+ void EnableHeadingHold(bool enable);
+ void SelectDemandType(bool value);
+ //------ Invert behavior ----------//
+ virtual void SetSensorPhase(bool PhaseSensor);
+ virtual void SetInverted(bool invert);
+ virtual bool GetInverted() const;
+ //----- general output shaping ------------------//
+ virtual ctre::phoenix::ErrorCode ConfigOpenloopRamp(double secondsFromNeutralToFull,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigClosedloopRamp(double secondsFromNeutralToFull,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigPeakOutputForward(double percentOut, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigPeakOutputReverse(double percentOut, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigNominalOutputForward(double percentOut,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigNominalOutputReverse(double percentOut,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigNeutralDeadband(double percentDeadband,
+ int timeoutMs);
+ //------ Voltage Compensation ----------//
+ virtual ctre::phoenix::ErrorCode ConfigVoltageCompSaturation(double voltage, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigVoltageMeasurementFilter(int filterWindowSamples,
+ int timeoutMs);
+ virtual void EnableVoltageCompensation(bool enable);
+ //------ General Status ----------//
+ virtual double GetBusVoltage();
+ virtual double GetMotorOutputPercent();
+ virtual double GetMotorOutputVoltage();
+ virtual double GetOutputCurrent();
+ virtual double GetTemperature();
+ //------ sensor selection ----------//
+ virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackSensor(
+ RemoteFeedbackDevice feedbackDevice, int pidIdx, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackSensor(
+ FeedbackDevice feedbackDevice, int pidIdx, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackCoefficient(
+ double coefficient, int pidIdx, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigRemoteFeedbackFilter(int deviceID,
+ RemoteSensorSource remoteSensorSource, int remoteOrdinal,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigSensorTerm(SensorTerm sensorTerm,
+ FeedbackDevice feedbackDevice, int timeoutMs);
+
+ //------- sensor status --------- //
+ virtual int GetSelectedSensorPosition(int pidIdx);
+ virtual int GetSelectedSensorVelocity(int pidIdx);
+ virtual ctre::phoenix::ErrorCode SetSelectedSensorPosition(int sensorPos, int pidIdx, int timeoutMs);
+ //------ status frame period changes ----------//
+ virtual ctre::phoenix::ErrorCode SetControlFramePeriod(ControlFrame frame, int periodMs);
+ virtual ctre::phoenix::ErrorCode SetStatusFramePeriod(StatusFrame frame, int periodMs,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode SetStatusFramePeriod(StatusFrameEnhanced frame,
+ int periodMs, int timeoutMs);
+ virtual int GetStatusFramePeriod(StatusFrame frame, int timeoutMs);
+ virtual int GetStatusFramePeriod(StatusFrameEnhanced frame, int timeoutMs);
+ //----- velocity signal conditionaing ------//
+ virtual ctre::phoenix::ErrorCode ConfigVelocityMeasurementPeriod(VelocityMeasPeriod period,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigVelocityMeasurementWindow(int windowSize,
+ int timeoutMs);
+ //------ remote limit switch ----------//
+ virtual ctre::phoenix::ErrorCode ConfigForwardLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigReverseLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs);
+ void OverrideLimitSwitchesEnable(bool enable);
+ //------ local limit switch ----------//
+ virtual ctre::phoenix::ErrorCode ConfigForwardLimitSwitchSource(LimitSwitchSource type,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigReverseLimitSwitchSource(LimitSwitchSource type,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs);
+ //------ soft limit ----------//
+ virtual ctre::phoenix::ErrorCode ConfigForwardSoftLimitThreshold(int forwardSensorLimit,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigReverseSoftLimitThreshold(int reverseSensorLimit,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigForwardSoftLimitEnable(bool enable,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigReverseSoftLimitEnable(bool enable,
+ int timeoutMs);
+ virtual void OverrideSoftLimitsEnable(bool enable);
+ //------ Current Lim ----------//
+ /* not available in base */
+ //------ General Close loop ----------//
+ virtual ctre::phoenix::ErrorCode Config_kP(int slotIdx, double value, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode Config_kI(int slotIdx, double value, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode Config_kD(int slotIdx, double value, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode Config_kF(int slotIdx, double value, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode Config_IntegralZone(int slotIdx, int izone,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigAllowableClosedloopError(int slotIdx,
+ int allowableCloseLoopError, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigMaxIntegralAccumulator(int slotIdx, double iaccum,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigClosedLoopPeakOutput(int slotIdx, double percentOut, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigClosedLoopPeriod(int slotIdx, int loopTimeMs, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigAuxPIDPolarity(bool invert, int timeoutMs);
+
+ //------ Close loop State ----------//
+ virtual ctre::phoenix::ErrorCode SetIntegralAccumulator(double iaccum, int pidIdx,int timeoutMs);
+ virtual int GetClosedLoopError(int pidIdx);
+ virtual double GetIntegralAccumulator(int pidIdx);
+ virtual double GetErrorDerivative(int pidIdx);
+
+ virtual ctre::phoenix::ErrorCode SelectProfileSlot(int slotIdx, int pidIdx);
+
+ virtual int GetClosedLoopTarget(int pidIdx);
+ virtual int GetActiveTrajectoryPosition();
+ virtual int GetActiveTrajectoryVelocity();
+ virtual double GetActiveTrajectoryHeading();
+
+ //------ Motion Profile Settings used in Motion Magic ----------//
+ virtual ctre::phoenix::ErrorCode ConfigMotionCruiseVelocity(int sensorUnitsPer100ms,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigMotionAcceleration(int sensorUnitsPer100msPerSec,
+ int timeoutMs);
+ //------ Motion Profile Buffer ----------//
+ virtual ErrorCode ClearMotionProfileTrajectories();
+ virtual int GetMotionProfileTopLevelBufferCount();
+ virtual ctre::phoenix::ErrorCode PushMotionProfileTrajectory(
+ const ctre::phoenix::motion::TrajectoryPoint & trajPt);
+ virtual bool IsMotionProfileTopLevelBufferFull();
+ virtual void ProcessMotionProfileBuffer();
+ virtual ctre::phoenix::ErrorCode GetMotionProfileStatus(
+ ctre::phoenix::motion::MotionProfileStatus & statusToFill);
+ virtual ctre::phoenix::ErrorCode ClearMotionProfileHasUnderrun(int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ChangeMotionControlFramePeriod(int periodMs);
+ virtual ctre::phoenix::ErrorCode ConfigMotionProfileTrajectoryPeriod(int baseTrajDurationMs, int timeoutMs);
+ //------ error ----------//
+ virtual ctre::phoenix::ErrorCode GetLastError();
+ //------ Faults ----------//
+ virtual ctre::phoenix::ErrorCode GetFaults(Faults & toFill);
+ virtual ctre::phoenix::ErrorCode GetStickyFaults(StickyFaults & toFill);
+ virtual ctre::phoenix::ErrorCode ClearStickyFaults(int timeoutMs);
+ //------ Firmware ----------//
+ virtual int GetFirmwareVersion();
+ virtual bool HasResetOccurred();
+ //------ Custom Persistent Params ----------//
+ virtual ctre::phoenix::ErrorCode ConfigSetCustomParam(int newValue, int paramIndex,
+ int timeoutMs);
+ virtual int ConfigGetCustomParam(int paramIndex,
+ int timeoutMs);
+ //------ Generic Param API, typically not used ----------//
+ virtual ctre::phoenix::ErrorCode ConfigSetParameter(ctre::phoenix::ParamEnum param, double value,
+ uint8_t subValue, int ordinal, int timeoutMs);
+ virtual double ConfigGetParameter(ctre::phoenix::ParamEnum param, int ordinal, int timeoutMs);
+ //------ Misc. ----------//
+ virtual int GetBaseID();
+ virtual ControlMode GetControlMode();
+ // ----- Follower ------//
+ void Follow(IMotorController & masterToFollow, ctre::phoenix::motorcontrol::FollowerType followerType);
+ virtual void Follow(IMotorController & masterToFollow);
+ virtual void ValueUpdated();
+
+ //------ RAW Sensor API ----------//
+ /**
+ * @retrieve object that can get/set individual RAW sensor values.
+ */
+ ctre::phoenix::motorcontrol::SensorCollection & GetSensorCollection();
+};
+
+} // namespace can
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/MotorControl/CAN/TalonSRX.h b/cpp/include/ctre/phoenix/MotorControl/CAN/TalonSRX.h
new file mode 100644
index 0000000..7054efa
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/CAN/TalonSRX.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "ctre/phoenix/MotorControl/CAN/BaseMotorController.h"
+#include "ctre/phoenix/MotorControl/IMotorControllerEnhanced.h"
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+namespace can {
+
+/**
+ * CTRE Talon SRX Motor Controller when used on CAN Bus.
+ */
+class TalonSRX: public virtual BaseMotorController,
+ public virtual IMotorControllerEnhanced {
+public:
+ TalonSRX(int deviceNumber);
+ virtual ~TalonSRX() {
+ }
+ TalonSRX() = delete;
+ TalonSRX(TalonSRX const&) = delete;
+ TalonSRX& operator=(TalonSRX const&) = delete;
+
+ virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackSensor(FeedbackDevice feedbackDevice, int pidIdx, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackSensor(RemoteFeedbackDevice feedbackDevice, int pidIdx, int timeoutMs);
+
+ virtual ctre::phoenix::ErrorCode SetStatusFramePeriod(StatusFrameEnhanced frame,int periodMs, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode SetStatusFramePeriod(StatusFrame frame,int periodMs, int timeoutMs);
+
+ virtual int GetStatusFramePeriod(StatusFrameEnhanced frame, int timeoutMs);
+ virtual int GetStatusFramePeriod(StatusFrame frame, int timeoutMs);
+
+ //------ Velocity measurement ----------//
+ virtual ctre::phoenix::ErrorCode ConfigVelocityMeasurementPeriod(VelocityMeasPeriod period,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigVelocityMeasurementWindow(int windowSize,
+ int timeoutMs);
+
+ //------ limit switch ----------//
+ virtual ctre::phoenix::ErrorCode ConfigForwardLimitSwitchSource(
+ LimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigReverseLimitSwitchSource(
+ LimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigForwardLimitSwitchSource(
+ RemoteLimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int deviceID, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigReverseLimitSwitchSource(
+ RemoteLimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int deviceID, int timeoutMs);
+
+ //------ Current Limit ----------//
+ virtual ctre::phoenix::ErrorCode ConfigPeakCurrentLimit(int amps, int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigPeakCurrentDuration(int milliseconds,
+ int timeoutMs);
+ virtual ctre::phoenix::ErrorCode ConfigContinuousCurrentLimit(int amps, int timeoutMs);
+ virtual void EnableCurrentLimit(bool enable);
+
+};
+// class TalonSRX
+} // namespace can
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/MotorControl/CAN/VictorSPX.h b/cpp/include/ctre/phoenix/MotorControl/CAN/VictorSPX.h
new file mode 100644
index 0000000..a209b85
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/CAN/VictorSPX.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "ctre/phoenix/MotorControl/CAN/BaseMotorController.h"
+#include "ctre/phoenix/MotorControl/IMotorController.h"
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol{
+namespace can {
+
+/**
+ * VEX Victor SPX Motor Controller when used on CAN Bus.
+ */
+class VictorSPX: public virtual ctre::phoenix::motorcontrol::can::BaseMotorController,
+ public virtual ctre::phoenix::motorcontrol::IMotorController {
+
+public:
+ VictorSPX(int deviceNumber);
+ virtual ~VictorSPX() {
+ }
+ VictorSPX(VictorSPX const&) = delete;
+ VictorSPX& operator=(VictorSPX const&) = delete;
+}; //class VictorSPX
+
+} //namespace can
+} //namespace motorcontrol
+} //namespace phoenix
+} //namespace ctre
diff --git a/cpp/include/ctre/phoenix/MotorControl/CAN/WPI_TalonSRX.h b/cpp/include/ctre/phoenix/MotorControl/CAN/WPI_TalonSRX.h
new file mode 100644
index 0000000..6174ce8
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/CAN/WPI_TalonSRX.h
@@ -0,0 +1,127 @@
+/**
+ * WPI Compliant motor controller class.
+ * WPILIB's object model requires many interfaces to be implemented to use
+ * the various features.
+ * This includes...
+ * - Software PID loops running in the robot controller
+ * - LiveWindow/Test mode features
+ * - Motor Safety (auto-turn off of motor if Set stops getting called)
+ * - Single Parameter set that assumes a simple motor controller.
+ */
+#pragma once
+
+#include "ctre/phoenix/MotorControl/CAN/TalonSRX.h"
+#include "SmartDashboard/SendableBase.h"
+#include "SmartDashboard/SendableBuilder.h"
+#include "SpeedController.h"
+#include "MotorSafety.h"
+#include "MotorSafetyHelper.h"
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+namespace can {
+
+
+class WPI_TalonSRX: public virtual TalonSRX,
+ public virtual frc::SpeedController,
+ public frc::SendableBase,
+ public frc::MotorSafety {
+public:
+ WPI_TalonSRX(int deviceNumber);
+ virtual ~WPI_TalonSRX();
+
+ WPI_TalonSRX() = delete;
+ WPI_TalonSRX(WPI_TalonSRX const&) = delete;
+ WPI_TalonSRX& operator=(WPI_TalonSRX const&) = delete;
+
+ //----------------------- set/get routines for WPILIB interfaces -------------------//
+ /**
+ * Common interface for setting the speed of a simple speed controller.
+ *
+ * @param speed The speed to set. Value should be between -1.0 and 1.0.
+ * Value is also saved for Get().
+ */
+ virtual void Set(double speed);
+ virtual void PIDWrite(double output);
+
+ /**
+ * Common interface for getting the current set speed of a speed controller.
+ *
+ * @return The current set speed. Value is between -1.0 and 1.0.
+ */
+ virtual double Get() const;
+
+ //----------------------- Intercept CTRE calls for motor safety -------------------//
+ virtual void Set(ControlMode mode, double value);
+ virtual void Set(ControlMode mode, double demand0, double demand1);
+ //----------------------- Invert routines -------------------//
+ /**
+ * Common interface for inverting direction of a speed controller.
+ *
+ * @param isInverted The state of inversion, true is inverted.
+ */
+ virtual void SetInverted(bool isInverted);
+ /**
+ * Common interface for returning the inversion state of a speed controller.
+ *
+ * @return isInverted The state of inversion, true is inverted.
+ */
+ virtual bool GetInverted() const;
+ //----------------------- turn-motor-off routines-------------------//
+ /**
+ * Common interface for disabling a motor.
+ */
+ virtual void Disable();
+ /**
+ * Common interface to stop the motor until Set is called again.
+ */
+ virtual void StopMotor();
+
+ //----------------------- Motor Safety-------------------//
+
+ /**
+ * Set the safety expiration time.
+ *
+ * @param timeout The timeout (in seconds) for this motor object
+ */
+ void SetExpiration(double timeout);
+
+ /**
+ * Return the safety expiration time.
+ *
+ * @return The expiration time value.
+ */
+ double GetExpiration() const;
+
+ /**
+ * Check if the motor is currently alive or stopped due to a timeout.
+ *
+ * @return a bool value that is true if the motor has NOT timed out and should
+ * still be running.
+ */
+ bool IsAlive() const;
+
+ /**
+ * Check if motor safety is enabled.
+ *
+ * @return True if motor safety is enforced for this object
+ */
+ bool IsSafetyEnabled() const;
+
+ void SetSafetyEnabled(bool enabled);
+
+ void GetDescription(llvm::raw_ostream& desc) const;
+
+protected:
+ virtual void InitSendable(frc::SendableBuilder& builder);
+private:
+ double _speed = 0;
+ std::string _desc;
+ frc::MotorSafetyHelper _safetyHelper;
+};
+
+} // namespace can
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/MotorControl/CAN/WPI_VictorSPX.h b/cpp/include/ctre/phoenix/MotorControl/CAN/WPI_VictorSPX.h
new file mode 100644
index 0000000..f0c8cd0
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/CAN/WPI_VictorSPX.h
@@ -0,0 +1,127 @@
+/**
+ * WPI Compliant motor controller class.
+ * WPILIB's object model requires many interfaces to be implemented to use
+ * the various features.
+ * This includes...
+ * - Software PID loops running in the robot controller
+ * - LiveWindow/Test mode features
+ * - Motor Safety (auto-turn off of motor if Set stops getting called)
+ * - Single Parameter set that assumes a simple motor controller.
+ */
+#pragma once
+
+#include "ctre/phoenix/MotorControl/CAN/VictorSPX.h"
+#include "SmartDashboard/SendableBase.h"
+#include "SmartDashboard/SendableBuilder.h"
+#include "SpeedController.h"
+#include "MotorSafety.h"
+#include "MotorSafetyHelper.h"
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+namespace can {
+
+
+class WPI_VictorSPX: public virtual VictorSPX,
+ public virtual frc::SpeedController,
+ public frc::SendableBase,
+ public frc::MotorSafety {
+public:
+ WPI_VictorSPX(int deviceNumber);
+ virtual ~WPI_VictorSPX();
+
+ WPI_VictorSPX() = delete;
+ WPI_VictorSPX(WPI_VictorSPX const&) = delete;
+ WPI_VictorSPX& operator=(WPI_VictorSPX const&) = delete;
+
+ //----------------------- set/get routines for WPILIB interfaces -------------------//
+ /**
+ * Common interface for setting the speed of a simple speed controller.
+ *
+ * @param speed The speed to set. Value should be between -1.0 and 1.0.
+ * Value is also saved for Get().
+ */
+ virtual void Set(double speed);
+ virtual void PIDWrite(double output);
+
+ /**
+ * Common interface for getting the current set speed of a speed controller.
+ *
+ * @return The current set speed. Value is between -1.0 and 1.0.
+ */
+ virtual double Get() const;
+
+ //----------------------- Intercept CTRE calls for motor safety -------------------//
+ virtual void Set(ControlMode mode, double value);
+ virtual void Set(ControlMode mode, double demand0, double demand1);
+ //----------------------- Invert routines -------------------//
+ /**
+ * Common interface for inverting direction of a speed controller.
+ *
+ * @param isInverted The state of inversion, true is inverted.
+ */
+ virtual void SetInverted(bool isInverted);
+ /**
+ * Common interface for returning the inversion state of a speed controller.
+ *
+ * @return isInverted The state of inversion, true is inverted.
+ */
+ virtual bool GetInverted() const;
+ //----------------------- turn-motor-off routines-------------------//
+ /**
+ * Common interface for disabling a motor.
+ */
+ virtual void Disable();
+ /**
+ * Common interface to stop the motor until Set is called again.
+ */
+ virtual void StopMotor();
+
+ //----------------------- Motor Safety-------------------//
+
+ /**
+ * Set the safety expiration time.
+ *
+ * @param timeout The timeout (in seconds) for this motor object
+ */
+ void SetExpiration(double timeout);
+
+ /**
+ * Return the safety expiration time.
+ *
+ * @return The expiration time value.
+ */
+ double GetExpiration() const;
+
+ /**
+ * Check if the motor is currently alive or stopped due to a timeout.
+ *
+ * @return a bool value that is true if the motor has NOT timed out and should
+ * still be running.
+ */
+ bool IsAlive() const;
+
+ /**
+ * Check if motor safety is enabled.
+ *
+ * @return True if motor safety is enforced for this object
+ */
+ bool IsSafetyEnabled() const;
+
+ void SetSafetyEnabled(bool enabled);
+
+ void GetDescription(llvm::raw_ostream& desc) const;
+
+protected:
+ virtual void InitSendable(frc::SendableBuilder& builder);
+private:
+ double _speed = 0;
+ std::string _desc;
+ frc::MotorSafetyHelper _safetyHelper;
+};
+
+} // namespace can
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/MotorControl/DeviceCatalog.h b/cpp/include/ctre/phoenix/MotorControl/DeviceCatalog.h
new file mode 100644
index 0000000..528eecd
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/DeviceCatalog.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "IMotorController.h"
+#include <vector>
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+
+class DeviceCatalog {
+public:
+ void Register(IMotorController *motorController) {
+ _mcs.push_back(motorController);
+ }
+
+ int MotorControllerCount() {
+ return _mcs.size();
+ }
+
+ IMotorController* Get(int idx) {
+ return _mcs[idx];
+ }
+
+ DeviceCatalog & GetInstance() {
+ if (!_instance)
+ _instance = new DeviceCatalog();
+ return *_instance;
+ }
+private:
+ std::vector<IMotorController*> _mcs;
+
+ static DeviceCatalog * _instance;
+};
+
+}
+} // namespace phoenix
+}
+
diff --git a/cpp/include/ctre/phoenix/MotorControl/GroupMotorControllers.h b/cpp/include/ctre/phoenix/MotorControl/GroupMotorControllers.h
new file mode 100644
index 0000000..9ab95bd
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/GroupMotorControllers.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "IMotorController.h"
+#include <vector>
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+
+class GroupMotorControllers {
+public:
+ static void Register(IMotorController *motorController);
+ static int MotorControllerCount();
+ static IMotorController* Get(int idx);
+
+private:
+ static std::vector<IMotorController*> _mcs;
+};
+
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
+
diff --git a/cpp/include/ctre/phoenix/MotorControl/IFollower.h b/cpp/include/ctre/phoenix/MotorControl/IFollower.h
new file mode 100644
index 0000000..8f52c3d
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/IFollower.h
@@ -0,0 +1,19 @@
+#pragma once
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+
+/* forward proto */
+class IMotorController;
+
+class IFollower {
+public:
+ virtual ~IFollower(){}
+ virtual void Follow(ctre::phoenix::motorcontrol::IMotorController & masterToFollow) = 0;
+ virtual void ValueUpdated()= 0;
+};
+
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/MotorControl/IMotorController.h b/cpp/include/ctre/phoenix/MotorControl/IMotorController.h
new file mode 100644
index 0000000..947022e
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/IMotorController.h
@@ -0,0 +1,205 @@
+#pragma once
+
+#include "ctre/phoenix/MotorControl/ControlMode.h"
+#include "ctre/phoenix/MotorControl/ControlFrame.h"
+#include "ctre/phoenix/MotorControl/DemandType.h"
+#include "ctre/phoenix/MotorControl/NeutralMode.h"
+#include "ctre/phoenix/MotorControl/FeedbackDevice.h"
+#include "ctre/phoenix/MotorControl/RemoteSensorSource.h"
+#include "ctre/phoenix/MotorControl/SensorTerm.h"
+#include "ctre/phoenix/MotorControl/StatusFrame.h"
+#include "ctre/phoenix/MotorControl/LimitSwitchType.h"
+#include "ctre/phoenix/MotorControl/Faults.h"
+#include "ctre/phoenix/MotorControl/StickyFaults.h"
+#include "ctre/phoenix/paramEnum.h"
+#include "ctre/phoenix/Motion/TrajectoryPoint.h"
+#include "ctre/phoenix/Motion/MotionProfileStatus.h"
+#include "ctre/phoenix/ErrorCode.h"
+#include "IFollower.h"
+/* WPILIB */
+#include "SpeedController.h"
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+
+class IMotorController: public virtual IFollower {
+public:
+ virtual ~IMotorController() {
+ }
+ //------ Set output routines. ----------//
+ virtual void Set(ControlMode Mode, double demand) = 0;
+ virtual void Set(ControlMode Mode, double demand0, double demand1) = 0;
+ virtual void Set(ControlMode mode, double demand0, DemandType demand1Type, double demand1) = 0;
+ virtual void NeutralOutput() = 0;
+ virtual void SetNeutralMode(NeutralMode neutralMode) = 0;
+
+ //------ Invert behavior ----------//
+ virtual void SetSensorPhase(bool PhaseSensor) = 0;
+ virtual void SetInverted(bool invert) = 0;
+ virtual bool GetInverted() const = 0;
+
+ //----- general output shaping ------------------//
+ virtual ErrorCode ConfigOpenloopRamp(double secondsFromNeutralToFull,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigClosedloopRamp(double secondsFromNeutralToFull,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigPeakOutputForward(double percentOut,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigPeakOutputReverse(double percentOut,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigNominalOutputForward(double percentOut,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigNominalOutputReverse(double percentOut,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigNeutralDeadband(double percentDeadband,
+ int timeoutMs) = 0;
+
+ //------ Voltage Compensation ----------//
+ virtual ErrorCode ConfigVoltageCompSaturation(double voltage,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigVoltageMeasurementFilter(int filterWindowSamples,
+ int timeoutMs) = 0;
+ virtual void EnableVoltageCompensation(bool enable) = 0;
+
+ //------ General Status ----------//
+ virtual double GetBusVoltage() = 0;
+ virtual double GetMotorOutputPercent() = 0;
+ virtual double GetMotorOutputVoltage() = 0;
+ virtual double GetOutputCurrent() = 0;
+ virtual double GetTemperature() = 0;
+
+ //------ sensor selection ----------//
+ virtual ErrorCode ConfigSelectedFeedbackSensor(
+ RemoteFeedbackDevice feedbackDevice, int pidIdx, int timeoutMs) = 0;
+ virtual ErrorCode ConfigSelectedFeedbackCoefficient(
+ double coefficient, int pidIdx, int timeoutMs) = 0;
+ virtual ErrorCode ConfigRemoteFeedbackFilter(int deviceID,
+ RemoteSensorSource remoteSensorSource, int remoteOrdinal,
+ int timeoutMs)= 0;
+ virtual ErrorCode ConfigSensorTerm(SensorTerm sensorTerm, FeedbackDevice feedbackDevice, int timeoutMs)= 0;
+
+ //------- sensor status --------- //
+ virtual int GetSelectedSensorPosition(int pidIdx) = 0;
+ virtual int GetSelectedSensorVelocity(int pidIdx) = 0;
+ virtual ErrorCode SetSelectedSensorPosition(int sensorPos, int pidIdx,
+ int timeoutMs) = 0;
+
+ //------ status frame period changes ----------//
+ virtual ErrorCode SetControlFramePeriod(ControlFrame frame,
+ int periodMs) = 0;
+ virtual ErrorCode SetStatusFramePeriod(StatusFrame frame, int periodMs,
+ int timeoutMs) = 0;
+ virtual int GetStatusFramePeriod(StatusFrame frame, int timeoutMs) = 0;
+
+ //----- velocity signal conditionaing ------//
+ /* not supported */
+
+ //------ remote limit switch ----------//
+ virtual ErrorCode ConfigForwardLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs) = 0;
+ virtual ErrorCode ConfigReverseLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs) = 0;
+ virtual void OverrideLimitSwitchesEnable(bool enable) = 0;
+
+ //------ local limit switch ----------//
+ /* not supported */
+
+ //------ soft limit ----------//
+ virtual ErrorCode ConfigForwardSoftLimitThreshold(int forwardSensorLimit,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigReverseSoftLimitThreshold(int reverseSensorLimit,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigForwardSoftLimitEnable(bool enable,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigReverseSoftLimitEnable(bool enable,
+ int timeoutMs) = 0;
+ virtual void OverrideSoftLimitsEnable(bool enable) = 0;
+
+ //------ Current Lim ----------//
+ /* not supported */
+
+ //------ Config Close loop ----------//
+ virtual ErrorCode Config_kP(int slotIdx, double value, int timeoutMs) = 0;
+ virtual ErrorCode Config_kI(int slotIdx, double value, int timeoutMs) = 0;
+ virtual ErrorCode Config_kD(int slotIdx, double value, int timeoutMs) = 0;
+ virtual ErrorCode Config_kF(int slotIdx, double value, int timeoutMs) = 0;
+ virtual ErrorCode Config_IntegralZone(int slotIdx, int izone,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigAllowableClosedloopError(int slotIdx,
+ int allowableCloseLoopError, int timeoutMs) = 0;
+ virtual ErrorCode ConfigMaxIntegralAccumulator(int slotIdx, double iaccum,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigClosedLoopPeakOutput(int slotIdx, double percentOut, int timeoutMs) = 0;
+ virtual ErrorCode ConfigClosedLoopPeriod(int slotIdx, int loopTimeMs, int timeoutMs) = 0;
+ virtual ErrorCode ConfigAuxPIDPolarity(bool invert, int timeoutMs) = 0;
+
+ //------ Close loop State ----------//
+ virtual ErrorCode SetIntegralAccumulator(double iaccum, int pidIdx,
+ int timeoutMs) = 0;
+ virtual int GetClosedLoopError(int pidIdx) = 0;
+ virtual double GetIntegralAccumulator(int pidIdx) = 0;
+ virtual double GetErrorDerivative(int pidIdx) = 0;
+
+ virtual ErrorCode SelectProfileSlot(int slotIdx, int pidIdx) = 0;
+
+ virtual int GetClosedLoopTarget(int pidIdx) = 0;
+ virtual int GetActiveTrajectoryPosition() = 0;
+ virtual int GetActiveTrajectoryVelocity() = 0;
+ virtual double GetActiveTrajectoryHeading() = 0;
+
+ //------ Motion Profile Settings used in Motion Magic ----------//
+ virtual ErrorCode ConfigMotionCruiseVelocity(int sensorUnitsPer100ms,
+ int timeoutMs) = 0;
+ virtual ErrorCode ConfigMotionAcceleration(int sensorUnitsPer100msPerSec,
+ int timeoutMs) = 0;
+
+ //------ Motion Profile Buffer ----------//
+ virtual ErrorCode ClearMotionProfileTrajectories()= 0;
+ virtual int GetMotionProfileTopLevelBufferCount()= 0;
+ virtual ErrorCode PushMotionProfileTrajectory(
+ const ctre::phoenix::motion::TrajectoryPoint & trajPt)= 0;
+ virtual bool IsMotionProfileTopLevelBufferFull()= 0;
+ virtual void ProcessMotionProfileBuffer()= 0;
+ virtual ErrorCode GetMotionProfileStatus(
+ ctre::phoenix::motion::MotionProfileStatus & statusToFill)= 0;
+ virtual ErrorCode ClearMotionProfileHasUnderrun(int timeoutMs)= 0;
+ virtual ErrorCode ChangeMotionControlFramePeriod(int periodMs)= 0;
+ virtual ErrorCode ConfigMotionProfileTrajectoryPeriod(int baseTrajDurationMs, int timeoutMs)=0;
+ //------ error ----------//
+ virtual ErrorCode GetLastError() = 0;
+
+ //------ Faults ----------//
+ virtual ErrorCode GetFaults(Faults & toFill) = 0;
+ virtual ErrorCode GetStickyFaults(StickyFaults & toFill) = 0;
+ virtual ErrorCode ClearStickyFaults(int timeoutMs) = 0;
+
+ //------ Firmware ----------//
+ virtual int GetFirmwareVersion() = 0;
+ virtual bool HasResetOccurred() = 0;
+
+ //------ Custom Persistent Params ----------//
+ virtual ErrorCode ConfigSetCustomParam(int newValue, int paramIndex,
+ int timeoutMs) = 0;
+ virtual int ConfigGetCustomParam(int paramIndex, int timeoutMs) = 0;
+
+ //------ Generic Param API, typically not used ----------//
+ virtual ErrorCode ConfigSetParameter(ParamEnum param, double value,
+ uint8_t subValue, int ordinal, int timeoutMs) = 0;
+ virtual double ConfigGetParameter(ParamEnum paramEnum, int ordinal,
+ int timeoutMs) = 0;
+
+ //------ Misc. ----------//
+ virtual int GetBaseID() = 0;
+ virtual int GetDeviceID() = 0;
+ virtual ControlMode GetControlMode() = 0;
+
+ // ----- Follower ------//
+ /* in parent interface */
+};
+
+}
+} // namespace phoenix
+}
diff --git a/cpp/include/ctre/phoenix/MotorControl/IMotorControllerEnhanced.h b/cpp/include/ctre/phoenix/MotorControl/IMotorControllerEnhanced.h
new file mode 100644
index 0000000..e5c429c
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/IMotorControllerEnhanced.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include "ctre/phoenix/MotorControl/ControlMode.h"
+#include "ctre/phoenix/MotorControl/ControlFrame.h"
+#include "ctre/phoenix/MotorControl/NeutralMode.h"
+#include "ctre/phoenix/MotorControl/FeedbackDevice.h"
+#include "ctre/phoenix/MotorControl/StatusFrame.h"
+#include "ctre/phoenix/MotorControl/LimitSwitchType.h"
+#include "ctre/phoenix/MotorControl/Faults.h"
+#include "ctre/phoenix/MotorControl/StickyFaults.h"
+#include "ctre/phoenix/paramEnum.h"
+#include "ctre/phoenix/Motion/TrajectoryPoint.h"
+#include "ctre/phoenix/Motion/MotionProfileStatus.h"
+#include "ctre/phoenix/ErrorCode.h"
+#include "IFollower.h"
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+
+class IMotorControllerEnhanced: public virtual IMotorController {
+public:
+ virtual ~IMotorControllerEnhanced() {
+ }
+
+ //------ Set output routines. ----------//
+ /* in parent */
+
+ //------ Invert behavior ----------//
+ /* in parent */
+
+ //----- general output shaping ------------------//
+ /* in parent */
+
+ //------ Voltage Compensation ----------//
+ /* in parent */
+
+ //------ General Status ----------//
+ /* in parent */
+
+ //------ sensor selection ----------//
+ /* expand the options */
+ virtual ErrorCode ConfigSelectedFeedbackSensor(
+ FeedbackDevice feedbackDevice, int pidIdx, int timeoutMs) = 0;
+ virtual ErrorCode ConfigSelectedFeedbackSensor(
+ RemoteFeedbackDevice feedbackDevice, int pidIdx, int timeoutMs) = 0;
+
+ //------- sensor status --------- //
+ /* in parent */
+
+ //------ status frame period changes ----------//
+ virtual ErrorCode SetStatusFramePeriod(StatusFrame frame, int periodMs,
+ int timeoutMs) = 0;
+ virtual ErrorCode SetStatusFramePeriod(StatusFrameEnhanced frame,
+ int periodMs, int timeoutMs) = 0;
+ virtual int GetStatusFramePeriod(StatusFrame frame, int timeoutMs) = 0;
+ virtual int GetStatusFramePeriod(StatusFrameEnhanced frame, int timeoutMs) = 0;
+
+ //----- velocity signal conditionaing ------//
+ virtual ErrorCode ConfigVelocityMeasurementPeriod(VelocityMeasPeriod period,
+ int timeoutMs)= 0;
+ virtual ErrorCode ConfigVelocityMeasurementWindow(int windowSize,
+ int timeoutMs)= 0;
+
+ //------ remote limit switch ----------//
+ virtual ErrorCode ConfigForwardLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs) = 0;
+ virtual ErrorCode ConfigReverseLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs) = 0;
+
+ //------ local limit switch ----------//
+ virtual ErrorCode ConfigForwardLimitSwitchSource(LimitSwitchSource type,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs)= 0;
+ virtual ErrorCode ConfigReverseLimitSwitchSource(LimitSwitchSource type,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs)= 0;
+
+ //------ soft limit ----------//
+ /* in parent */
+
+ //------ Current Lim ----------//
+ virtual ErrorCode ConfigPeakCurrentLimit(int amps, int timeoutMs)= 0;
+ virtual ErrorCode ConfigPeakCurrentDuration(int milliseconds,
+ int timeoutMs)= 0;
+ virtual ErrorCode ConfigContinuousCurrentLimit(int amps, int timeoutMs)= 0;
+ virtual void EnableCurrentLimit(bool enable)= 0;
+
+ //------ General Close loop ----------//
+ /* in parent */
+
+ //------ Motion Profile Settings used in Motion Magic and Motion Profile ----------//
+ /* in parent */
+
+ //------ Motion Profile Buffer ----------//
+ /* in parent */
+
+ //------ error ----------//
+ /* in parent */
+
+ //------ Faults ----------//
+ /* in parent */
+
+ //------ Firmware ----------//
+ /* in parent */
+
+ //------ Custom Persistent Params ----------//
+ /* in parent */
+
+ //------ Generic Param API, typically not used ----------//
+ /* in parent */
+
+ //------ Misc. ----------//
+ /* in parent */
+
+}; // class IMotorControllerEnhanced
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/MotorControl/SensorCollection.h b/cpp/include/ctre/phoenix/MotorControl/SensorCollection.h
new file mode 100644
index 0000000..63b5894
--- /dev/null
+++ b/cpp/include/ctre/phoenix/MotorControl/SensorCollection.h
@@ -0,0 +1,197 @@
+#pragma once
+
+#include "ctre/phoenix/ErrorCode.h"
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+namespace can {
+class BaseMotorController;
+}
+}
+}
+}
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+
+class SensorCollection {
+public:
+
+ /**
+ * Get the position of whatever is in the analog pin of the Talon, regardless of
+ * whether it is actually being used for feedback.
+ *
+ * @return the 24bit analog value. The bottom ten bits is the ADC (0 - 1023)
+ * on the analog pin of the Talon. The upper 14 bits tracks the overflows and underflows
+ * (continuous sensor).
+ */
+
+ int GetAnalogIn();
+
+ /**
+ * Sets analog position.
+ *
+ * @param newPosition The new position.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ *
+ * @return an ErrorCode.
+ */
+
+ ErrorCode SetAnalogPosition(int newPosition, int timeoutMs);
+
+ /**
+ * Get the position of whatever is in the analog pin of the Talon, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the ADC (0 - 1023) on analog pin of the Talon.
+ */
+
+ int GetAnalogInRaw();
+
+ /**
+ * Get the velocity of whatever is in the analog pin of the Talon, regardless of
+ * whether it is actually being used for feedback.
+ *
+ * @return the speed in units per 100ms where 1024 units is one rotation.
+ */
+
+ int GetAnalogInVel();
+
+ /**
+ * Get the quadrature position of the Talon, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the quadrature position.
+ */
+
+ int GetQuadraturePosition();
+
+ /**
+ * Change the quadrature reported position. Typically this is used to "zero" the
+ * sensor. This only works with Quadrature sensor. To set the selected sensor position
+ * regardless of what type it is, see SetSelectedSensorPosition in the motor controller class.
+ *
+ * @param newPosition The position value to apply to the sensor.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ *
+ * @return error code.
+ */
+
+ ErrorCode SetQuadraturePosition(int newPosition, int timeoutMs);
+
+ /**
+ * Get the quadrature velocity, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the quadrature velocity in units per 100ms.
+ */
+
+ int GetQuadratureVelocity();
+
+ /**
+ * Gets pulse width position, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the pulse width position.
+ */
+
+ int GetPulseWidthPosition();
+
+ /**
+ * Sets pulse width position.
+ *
+ * @param newPosition The position value to apply to the sensor.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ *
+ * @return an ErrErrorCode
+ */
+ ErrorCode SetPulseWidthPosition(int newPosition, int timeoutMs);
+
+ /**
+ * Gets pulse width velocity, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the pulse width velocity in units per 100ms (where 4096 units is 1 rotation).
+ */
+
+ int GetPulseWidthVelocity();
+
+ /**
+ * Gets pulse width rise to fall time.
+ *
+ * @return the pulse width rise to fall time in microseconds.
+ */
+
+ int GetPulseWidthRiseToFallUs();
+
+ /**
+ * Gets pulse width rise to rise time.
+ *
+ * @return the pulse width rise to rise time in microseconds.
+ */
+
+ int GetPulseWidthRiseToRiseUs();
+
+ /**
+ * Gets pin state quad a.
+ *
+ * @return the pin state of quad a (1 if asserted, 0 if not asserted).
+ */
+
+ int GetPinStateQuadA();
+
+ /**
+ * Gets pin state quad b.
+ *
+ * @return Digital level of QUADB pin (1 if asserted, 0 if not asserted).
+ */
+
+ int GetPinStateQuadB();
+
+ /**
+ * Gets pin state quad index.
+ *
+ * @return Digital level of QUAD Index pin (1 if asserted, 0 if not asserted).
+ */
+
+ int GetPinStateQuadIdx();
+
+ /**
+ * Is forward limit switch closed.
+ *
+ * @return '1' iff forward limit switch is closed, 0 iff switch is open. This function works
+ * regardless if limit switch feature is enabled.
+ */
+
+ int IsFwdLimitSwitchClosed();
+
+ /**
+ * Is reverse limit switch closed.
+ *
+ * @return '1' iff reverse limit switch is closed, 0 iff switch is open. This function works
+ * regardless if limit switch feature is enabled.
+ */
+
+ int IsRevLimitSwitchClosed();
+
+private:
+ SensorCollection(void * handle);
+ friend class ctre::phoenix::motorcontrol::can::BaseMotorController;
+ void* _handle;
+
+};
+
+} // namespace motorcontrol
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/RCRadio3Ch.h b/cpp/include/ctre/phoenix/RCRadio3Ch.h
new file mode 100644
index 0000000..aaea7b4
--- /dev/null
+++ b/cpp/include/ctre/phoenix/RCRadio3Ch.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <vector>
+#include "ctre/phoenix/CANifier.h"
+#include "ctre/phoenix/Tasking/IProcessable.h"
+
+namespace ctre{
+namespace phoenix {
+
+class RCRadio3Ch : public ctre::phoenix::tasking::IProcessable{
+public:
+ enum Channel{
+ Channel1,
+ Channel2,
+ Channel3,
+ };
+ enum Status{
+ LossOfCAN,
+ LossOfPwm,
+ Okay,
+ };
+ Status CurrentStatus = Status::Okay;
+
+ RCRadio3Ch(ctre::phoenix::CANifier *canifier);
+ float GetDutyCycleUs(Channel channel);
+ float GetDutyCyclePerc(Channel channel);
+ bool GetSwitchValue(Channel channel);
+ float GetPeriodUs(Channel channel);
+
+ //ILoopable
+ void Process();
+
+private:
+ int _errorCodes[4];
+ ctre::phoenix::CANifier *_canifier;
+
+
+ //This is only a 2d array??
+ double _dutyCycleAndPeriods[4][2] =
+ {
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ };
+ double Interpolate(std::vector<double> &xData, std::vector<double> &yData, double x, bool extrapolate);
+};
+
+}}
diff --git a/cpp/include/ctre/phoenix/Sensors/PigeonIMU.h b/cpp/include/ctre/phoenix/Sensors/PigeonIMU.h
new file mode 100644
index 0000000..a360f74
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Sensors/PigeonIMU.h
@@ -0,0 +1,303 @@
+/*
+ * Software License Agreement
+ *
+ * Copyright (C) Cross The Road Electronics. All rights
+ * reserved.
+ *
+ * Cross The Road Electronics (CTRE) licenses to you the right to
+ * use, publish, and distribute copies of CRF (Cross The Road) firmware files (*.crf) and Software
+ * API Libraries ONLY when in use with Cross The Road Electronics hardware products.
+ *
+ * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
+ * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * CROSS THE ROAD ELECTRONICS BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
+ * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
+ * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
+ * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
+ * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE
+ */
+
+#pragma once
+
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+#include <string>
+#include "ctre/phoenix/LowLevel/CANBusAddressable.h"
+#include "ctre/phoenix/paramEnum.h"
+#include "ctre/phoenix/ErrorCode.h"
+#include "ctre/phoenix/Sensors/PigeonIMU_ControlFrame.h"
+#include "ctre/phoenix/Sensors/PigeonIMU_Faults.h"
+#include "ctre/phoenix/Sensors/PigeonIMU_StatusFrame.h"
+#include "ctre/phoenix/Sensors/PigeonIMU_StickyFaults.h"
+
+/* forward prototype */
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+namespace can {
+class TalonSRX;
+}
+}
+}
+}
+
+namespace ctre {
+namespace phoenix {
+namespace sensors {
+/**
+ * Pigeon IMU Class.
+ * Class supports communicating over CANbus and over ribbon-cable (CAN Talon SRX).
+ */
+class PigeonIMU: public CANBusAddressable {
+public:
+ /** Data object for holding fusion information. */
+ struct FusionStatus {
+ double heading;
+ bool bIsValid;
+ bool bIsFusing;
+ std::string description;
+ /**
+ * Same as GetLastError()
+ */
+ int lastError;
+ };
+ /** Various calibration modes supported by Pigeon. */
+ enum CalibrationMode {
+ BootTareGyroAccel = 0,
+ Temperature = 1,
+ Magnetometer12Pt = 2,
+ Magnetometer360 = 3,
+ Accelerometer = 5,
+ };
+ /** Overall state of the Pigeon. */
+ enum PigeonState {
+ NoComm, Initializing, Ready, UserCalibration,
+ };
+ /**
+ * Data object for status on current calibration and general status.
+ *
+ * Pigeon has many calibration modes supported for a variety of uses.
+ * The modes generally collects and saves persistently information that makes
+ * the Pigeon signals more accurate. This includes collecting temperature, gyro, accelerometer,
+ * and compass information.
+ *
+ * For FRC use-cases, typically compass and temperature calibration is not required.
+ *
+ * Additionally when motion driver software in the Pigeon boots, it will perform a fast boot calibration
+ * to initially bias gyro and setup accelerometer.
+ *
+ * These modes can be enabled with the EnterCalibration mode.
+ *
+ * When a calibration mode is entered, caller can expect...
+ *
+ * - PigeonState to reset to Initializing and bCalIsBooting is set to true. Pigeon LEDs will blink the boot pattern.
+ * This is similar to the normal boot cal, however it can an additional ~30 seconds since calibration generally
+ * requires more information.
+ * currentMode will reflect the user's selected calibration mode.
+ *
+ * - PigeonState will eventually settle to UserCalibration and Pigeon LEDs will show cal specific blink patterns.
+ * bCalIsBooting is now false.
+ *
+ * - Follow the instructions in the Pigeon User Manual to meet the calibration specific requirements.
+ * When finished calibrationError will update with the result.
+ * Pigeon will solid-fill LEDs with red (for failure) or green (for success) for ~5 seconds.
+ * Pigeon then perform boot-cal to cleanly apply the newly saved calibration data.
+ */
+ struct GeneralStatus {
+ /**
+ * The current state of the motion driver. This reflects if the sensor signals are accurate.
+ * Most calibration modes will force Pigeon to reinit the motion driver.
+ */
+ PigeonIMU::PigeonState state;
+ /**
+ * The currently applied calibration mode if state is in UserCalibration or if bCalIsBooting is true.
+ * Otherwise it holds the last selected calibration mode (when calibrationError was updated).
+ */
+ PigeonIMU::CalibrationMode currentMode;
+ /**
+ * The error code for the last calibration mode.
+ * Zero represents a successful cal (with solid green LEDs at end of cal)
+ * and nonzero is a failed calibration (with solid red LEDs at end of cal).
+ * Different calibration
+ */
+ int calibrationError;
+ /**
+ * After caller requests a calibration mode, pigeon will perform a boot-cal before
+ * entering the requested mode. During this period, this flag is set to true.
+ */
+ bool bCalIsBooting;
+ /**
+ * general string description of current status
+ */
+ std::string description;
+ /**
+ * Temperature in Celsius
+ */
+ double tempC;
+ /**
+ * Number of seconds Pigeon has been up (since boot).
+ * This register is reset on power boot or processor reset.
+ * Register is capped at 255 seconds with no wrap around.
+ */
+ int upTimeSec;
+ /**
+ * Number of times the Pigeon has automatically rebiased the gyro.
+ * This counter overflows from 15 -> 0 with no cap.
+ */
+ int noMotionBiasCount;
+ /**
+ * Number of times the Pigeon has temperature compensated the various signals.
+ * This counter overflows from 15 -> 0 with no cap.
+ */
+ int tempCompensationCount;
+ /**
+ * Same as GetLastError()
+ */
+ int lastError;
+ };
+
+ PigeonIMU(int deviceNumber);
+ PigeonIMU(ctre::phoenix::motorcontrol::can::TalonSRX * talonSrx);
+
+ int SetYaw(double angleDeg, int timeoutMs);
+ int AddYaw(double angleDeg, int timeoutMs);
+ int SetYawToCompass(int timeoutMs);
+
+ int SetFusedHeading(double angleDeg, int timeoutMs);
+ int AddFusedHeading(double angleDeg, int timeoutMs);
+ int SetFusedHeadingToCompass(int timeoutMs);
+ int SetAccumZAngle(double angleDeg, int timeoutMs);
+
+ int ConfigTemperatureCompensationEnable(bool bTempCompEnable,
+ int timeoutMs);
+
+ int SetCompassDeclination(double angleDegOffset, int timeoutMs);
+ int SetCompassAngle(double angleDeg, int timeoutMs);
+
+ int EnterCalibrationMode(CalibrationMode calMode, int timeoutMs);
+ int GetGeneralStatus(PigeonIMU::GeneralStatus & genStatusToFill);
+ int GetLastError();
+ int Get6dQuaternion(double wxyz[4]);
+ int GetYawPitchRoll(double ypr[3]);
+ int GetAccumGyro(double xyz_deg[3]);
+ double GetAbsoluteCompassHeading();
+ double GetCompassHeading();
+ double GetCompassFieldStrength();
+ double GetTemp();
+ PigeonState GetState();
+ uint32_t GetUpTime();
+ int GetRawMagnetometer(int16_t rm_xyz[3]);
+
+ int GetBiasedMagnetometer(int16_t bm_xyz[3]);
+ int GetBiasedAccelerometer(int16_t ba_xyz[3]);
+ int GetRawGyro(double xyz_dps[3]);
+ int GetAccelerometerAngles(double tiltAngles[3]);
+ /**
+ * @param status object reference to fill with fusion status flags.
+ * @return The fused heading in degrees.
+ */
+ double GetFusedHeading(FusionStatus & status);
+ /**
+ * @return The fused heading in degrees.
+ */
+ double GetFusedHeading();
+ uint32_t GetResetCount();
+ uint32_t GetResetFlags();
+ uint32_t GetFirmVers();
+
+ bool HasResetOccurred();
+
+ static std::string ToString(PigeonIMU::PigeonState state);
+ static std::string ToString(CalibrationMode cm);
+
+ ErrorCode ConfigSetCustomParam(int newValue, int paramIndex, int timeoutMs);
+ int ConfigGetCustomParam(int paramIndex, int timeoutMs);
+ ErrorCode ConfigSetParameter(ParamEnum param, double value,
+ uint8_t subValue, int ordinal, int timeoutMs);
+ double ConfigGetParameter(ctre::phoenix::ParamEnum param, int ordinal, int timeoutMs);
+
+ ErrorCode SetStatusFramePeriod(PigeonIMU_StatusFrame statusFrame, int periodMs,
+ int timeoutMs);
+
+ /**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+ * Timeout value in ms. @see #ConfigOpenLoopRamp
+ * @return Period of the given status frame.
+ */
+ int GetStatusFramePeriod(PigeonIMU_StatusFrame frame,
+ int timeoutMs) ;
+ ErrorCode SetControlFramePeriod(PigeonIMU_ControlFrame frame,
+ int periodMs);
+ int GetFirmwareVersion() ;
+ ErrorCode GetFaults(PigeonIMU_Faults & toFill) ;
+ ErrorCode GetStickyFaults(PigeonIMU_StickyFaults & toFill);
+ ErrorCode ClearStickyFaults(int timeoutMs);
+
+
+
+
+ void* GetLowLevelHandle() {
+ return _handle;
+ }
+private:
+ /** firmware state reported over CAN */
+ enum MotionDriverState {
+ Init0 = 0,
+ WaitForPowerOff = 1,
+ ConfigAg = 2,
+ SelfTestAg = 3,
+ StartDMP = 4,
+ ConfigCompass_0 = 5,
+ ConfigCompass_1 = 6,
+ ConfigCompass_2 = 7,
+ ConfigCompass_3 = 8,
+ ConfigCompass_4 = 9,
+ ConfigCompass_5 = 10,
+ SelfTestCompass = 11,
+ WaitForGyroStable = 12,
+ AdditionalAccelAdjust = 13,
+ Idle = 14,
+ Calibration = 15,
+ LedInstrum = 16,
+ Error = 31,
+ };
+ /** sub command for the various Set param enums */
+ enum TareType {
+ SetValue = 0x00, AddOffset = 0x01, MatchCompass = 0x02, SetOffset = 0xFF,
+ };
+ /** data storage for reset signals */
+ struct ResetStats {
+ int32_t resetCount;
+ int32_t resetFlags;
+ int32_t firmVers;
+ bool hasReset;
+ };
+ ResetStats _resetStats = { 0, 0, 0, false };
+
+ /** Portion of the arbID for all status and control frames. */
+ void* _handle;
+ uint32_t _deviceNumber;
+ uint32_t _usageHist = 0;
+ uint64_t _cache;
+ uint32_t _len;
+
+ /** overall threshold for when frame data is too old */
+ const uint32_t EXPECTED_RESPONSE_TIMEOUT_MS = (200);
+
+ int PrivateSetParameter(ParamEnum paramEnum, TareType tareType,
+ double angleDeg, int timeoutMs);
+
+ PigeonIMU::PigeonState GetState(int errCode, const uint64_t & statusFrame);
+ double GetTemp(const uint64_t & statusFrame);
+};
+} // namespace signals
+} // namespace phoenix
+} // namespace ctre
+#endif // CTR_EXCLUDE_WPILIB_CLASSES
diff --git a/cpp/include/ctre/phoenix/Signals/IInvertable.h b/cpp/include/ctre/phoenix/Signals/IInvertable.h
new file mode 100644
index 0000000..b964b1b
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Signals/IInvertable.h
@@ -0,0 +1,16 @@
+#pragma once
+
+namespace ctre {
+namespace phoenix {
+namespace signals {
+
+class IInvertable {
+public:
+ virtual ~IInvertable(){}
+ virtual void SetInverted(bool invert) = 0;
+ virtual bool GetInverted() const = 0;
+};
+
+} // namespace Signals
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/Signals/IOutputSignal.h b/cpp/include/ctre/phoenix/Signals/IOutputSignal.h
new file mode 100644
index 0000000..ff909fe
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Signals/IOutputSignal.h
@@ -0,0 +1,15 @@
+#pragma once
+
+namespace ctre {
+namespace phoenix {
+namespace signals {
+
+class IOutputSignal {
+public:
+ virtual ~IOutputSignal(){}
+ virtual void Set(double value) = 0;
+};
+
+} // namespace Signals
+} // namespace phoenix
+} // namespace ctre
diff --git a/cpp/include/ctre/phoenix/Signals/MovingAverage.h b/cpp/include/ctre/phoenix/Signals/MovingAverage.h
new file mode 100644
index 0000000..862b3d5
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Signals/MovingAverage.h
@@ -0,0 +1,92 @@
+/*
+ * Software License Agreement
+ *
+ * Copyright (C) Cross The Road Electronics. All rights
+ * reserved.
+ *
+ * Cross The Road Electronics (CTRE) licenses to you the right to
+ * use, publish, and distribute copies of CRF (Cross The Road) firmware files (*.crf) and Software
+ * API Libraries ONLY when in use with Cross The Road Electronics hardware products.
+ *
+ * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
+ * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * CROSS THE ROAD ELECTRONICS BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
+ * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
+ * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
+ * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
+ * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE
+ */
+
+namespace ctre {
+namespace phoenix {
+namespace signals {
+
+class MovingAverage {
+private:
+
+ int _in; //!< head ptr for ringbuffer
+ int _ou; //!< tail ptr for ringbuffer
+ int _cnt; //!< number of element in ring buffer
+ int _cap; //!< capacity of ring buffer
+ float _sum; //!< sum of all elements in ring buffer
+ float * _d; //!< ring buffer
+public:
+ MovingAverage(int capacity) {
+ _cap = capacity;
+ _d = new float[_cap];
+ Clear();
+ }
+ float Process(float input) {
+ Push(input);
+ return _sum / (float) _cnt;
+ }
+ void Clear() {
+ _in = 0;
+ _ou = 0;
+ _cnt = 0;
+
+ _sum = 0;
+ }
+ void Push(float d) {
+ /* process it */
+ _sum += d;
+
+ /* if full, pop one */
+ if (_cnt >= _cap)
+ Pop();
+
+ /* push new one */
+ _d[_in] = d;
+ if (++_in >= _cap)
+ _in = 0;
+ ++_cnt;
+ }
+ void Pop() {
+ /* get the oldest */
+ float d = _d[_ou];
+
+ /* process it */
+ _sum -= d;
+
+ /* pop it */
+ if (++_ou >= _cap)
+ _ou = 0;
+ --_cnt;
+ }
+ //-------------- Properties --------------//
+ float GetSum() {
+ return _sum;
+ }
+ int GetCount() {
+ return _cnt;
+ }
+};
+
+} // namespace Signals
+} // namespace phoenix
+} // namespace ctre
+
diff --git a/cpp/include/ctre/phoenix/Stopwatch.h b/cpp/include/ctre/phoenix/Stopwatch.h
new file mode 100644
index 0000000..eb0c9ff
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Stopwatch.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <time.h>
+
+namespace ctre {
+namespace phoenix {
+
+class Stopwatch {
+public:
+ void Start();
+ unsigned int DurationMs();
+ float Duration();
+
+private:
+ unsigned long _t0 = 0;
+ unsigned long _t1 = 0;
+ float _scalar = 0.001f / CLOCKS_PER_SEC;
+};
+
+}}
diff --git a/cpp/include/ctre/phoenix/Tasking/ButtonMonitor.h b/cpp/include/ctre/phoenix/Tasking/ButtonMonitor.h
new file mode 100644
index 0000000..2578d35
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Tasking/ButtonMonitor.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "ctre/phoenix/Tasking/ILoopable.h"
+#include "ctre/phoenix/Tasking/IProcessable.h"
+#include <functional>
+
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+
+/* forward proto's */
+namespace frc {
+ class GenericHID;
+}
+
+namespace ctre {
+namespace phoenix {
+namespace tasking {
+
+class ButtonMonitor: public IProcessable, public ILoopable {
+public:
+
+ class IButtonPressEventHandler {
+ public:
+ virtual ~IButtonPressEventHandler(){}
+ virtual void OnButtonPress(int idx, bool isDown) = 0;
+ };
+
+ ButtonMonitor(frc::GenericHID * controller, int buttonIndex, IButtonPressEventHandler * ButtonPressEventHandler);
+ ButtonMonitor(const ButtonMonitor & rhs);
+ virtual ~ButtonMonitor() { }
+
+ /* IProcessable */
+ virtual void Process();
+
+ /* ILoopable */
+ virtual void OnStart();
+ virtual void OnLoop();
+ virtual bool IsDone();
+ virtual void OnStop();
+
+private:
+ frc::GenericHID * _gameCntrlr;
+ int _btnIdx;
+ IButtonPressEventHandler * _handler;
+ bool _isDown = false;
+};
+}
+}
+}
+#endif // CTR_EXCLUDE_WPILIB_CLASSES
diff --git a/cpp/include/ctre/phoenix/Tasking/ILoopable.h b/cpp/include/ctre/phoenix/Tasking/ILoopable.h
new file mode 100644
index 0000000..db1dd50
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Tasking/ILoopable.h
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace ctre { namespace phoenix { namespace tasking {
+
+class ILoopable{
+public:
+ virtual ~ILoopable(){}
+ virtual void OnStart() = 0;
+ virtual void OnLoop() = 0;
+ virtual bool IsDone() = 0;
+ virtual void OnStop() = 0;
+};
+}}}
diff --git a/cpp/include/ctre/phoenix/Tasking/IProcessable.h b/cpp/include/ctre/phoenix/Tasking/IProcessable.h
new file mode 100644
index 0000000..0e93180
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Tasking/IProcessable.h
@@ -0,0 +1,9 @@
+#pragma once
+namespace ctre { namespace phoenix { namespace tasking{
+
+class IProcessable {
+public:
+ virtual ~IProcessable(){}
+ virtual void Process() = 0;
+};
+}}}
diff --git a/cpp/include/ctre/phoenix/Tasking/Schedulers/ConcurrentScheduler.h b/cpp/include/ctre/phoenix/Tasking/Schedulers/ConcurrentScheduler.h
new file mode 100644
index 0000000..7481d29
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Tasking/Schedulers/ConcurrentScheduler.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <vector>
+#include "ctre/phoenix/Tasking/ILoopable.h"
+#include "ctre/phoenix/Tasking/IProcessable.h"
+
+namespace ctre {
+namespace phoenix {
+namespace tasking {
+namespace schedulers {
+
+class ConcurrentScheduler: public ILoopable, public IProcessable {
+public:
+ std::vector<ILoopable*> _loops;
+ std::vector<bool> _enabs;
+
+ ConcurrentScheduler();
+ virtual ~ConcurrentScheduler();
+ void Add(ILoopable *aLoop, bool enable = true);
+ void RemoveAll();
+ void Start(ILoopable *toStart);
+ void Stop(ILoopable *toStop);
+ void StartAll();
+ void StopAll();
+
+ //IProcessable
+ void Process();
+
+ //ILoopable
+ bool Iterated();
+ void OnStart();
+ void OnLoop();
+ void OnStop();
+ bool IsDone();
+};
+}
+}
+}
+}
diff --git a/cpp/include/ctre/phoenix/Tasking/Schedulers/SequentialScheduler.h b/cpp/include/ctre/phoenix/Tasking/Schedulers/SequentialScheduler.h
new file mode 100644
index 0000000..f550b31
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Tasking/Schedulers/SequentialScheduler.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <vector>
+#include "ctre/phoenix/Tasking/ILoopable.h"
+#include "ctre/phoenix/Tasking/IProcessable.h"
+
+namespace ctre { namespace phoenix { namespace tasking { namespace schedulers {
+
+class SequentialScheduler: public ILoopable, public IProcessable{
+public:
+ bool _running = false;
+ std::vector<ILoopable*> _loops;
+ unsigned int _idx = 0;
+ bool _iterated = false;
+
+ SequentialScheduler();
+ virtual ~SequentialScheduler();
+
+ void Add(ILoopable *aLoop);
+ ILoopable * GetCurrent();
+ void RemoveAll();
+ void Start();
+ void Stop();
+
+ //IProcessable
+ void Process();
+
+ //ILoopable
+ void OnStart();
+ void OnLoop();
+ void OnStop();
+ bool IsDone();
+};
+}}}}
diff --git a/cpp/include/ctre/phoenix/Utilities.h b/cpp/include/ctre/phoenix/Utilities.h
new file mode 100644
index 0000000..ce591c8
--- /dev/null
+++ b/cpp/include/ctre/phoenix/Utilities.h
@@ -0,0 +1,20 @@
+#pragma once
+
+namespace ctre {
+namespace phoenix {
+
+class Utilities {
+public:
+ static float abs(float f);
+ static float bound(float value, float capValue = 1);
+ static float cap(float value, float peak);
+ static void Deadband(float &value, float deadband = -.10);
+ static bool IsWithin(float value, float compareTo, float allowDelta);
+ static int SmallerOf(int value_1, int value_2);
+ static void Split_1(float forward, float turn, float *left, float *right);
+ static void Split_2(float left, float right, float *forward, float *turn);
+private:
+ static bool Contains(char array[], char item);
+};
+
+}}
diff --git a/cpp/src/CANifier.cpp b/cpp/src/CANifier.cpp
new file mode 100644
index 0000000..7b18849
--- /dev/null
+++ b/cpp/src/CANifier.cpp
@@ -0,0 +1,454 @@
+/*
+ * Software License Agreement
+ *
+ * Copyright (C) Cross The Road Electronics. All rights
+ * reserved.
+ *
+ * Cross The Road Electronics (CTRE) licenses to you the right to
+ * use, publish, and distribute copies of CRF (Cross The Road) firmware files (*.crf) and Software
+ * API Libraries ONLY when in use with Cross The Road Electronics hardware products.
+ *
+ * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
+ * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * CROSS THE ROAD ELECTRONICS BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
+ * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
+ * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
+ * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
+ * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE
+ */
+
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+#include "ctre/phoenix/CANifier.h"
+#include "ctre/phoenix/CCI/CANifier_CCI.h"
+#include "ctre/phoenix/CTRLogger.h"
+#include "HAL/HAL.h"
+
+namespace ctre {
+namespace phoenix {
+ /**
+ * Constructor.
+ * @param deviceNumber The CAN Device ID of the CANifier.
+ */
+CANifier::CANifier(int deviceNumber): CANBusAddressable(deviceNumber)
+{
+ m_handle = c_CANifier_Create1(deviceNumber);
+ HAL_Report(HALUsageReporting::kResourceType_CANifier, deviceNumber + 1);
+}
+
+/**
+ * Sets the LED Output
+ * @param percentOutput Output duty cycle expressed as percentage.
+ * @param ledChannel Channel to set the output of.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::SetLEDOutput(double percentOutput, LEDChannel ledChannel) {
+ /* convert float to integral fixed pt */
+ if (percentOutput > 1) {
+ percentOutput = 1;
+ }
+ if (percentOutput < 0) {
+ percentOutput = 0;
+ }
+ int dutyCycle = (int) (percentOutput * 1023); // [0,1023]
+
+ return c_CANifier_SetLEDOutput(m_handle, dutyCycle, ledChannel);
+}
+
+/**
+ * Sets the output of a General Pin
+ * @param outputPin The pin to use as output.
+ * @param outputValue The desired output state.
+ * @param outputEnable Whether this pin is an output. "True" enables output.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::SetGeneralOutput(GeneralPin outputPin, bool outputValue,
+ bool outputEnable) {
+ return c_CANifier_SetGeneralOutput(m_handle, outputPin, outputValue,
+ outputEnable);
+}
+
+/**
+ * Sets the output of all General Pin
+ * @param outputBits A bit mask of all the output states. LSB->MSB is in the order of the #GeneralPin enum.
+ * @param isOutputBits A boolean bit mask that sets the pins to be outputs or inputs. A bit of 1 enables output.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::SetGeneralOutputs(int outputBits, int isOutputBits) {
+ return c_CANifier_SetGeneralOutputs(m_handle, outputBits, isOutputBits);
+}
+
+/**
+ * Sets the output of all General Pin
+ * @param allPins A structure to fill with the current state of all pins.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::GetGeneralInputs(CANifier::PinValues &allPins) {
+ ErrorCode err = c_CANifier_GetGeneralInputs(m_handle, _tempPins, sizeof(_tempPins));
+ allPins.LIMF = _tempPins[LIMF];
+ allPins.LIMR = _tempPins[LIMR];
+ allPins.QUAD_A = _tempPins[QUAD_A];
+ allPins.QUAD_B = _tempPins[QUAD_B];
+ allPins.QUAD_IDX = _tempPins[QUAD_IDX];
+ allPins.SCL = _tempPins[SCL];
+ allPins.SDA = _tempPins[SDA];
+ allPins.SPI_CLK_PWM0 = _tempPins[SPI_CLK_PWM0P];
+ allPins.SPI_MOSI_PWM1 = _tempPins[SPI_MOSI_PWM1P];
+ allPins.SPI_MISO_PWM2 = _tempPins[SPI_MISO_PWM2P];
+ allPins.SPI_CS_PWM3 = _tempPins[SPI_CS];
+ return err;
+}
+
+/**
+ * Gets the state of the specified pin
+ * @param inputPin The index of the pin.
+ * @return The state of the pin.
+ */
+bool CANifier::GetGeneralInput(GeneralPin inputPin) {
+ bool retval = false;
+ (void)c_CANifier_GetGeneralInput(m_handle, inputPin, &retval);
+ return retval;
+}
+
+/**
+ * Gets the position of the quadrature encoder.
+ * @return The Position of the encoder.
+ */
+int CANifier::GetQuadraturePosition() {
+ int retval = 0;
+ (void)c_CANifier_GetQuadraturePosition(m_handle, &retval);
+ return retval;
+}
+/**
+ * Sets the position of the quadrature encoder.
+ * @param newPosition
+ * @return ErrorCode generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::SetQuadraturePosition(int newPosition, int timeoutMs) {
+ return c_CANifier_SetQuadraturePosition(m_handle, newPosition, timeoutMs);
+}
+/**
+ * Gets the velocity of the quadrature encoder.
+ * @return The Velocity of the encoder.
+ */
+int CANifier::GetQuadratureVelocity() {
+ int retval = 0;
+ (void)c_CANifier_GetQuadratureVelocity(m_handle, &retval);
+ return retval;
+}
+/**
+ * Configures the period of each velocity sample.
+ * Every 1ms a position value is sampled, and the delta between that sample
+ * and the position sampled kPeriod ms ago is inserted into a filter.
+ * kPeriod is configured with this function.
+ *
+ * @param period
+ * Desired period for the velocity measurement. @see
+ * #VelocityMeasPeriod
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::ConfigVelocityMeasurementPeriod(CANifierVelocityMeasPeriod period, int timeoutMs) {
+ return c_CANifier_ConfigVelocityMeasurementPeriod(m_handle, period, timeoutMs);
+}
+/**
+ * Sets the number of velocity samples used in the rolling average velocity
+ * measurement.
+ *
+ * @param windowSize
+ * Number of samples in the rolling average of velocity
+ * measurement. Valid values are 1,2,4,8,16,32. If another
+ * value is specified, it will truncate to nearest support value.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::ConfigVelocityMeasurementWindow(int windowSize, int timeoutMs) {
+ return c_CANifier_ConfigVelocityMeasurementWindow(m_handle, windowSize, timeoutMs);
+}
+/**
+ * Gets the bus voltage seen by the device.
+ *
+ * @return The bus voltage value (in volts).
+ */
+double CANifier::GetBusVoltage() {
+ double param = 0;
+ c_CANifier_GetBusVoltage(m_handle, ¶m);
+ return param;
+}
+
+/**
+ * Call GetLastError() generated by this object.
+ * Not all functions return an error code but can
+ * potentially report errors.
+ *
+ * This function can be used to retrieve those error codes.
+ *
+ * @return The last ErrorCode generated.
+ */
+ErrorCode CANifier::GetLastError() {
+ return c_CANifier_GetLastError(m_handle);
+}
+
+/**
+ * Sets the PWM Output
+ * Currently supports PWM 0, PWM 1, and PWM 2
+ * @param pwmChannel Index of the PWM channel to output.
+ * @param dutyCycle Duty Cycle (0 to 1) to output. Default period of the signal is 4.2 ms.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::SetPWMOutput(int pwmChannel, double dutyCycle) {
+ if (dutyCycle < 0) {
+ dutyCycle = 0;
+ } else if (dutyCycle > 1) {
+ dutyCycle = 1;
+ }
+ if (pwmChannel < 0) {
+ pwmChannel = 0;
+ }
+
+ int dutyCyc10bit = (int) (1023 * dutyCycle);
+
+ return c_CANifier_SetPWMOutput(m_handle, (int) pwmChannel,
+ dutyCyc10bit);
+}
+
+/**
+ * Enables PWM Outputs
+ * Currently supports PWM 0, PWM 1, and PWM 2
+ * @param pwmChannel Index of the PWM channel to enable.
+ * @param bEnable "True" enables output on the pwm channel.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::EnablePWMOutput(int pwmChannel, bool bEnable) {
+ if (pwmChannel < 0) {
+ pwmChannel = 0;
+ }
+
+ return c_CANifier_EnablePWMOutput(m_handle, (int) pwmChannel,
+ bEnable);
+}
+
+/**
+ * Gets the PWM Input
+ * @param pwmChannel PWM channel to get.
+ * @param dutyCycleAndPeriod Double array to hold Duty Cycle [0] and Period [1].
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::GetPWMInput(PWMChannel pwmChannel, double dutyCycleAndPeriod[]) {
+ return c_CANifier_GetPWMInput(m_handle, pwmChannel,
+ dutyCycleAndPeriod);
+}
+
+//------ Custom Persistent Params ----------//
+
+/**
+ * Sets the value of a custom parameter. This is for arbitrary use.
+ *
+ * Sometimes it is necessary to save calibration/duty cycle/output
+ * information in the device. Particularly if the
+ * device is part of a subsystem that can be replaced.
+ *
+ * @param newValue
+ * Value for custom parameter.
+ * @param paramIndex
+ * Index of custom parameter. [0-1]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::ConfigSetCustomParam(int newValue,
+ int paramIndex, int timeoutMs) {
+ return c_CANifier_ConfigSetCustomParam(m_handle, newValue, paramIndex, timeoutMs);
+}
+/**
+ * Gets the value of a custom parameter. This is for arbitrary use.
+ *
+ * Sometimes it is necessary to save calibration/duty cycle/output
+ * information in the device. Particularly if the
+ * device is part of a subsystem that can be replaced.
+ *
+ * @param paramIndex
+ * Index of custom parameter. [0-1]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Value of the custom param.
+ */
+int CANifier::ConfigGetCustomParam(
+ int paramIndex, int timeoutMs) {
+ int readValue;
+ c_CANifier_ConfigGetCustomParam(m_handle, &readValue, paramIndex, timeoutMs);
+ return readValue;
+}
+
+//------ Generic Param API, typically not used ----------//
+/**
+ * Sets a parameter. Generally this is not used.
+ * This can be utilized in
+ * - Using new features without updating API installation.
+ * - Errata workarounds to circumvent API implementation.
+ * - Allows for rapid testing / unit testing of firmware.
+ *
+ * @param param
+ * Parameter enumeration.
+ * @param value
+ * Value of parameter.
+ * @param subValue
+ * Subvalue for parameter. Maximum value of 255.
+ * @param ordinal
+ * Ordinal of parameter.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::ConfigSetParameter(ParamEnum param, double value,
+ uint8_t subValue, int ordinal, int timeoutMs) {
+ return c_CANifier_ConfigSetParameter(m_handle, param, value, subValue, ordinal, timeoutMs);
+
+}
+/**
+ * Gets a parameter. Generally this is not used.
+ * This can be utilized in
+ * - Using new features without updating API installation.
+ * - Errata workarounds to circumvent API implementation.
+ * - Allows for rapid testing / unit testing of firmware.
+ *
+ * @param param
+ * Parameter enumeration.
+ * @param ordinal
+ * Ordinal of parameter.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Value of parameter.
+ */
+double CANifier::ConfigGetParameter(ParamEnum param, int ordinal, int timeoutMs) {
+ double value = 0;
+ c_CANifier_ConfigGetParameter(m_handle, param, &value, ordinal, timeoutMs);
+ return value;
+}
+
+//------ Frames ----------//
+/**
+ * Sets the period of the given status frame.
+ *
+ * @param statusFrame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::SetStatusFramePeriod(CANifierStatusFrame statusFrame, int periodMs,
+ int timeoutMs) {
+ return c_CANifier_SetStatusFramePeriod(m_handle, statusFrame, periodMs,
+ timeoutMs);
+}
+/**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Period of the given status frame.
+ */
+int CANifier::GetStatusFramePeriod(CANifierStatusFrame frame,
+ int timeoutMs) {
+ int periodMs = 0;
+ c_CANifier_GetStatusFramePeriod(m_handle, frame, &periodMs, timeoutMs);
+ return periodMs;
+}
+/**
+ * Sets the period of the given control frame.
+ *
+ * @param frame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::SetControlFramePeriod(CANifierControlFrame frame,
+ int periodMs) {
+ return c_CANifier_SetControlFramePeriod(m_handle, frame, periodMs);
+}
+//------ Firmware ----------//
+/**
+ * Gets the firmware version of the device.
+ *
+ * @return Firmware version of device.
+ */
+int CANifier::GetFirmwareVersion() {
+ int retval = -1;
+ c_CANifier_GetFirmwareVersion(m_handle, &retval);
+ return retval;
+}
+/**
+ * Returns true if the device has reset since last call.
+ *
+ * @return Has a Device Reset Occurred?
+ */
+bool CANifier::HasResetOccurred() {
+ bool retval = false;
+ c_CANifier_HasResetOccurred(m_handle, &retval);
+ return retval;
+}
+//------ Faults ----------//
+/**
+ * Gets the CANifier fault status
+ *
+ * @param toFill
+ * Container for fault statuses.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::GetFaults(CANifierFaults & toFill) {
+ int faultBits;
+ ErrorCode retval = c_CANifier_GetFaults(m_handle, &faultBits);
+ toFill = CANifierFaults(faultBits);
+ return retval;
+}
+/**
+ * Gets the CANifier sticky fault status
+ *
+ * @param toFill
+ * Container for sticky fault statuses.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::GetStickyFaults(CANifierStickyFaults & toFill) {
+ int faultBits;
+ ErrorCode retval = c_CANifier_GetFaults(m_handle, &faultBits);
+ toFill = CANifierStickyFaults(faultBits);
+ return retval;
+}
+/**
+ * Clears the Sticky Faults
+ *
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode CANifier::ClearStickyFaults(int timeoutMs) {
+ return c_CANifier_ClearStickyFaults(m_handle, timeoutMs);
+}
+
+} // phoenix
+} // ctre
+#endif // CTR_EXCLUDE_WPILIB_CLASSES
diff --git a/cpp/src/CTRLogger.cpp b/cpp/src/CTRLogger.cpp
new file mode 100644
index 0000000..e9c5a4b
--- /dev/null
+++ b/cpp/src/CTRLogger.cpp
@@ -0,0 +1,31 @@
+#include "ctre/phoenix/CTRLogger.h"
+#include "ctre/phoenix/CCI/Logger_CCI.h" // c_Logger_*
+#include <execinfo.h>
+
+namespace ctre {
+namespace phoenix {
+
+void CTRLogger::Open(int language) {
+ c_Logger_Open(language, true);
+}
+ErrorCode CTRLogger::Log(ErrorCode code, std::string origin) {
+ void *buf[100];
+ char **strings;
+ int size = backtrace(buf, 100);
+ strings = backtrace_symbols(buf, size);
+ std::string stackTrace;
+ for (int i = 1; i < size; i++) {
+ stackTrace += strings[i];
+ stackTrace += "\n";
+ }
+ return c_Logger_Log(code, origin.c_str(), 3, stackTrace.c_str());
+}
+void CTRLogger::Close() {
+ c_Logger_Close();
+}
+//void CTRLogger::Description(ErrorCode code, const char *&shrt, const char *&lng) {
+// c_Logger_Description(code, shrt, lng);
+//}
+
+}
+}
diff --git a/cpp/src/CompileTest.cpp b/cpp/src/CompileTest.cpp
new file mode 100644
index 0000000..47e4f64
--- /dev/null
+++ b/cpp/src/CompileTest.cpp
@@ -0,0 +1,2 @@
+#include "ctre/Phoenix.h"
+
diff --git a/cpp/src/HsvToRgb.cpp b/cpp/src/HsvToRgb.cpp
new file mode 100644
index 0000000..c7d5f16
--- /dev/null
+++ b/cpp/src/HsvToRgb.cpp
@@ -0,0 +1,106 @@
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+
+#include "ctre/phoenix/HsvToRgb.h"
+#include <math.h>
+
+namespace ctre {
+namespace phoenix {
+/**
+ * Convert hue/saturation/and value into RGB values
+ *
+ * @param hDegrees Hue in degrees
+ * @param S Saturation with range of 0 to 1
+ * @param V Value with range of 0 to 1
+ * @param r Calculated Red value of RGB
+ * @param g Calculated Green value of RGB
+ * @param b Calculated Blue value of RGB
+ */
+void HsvToRgb::Convert(double hDegrees, double S, double V, float* r, float* g,
+ float* b) {
+ double R, G, B;
+ double H = hDegrees;
+
+ //Handles wrap-around
+ if (H < 0) {
+ H += 360;
+ };
+ if (H >= 360) {
+ H -= 360;
+ };
+
+ if (V <= 0)
+ R = G = B = 0;
+ else if (S <= 0)
+ R = G = B = V;
+ else {
+ double hf = H / 60.0;
+ int i = (int) floor(hf);
+ double f = hf - i;
+ double pv = V * (1 - S);
+ double qv = V * (1 - S * f);
+ double tv = V * (1 - S * (1 - f));
+ switch (i) {
+ //Red is dominant color
+ case 0:
+ R = V;
+ G = tv;
+ B = pv;
+ break;
+
+ //Green is dominant color
+ case 1:
+ R = qv;
+ G = V;
+ B = pv;
+ break;
+ case 2:
+ R = pv;
+ G = V;
+ B = tv;
+ break;
+
+ //Blue is dominant color
+ case 3:
+ R = pv;
+ G = qv;
+ B = V;
+ break;
+ case 4:
+ R = tv;
+ G = pv;
+ B = V;
+ break;
+
+ //Red is dominant color
+ case 5:
+ R = V;
+ G = pv;
+ B = qv;
+ break;
+
+ //Back-up case statements, in case our math is wrong
+ case 6:
+ R = V;
+ G = tv;
+ B = pv;
+ break;
+ case -1:
+ R = V;
+ G = pv;
+ B = qv;
+ break;
+
+ //Color is not defined
+ default:
+ //pretend color is black and white
+ R = G = B = V;
+ break;
+ }
+ }
+ *r = (float) R;
+ *g = (float) G;
+ *b = (float) B;
+}
+}
+}
+#endif
diff --git a/cpp/src/LinearInterpolation.cpp b/cpp/src/LinearInterpolation.cpp
new file mode 100644
index 0000000..dc5c358
--- /dev/null
+++ b/cpp/src/LinearInterpolation.cpp
@@ -0,0 +1,13 @@
+#include "ctre/phoenix/LinearInterpolation.h"
+
+namespace ctre {
+namespace phoenix {
+float LinearInterpolation::Calculate(float x, float x1, float y1, float x2,
+ float y2) {
+ float m = (y2 - y1) / (x2 - x1);
+
+ float retval = m * (x - x1) + y1;
+ return retval;
+}
+}
+}
diff --git a/cpp/src/MotorControl/CAN/BaseMotorController.cpp b/cpp/src/MotorControl/CAN/BaseMotorController.cpp
new file mode 100644
index 0000000..b67451e
--- /dev/null
+++ b/cpp/src/MotorControl/CAN/BaseMotorController.cpp
@@ -0,0 +1,1738 @@
+#include "ctre/phoenix/MotorControl/CAN/BaseMotorController.h"
+#include "ctre/phoenix/MotorControl/SensorCollection.h"
+#include "ctre/phoenix/CCI/MotController_CCI.h"
+#include "ctre/phoenix/LowLevel/MotControllerWithBuffer_LowLevel.h"
+
+using namespace ctre::phoenix;
+using namespace ctre::phoenix::motorcontrol;
+using namespace ctre::phoenix::motorcontrol::can;
+using namespace ctre::phoenix::motorcontrol::lowlevel;
+
+//--------------------- Constructors -----------------------------//
+/**
+ *
+ * Constructor for motor controllers.
+ * @param arbId
+ */
+BaseMotorController::BaseMotorController(int arbId) {
+ m_handle = c_MotController_Create1(arbId);
+ _arbId = arbId;
+
+ _sensorColl = new motorcontrol::SensorCollection((void*) m_handle);
+}
+/**
+ *
+ * Destructor
+ */
+BaseMotorController::~BaseMotorController() {
+ delete _sensorColl;
+ _sensorColl = 0;
+}
+/**
+ * @return CCI handle for child classes.
+ */
+void* BaseMotorController::GetHandle() {
+ return m_handle;
+}
+/**
+ * Returns the Device ID
+ *
+ * @return Device number.
+ */
+int BaseMotorController::GetDeviceID() {
+ int devID = 0;
+ (void) c_MotController_GetDeviceNumber(m_handle, &devID);
+ return devID;
+}
+//------ Set output routines. ----------//
+/**
+ * @param Mode Sets the appropriate output on the talon, depending on the mode.
+ * @param value The output value to apply.
+ *
+ * In PercentOutput, the output is between -1.0 and 1.0, with 0.0 as stopped.
+ * In Current mode, output value is in amperes.
+ * In Velocity mode, output value is in position change / 100ms.
+ * In Position mode, output value is in encoder ticks or an analog value,
+ * depending on the sensor.
+ * In Follower mode, the output value is the integer device ID of the talon to
+ * duplicate.
+ *
+ * @param value The setpoint value, as described above.
+ *
+ *
+ * Standard Driving Example:
+ * _talonLeft.set(ControlMode.PercentOutput, leftJoy);
+ * _talonRght.set(ControlMode.PercentOutput, rghtJoy);
+ */
+void BaseMotorController::Set(ControlMode Mode, double value) {
+ Set(Mode, value, DemandType_Neutral, 0);
+}
+/**
+ * @param mode Sets the appropriate output on the talon, depending on the mode.
+ * @param demand0 The output value to apply.
+ * such as advanced feed forward and/or auxiliary close-looping in firmware.
+ * In PercentOutput, the output is between -1.0 and 1.0, with 0.0 as stopped.
+ * In Current mode, output value is in amperes.
+ * In Velocity mode, output value is in position change / 100ms.
+ * In Position mode, output value is in encoder ticks or an analog value,
+ * depending on the sensor. See
+ * In Follower mode, the output value is the integer device ID of the talon to
+ * duplicate.
+ *
+ * @param demand1 Supplemental value. This will also be control mode specific for future features.
+ */
+
+void BaseMotorController::Set(ControlMode mode, double demand0, double demand1) {
+ Set(mode, demand0, DemandType_Neutral, demand1);
+}
+/**
+ * @param mode Sets the appropriate output on the talon, depending on the mode.
+ * @param demand0 The output value to apply.
+ * such as advanced feed forward and/or auxiliary close-looping in firmware.
+ * In PercentOutput, the output is between -1.0 and 1.0, with 0.0 as stopped.
+ * In Current mode, output value is in amperes.
+ * In Velocity mode, output value is in position change / 100ms.
+ * In Position mode, output value is in encoder ticks or an analog value,
+ * depending on the sensor. See
+ * In Follower mode, the output value is the integer device ID of the talon to
+ * duplicate.
+ *
+ * @param demand1Type The demand type for demand1.
+ * Neutral: Ignore demand1 and apply no change to the demand0 output.
+ * AuxPID: Use demand1 to set the target for the auxiliary PID 1.
+ * ArbitraryFeedForward: Use demand1 as an arbitrary additive value to the
+ * demand0 output. In PercentOutput the demand0 output is the motor output,
+ * and in closed-loop modes the demand0 output is the output of PID0.
+ * @param demand1 Supplmental output value. Units match the set mode.
+ *
+ *
+ * Arcade Drive Example:
+ * _talonLeft.set(ControlMode::PercentOutput, joyForward, DemandType_ArbitraryFeedForward, +joyTurn);
+ * _talonRght.set(ControlMode::PercentOutput, joyForward, DemandType_ArbitraryFeedForward, -joyTurn);
+ *
+ * Drive Straight Example:
+ * Note: Selected Sensor Configuration is necessary for both PID0 and PID1.
+ * _talonLeft.follow(_talonRght, FollwerType_AuxOutput1);
+ * _talonRght.set(ControlMode::PercentOutput, joyForward, DemandType_AuxPID, desiredRobotHeading);
+ *
+ * Drive Straight to a Distance Example:
+ * Note: Other configurations (sensor selection, PID gains, etc.) need to be set.
+ * _talonLeft.follow(_talonRght, FollwerType_AuxOutput1);
+ * _talonRght.set(ControlMode::MotionMagic, targetDistance, DemandType_AuxPID, desiredRobotHeading);
+ */
+void BaseMotorController::Set(ControlMode mode, double demand0, DemandType demand1Type, double demand1) {
+ m_controlMode = mode;
+ m_sendMode = mode;
+ m_setPoint = demand0;
+
+ uint32_t work;
+ switch (m_controlMode) {
+ case ControlMode::PercentOutput:
+ //case ControlMode::TimedPercentOutput:
+ c_MotController_Set_4(m_handle, (int) m_sendMode, demand0, demand1, demand1Type);
+ break;
+ case ControlMode::Follower:
+ /* did caller specify device ID */
+ if ((0 <= demand0) && (demand0 <= 62)) { // [0,62]
+ work = (uint32_t) GetBaseID();
+ work >>= 16;
+ work <<= 8;
+ work |= (uint8_t) demand0;
+ } else {
+ work = (uint32_t) demand0;
+ }
+ /* single precision guarantees 16bits of integral precision,
+ * so float/double cast on work is safe */
+ c_MotController_Set_4(m_handle, (int) m_sendMode, (double)work, demand1, demand1Type);
+ break;
+ case ControlMode::Velocity:
+ case ControlMode::Position:
+ case ControlMode::MotionMagic:
+ //case ControlMode::MotionMagicArc:
+ case ControlMode::MotionProfile:
+ case ControlMode::MotionProfileArc:
+ c_MotController_Set_4(m_handle, (int) m_sendMode, demand0, demand1, demand1Type);
+ break;
+ case ControlMode::Current:
+ c_MotController_SetDemand(m_handle, (int) m_sendMode,
+ (int) (1000 * demand0), 0); /* milliamps */
+ break;
+ case ControlMode::Disabled:
+ /* fall thru...*/
+ default:
+ c_MotController_SetDemand(m_handle, (int) m_sendMode, 0, 0);
+ break;
+ }
+}
+/**
+ * Neutral the motor output by setting control mode to disabled.
+ */
+void BaseMotorController::NeutralOutput() {
+ Set(ControlMode::Disabled, 0);
+}
+/**
+ * Sets the mode of operation during neutral throttle output.
+ *
+ * @param neutralMode
+ * The desired mode of operation when the Controller output
+ * throttle is neutral (ie brake/coast)
+ **/
+void BaseMotorController::SetNeutralMode(NeutralMode neutralMode) {
+ c_MotController_SetNeutralMode(m_handle, neutralMode);
+}
+/**
+ * Enables a future feature called "Heading Hold".
+ * For now this simply updates the CAN signal to the motor controller.
+ * Future firmware updates will use this.
+ *
+ * @param enable true/false enable
+ */
+void BaseMotorController::EnableHeadingHold(bool enable) {
+ (void)enable;
+ /* this routine is moot as the Set() call updates the signal on each call */
+ //c_MotController_EnableHeadingHold(m_handle, enable);
+}
+/**
+ * For now this simply updates the CAN signal to the motor controller.
+ * Future firmware updates will use this to control advanced auxiliary loop behavior.
+ *
+ * @param value
+ */
+void BaseMotorController::SelectDemandType(bool value) {
+ (void)value;
+ /* this routine is moot as the Set() call updates the signal on each call */
+ //c_MotController_SelectDemandType(m_handle, value);
+}
+
+//------ Invert behavior ----------//
+/**
+ * Sets the phase of the sensor. Use when controller forward/reverse output
+ * doesn't correlate to appropriate forward/reverse reading of sensor.
+ * Pick a value so that positive PercentOutput yields a positive change in sensor.
+ * After setting this, user can freely call SetInvert() with any value.
+ *
+ * @param PhaseSensor
+ * Indicates whether to invert the phase of the sensor.
+ */
+void BaseMotorController::SetSensorPhase(bool PhaseSensor) {
+ c_MotController_SetSensorPhase(m_handle, PhaseSensor);
+}
+
+/**
+ * Inverts the hbridge output of the motor controller.
+ *
+ * This does not impact sensor phase and should not be used to correct sensor polarity.
+ *
+ * This will invert the hbridge output but NOT the LEDs.
+ * This ensures....
+ * - Green LEDs always represents positive request from robot-controller/closed-looping mode.
+ * - Green LEDs correlates to forward limit switch.
+ * - Green LEDs correlates to forward soft limit.
+ *
+ * @param invert
+ * Invert state to set.
+ */
+void BaseMotorController::SetInverted(bool invert) {
+ _invert = invert; /* cache for getter */
+ c_MotController_SetInverted(m_handle, _invert);
+}
+/**
+ * @return invert setting of motor output.
+ */
+bool BaseMotorController::GetInverted() const {
+ return _invert;
+}
+
+//----- general output shaping ------------------//
+/**
+ * Configures the open-loop ramp rate of throttle output.
+ *
+ * @param secondsFromNeutralToFull
+ * Minimum desired time to go from neutral to full throttle. A
+ * value of '0' will disable the ramp.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigOpenloopRamp(
+ double secondsFromNeutralToFull, int timeoutMs) {
+ return c_MotController_ConfigOpenLoopRamp(m_handle,
+ secondsFromNeutralToFull, timeoutMs);
+}
+
+/**
+ * Configures the closed-loop ramp rate of throttle output.
+ *
+ * @param secondsFromNeutralToFull
+ * Minimum desired time to go from neutral to full throttle. A
+ * value of '0' will disable the ramp.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigClosedloopRamp(
+ double secondsFromNeutralToFull, int timeoutMs) {
+ return c_MotController_ConfigClosedLoopRamp(m_handle,
+ secondsFromNeutralToFull, timeoutMs);
+}
+
+/**
+ * Configures the forward peak output percentage.
+ *
+ * @param percentOut
+ * Desired peak output percentage. [0,+1]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigPeakOutputForward(double percentOut,
+ int timeoutMs) {
+ return c_MotController_ConfigPeakOutputForward(m_handle, percentOut,
+ timeoutMs);
+}
+
+/**
+ * Configures the reverse peak output percentage.
+ *
+ * @param percentOut
+ * Desired peak output percentage. [-1,0]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigPeakOutputReverse(double percentOut,
+ int timeoutMs) {
+ return c_MotController_ConfigPeakOutputReverse(m_handle, percentOut,
+ timeoutMs);
+}
+/**
+ * Configures the forward nominal output percentage.
+ *
+ * @param percentOut
+ * Nominal (minimum) percent output. [0,+1]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigNominalOutputForward(double percentOut,
+ int timeoutMs) {
+ return c_MotController_ConfigNominalOutputForward(m_handle, percentOut,
+ timeoutMs);
+}
+/**
+ * Configures the reverse nominal output percentage.
+ *
+ * @param percentOut
+ * Nominal (minimum) percent output. [-1,0]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigNominalOutputReverse(double percentOut,
+ int timeoutMs) {
+ return c_MotController_ConfigNominalOutputReverse(m_handle, percentOut,
+ timeoutMs);
+}
+/**
+ * Configures the output deadband percentage.
+ *
+ * @param percentDeadband
+ * Desired deadband percentage. Minimum is 0.1%, Maximum is
+ * 25%. Pass 0.04 for 4% (factory default).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigNeutralDeadband(double percentDeadband,
+ int timeoutMs) {
+ return c_MotController_ConfigNeutralDeadband(m_handle, percentDeadband,
+ timeoutMs);
+}
+
+//------ Voltage Compensation ----------//
+/**
+ * Configures the Voltage Compensation saturation voltage.
+ *
+ * @param voltage
+ * This is the max voltage to apply to the hbridge when voltage
+ * compensation is enabled. For example, if 10 (volts) is specified
+ * and a TalonSRX is commanded to 0.5 (PercentOutput, closed-loop, etc)
+ * then the TalonSRX will attempt to apply a duty-cycle to produce 5V.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigVoltageCompSaturation(double voltage,
+ int timeoutMs) {
+ return c_MotController_ConfigVoltageCompSaturation(m_handle, voltage,
+ timeoutMs);
+}
+
+/**
+ * Configures the voltage measurement filter.
+ *
+ * @param filterWindowSamples
+ * Number of samples in the rolling average of voltage
+ * measurement.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigVoltageMeasurementFilter(
+ int filterWindowSamples, int timeoutMs) {
+ return c_MotController_ConfigVoltageMeasurementFilter(m_handle,
+ filterWindowSamples, timeoutMs);
+}
+
+/**
+ * Enables voltage compensation. If enabled, voltage compensation works in
+ * all control modes.
+ *
+ * @param enable
+ * Enable state of voltage compensation.
+ **/
+void BaseMotorController::EnableVoltageCompensation(bool enable) {
+ c_MotController_EnableVoltageCompensation(m_handle, enable);
+}
+
+//------ General Status ----------//
+/**
+ * Gets the bus voltage seen by the device.
+ *
+ * @return The bus voltage value (in volts).
+ */
+double BaseMotorController::GetBusVoltage() {
+ double param = 0;
+ c_MotController_GetBusVoltage(m_handle, ¶m);
+ return param;
+}
+
+/**
+ * Gets the output percentage of the motor controller.
+ *
+ * @return Output of the motor controller (in percent). [-1,+1]
+ */
+double BaseMotorController::GetMotorOutputPercent() {
+ double param = 0;
+ c_MotController_GetMotorOutputPercent(m_handle, ¶m);
+ return param;
+}
+
+/**
+ * @return applied voltage to motor in volts.
+ */
+double BaseMotorController::GetMotorOutputVoltage() {
+ return GetBusVoltage() * GetMotorOutputPercent();
+}
+
+/**
+ * Gets the output current of the motor controller.
+ *
+ * @return The output current (in amps).
+ */
+double BaseMotorController::GetOutputCurrent() {
+ double param = 0;
+ c_MotController_GetOutputCurrent(m_handle, ¶m);
+ return param;
+}
+/**
+ * Gets the temperature of the motor controller.
+ *
+ * @return Temperature of the motor controller (in 'C)
+ */
+double BaseMotorController::GetTemperature() {
+ double param = 0;
+ c_MotController_GetTemperature(m_handle, ¶m);
+ return param;
+}
+
+//------ sensor selection ----------//
+/**
+ * Select the remote feedback device for the motor controller.
+ * Most CTRE CAN motor controllers will support remote sensors over CAN.
+ *
+ * @param feedbackDevice
+ * Remote Feedback Device to select.
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigSelectedFeedbackSensor(
+ RemoteFeedbackDevice feedbackDevice, int pidIdx, int timeoutMs) {
+ return c_MotController_ConfigSelectedFeedbackSensor(m_handle,
+ feedbackDevice, pidIdx, timeoutMs);
+}
+/**
+ * Select the feedback device for the motor controller.
+ *
+ * @param feedbackDevice
+ * Feedback Device to select.
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigSelectedFeedbackSensor(
+ FeedbackDevice feedbackDevice, int pidIdx, int timeoutMs) {
+ return c_MotController_ConfigSelectedFeedbackSensor(m_handle,
+ feedbackDevice, pidIdx, timeoutMs);
+}
+
+/**
+ * The Feedback Coefficient is a scalar applied to the value of the
+ * feedback sensor. Useful when you need to scale your sensor values
+ * within the closed-loop calculations. Default value is 1.
+ *
+ * Selected Feedback Sensor register in firmware is the decoded sensor value
+ * multiplied by the Feedback Coefficient.
+ *
+ * @param coefficient
+ * Feedback Coefficient value. Maximum value of 1.
+ * Resolution is 1/(2^16). Cannot be 0.
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigSelectedFeedbackCoefficient(
+ double coefficient, int pidIdx, int timeoutMs) {
+ return c_MotController_ConfigSelectedFeedbackCoefficient(m_handle,
+ coefficient, pidIdx, timeoutMs);
+}
+
+/**
+ * Select what remote device and signal to assign to Remote Sensor 0 or Remote Sensor 1.
+ * After binding a remote device and signal to Remote Sensor X, you may select Remote Sensor X
+ * as a PID source for closed-loop features.
+ *
+ * @param deviceID
+ * The CAN ID of the remote sensor device.
+ * @param remoteSensorSource
+ * The remote sensor device and signal type to bind.
+ * @param remoteOrdinal
+ * 0 for configuring Remote Sensor 0
+ * 1 for configuring Remote Sensor 1
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigRemoteFeedbackFilter(int deviceID,
+ RemoteSensorSource remoteSensorSource, int remoteOrdinal,
+ int timeoutMs) {
+ return c_MotController_ConfigRemoteFeedbackFilter(m_handle, deviceID,
+ (int) remoteSensorSource, remoteOrdinal, timeoutMs);
+}
+/**
+ * Select what sensor term should be bound to switch feedback device.
+ * Sensor Sum = Sensor Sum Term 0 - Sensor Sum Term 1
+ * Sensor Difference = Sensor Diff Term 0 - Sensor Diff Term 1
+ * The four terms are specified with this routine. Then Sensor Sum/Difference
+ * can be selected for closed-looping.
+ *
+ * @param sensorTerm Which sensor term to bind to a feedback source.
+ * @param feedbackDevice The sensor signal to attach to sensorTerm.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigSensorTerm(SensorTerm sensorTerm,
+ FeedbackDevice feedbackDevice, int timeoutMs) {
+ return c_MotController_ConfigSensorTerm(m_handle, (int) sensorTerm,
+ (int) feedbackDevice, timeoutMs);
+}
+
+//------- sensor status --------- //
+/**
+ * Get the selected sensor position (in raw sensor units).
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * See Phoenix-Documentation for how to interpret.
+ *
+ * @return Position of selected sensor (in raw sensor units).
+ */
+int BaseMotorController::GetSelectedSensorPosition(int pidIdx) {
+ int retval;
+ c_MotController_GetSelectedSensorPosition(m_handle, &retval, pidIdx);
+ return retval;
+}
+/**
+ * Get the selected sensor velocity.
+ *
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @return selected sensor (in raw sensor units) per 100ms.
+ * See Phoenix-Documentation for how to interpret.
+ */
+int BaseMotorController::GetSelectedSensorVelocity(int pidIdx) {
+ int retval;
+ c_MotController_GetSelectedSensorVelocity(m_handle, &retval, pidIdx);
+ return retval;
+}
+/**
+ * Sets the sensor position to the given value.
+ *
+ * @param sensorPos
+ * Position to set for the selected sensor (in raw sensor units).
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::SetSelectedSensorPosition(int sensorPos,
+ int pidIdx, int timeoutMs) {
+ return c_MotController_SetSelectedSensorPosition(m_handle, sensorPos,
+ pidIdx, timeoutMs);
+}
+
+//------ status frame period changes ----------//
+/**
+ * Sets the period of the given control frame.
+ *
+ * @param frame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::SetControlFramePeriod(ControlFrame frame,
+ int periodMs) {
+ return c_MotController_SetControlFramePeriod(m_handle, frame, periodMs);
+}
+/**
+ * Sets the period of the given status frame.
+ *
+ * User ensure CAN Bus utilization is not high.
+ *
+ * This setting is not persistent and is lost when device is reset.
+ * If this is a concern, calling application can use HasReset()
+ * to determine if the status frame needs to be reconfigured.
+ *
+ * @param frame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::SetStatusFramePeriod(StatusFrame frame,
+ int periodMs, int timeoutMs) {
+ return c_MotController_SetStatusFramePeriod(m_handle, frame, periodMs,
+ timeoutMs);
+}
+/**
+ * Sets the period of the given status frame.
+ *
+ * User ensure CAN Bus utilization is not high.
+ *
+ * This setting is not persistent and is lost when device is reset.
+ * If this is a concern, calling application can use HasReset()
+ * to determine if the status frame needs to be reconfigured.
+ *
+ * @param frame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::SetStatusFramePeriod(StatusFrameEnhanced frame,
+ int periodMs, int timeoutMs) {
+ return c_MotController_SetStatusFramePeriod(m_handle, frame, periodMs,
+ timeoutMs);
+}
+/**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Period of the given status frame.
+ */
+int BaseMotorController::GetStatusFramePeriod(StatusFrame frame,
+ int timeoutMs) {
+ int periodMs = 0;
+ c_MotController_GetStatusFramePeriod(m_handle, frame, &periodMs, timeoutMs);
+ return periodMs;
+}
+
+/**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Period of the given status frame.
+ */
+int BaseMotorController::GetStatusFramePeriod(StatusFrameEnhanced frame,
+ int timeoutMs) {
+ int periodMs = 0;
+ c_MotController_GetStatusFramePeriod(m_handle, frame, &periodMs, timeoutMs);
+ return periodMs;
+}
+
+//----- velocity signal conditioning ------//
+
+/**
+ * Configures the period of each velocity sample.
+ * Every 1ms a position value is sampled, and the delta between that sample
+ * and the position sampled kPeriod ms ago is inserted into a filter.
+ * kPeriod is configured with this function.
+ *
+ * @param period
+ * Desired period for the velocity measurement. @see
+ * #VelocityMeasPeriod
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigVelocityMeasurementPeriod(
+ VelocityMeasPeriod period, int timeoutMs) {
+ return c_MotController_ConfigVelocityMeasurementPeriod(m_handle, period,
+ timeoutMs);
+}
+/**
+ * Sets the number of velocity samples used in the rolling average velocity
+ * measurement.
+ *
+ * @param windowSize
+ * Number of samples in the rolling average of velocity
+ * measurement. Valid values are 1,2,4,8,16,32. If another
+ * value is specified, it will truncate to nearest support value.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigVelocityMeasurementWindow(int windowSize,
+ int timeoutMs) {
+ return c_MotController_ConfigVelocityMeasurementWindow(m_handle, windowSize,
+ timeoutMs);
+}
+
+//------ remote limit switch ----------//
+/**
+ * Configures the forward limit switch for a remote source.
+ * For example, a CAN motor controller may need to monitor the Limit-F pin
+ * of another Talon or CANifier.
+ *
+ * @param type
+ * Remote limit switch source.
+ * User can choose between a remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param deviceID
+ * Device ID of remote source (Talon SRX or CANifier device ID).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigForwardLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs) {
+ LimitSwitchSource cciType = LimitSwitchRoutines::Promote(type);
+ return c_MotController_ConfigForwardLimitSwitchSource(m_handle, cciType,
+ normalOpenOrClose, deviceID, timeoutMs);
+}
+/**
+ * Configures the reverse limit switch for a remote source.
+ * For example, a CAN motor controller may need to monitor the Limit-R pin
+ * of another Talon or CANifier.
+ *
+ * @param type
+ * Remote limit switch source.
+ * User can choose between a remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param deviceID
+ * Device ID of remote source (Talon SRX or CANifier device ID).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigReverseLimitSwitchSource(
+ RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int deviceID, int timeoutMs) {
+ LimitSwitchSource cciType = LimitSwitchRoutines::Promote(type);
+ return c_MotController_ConfigReverseLimitSwitchSource(m_handle, cciType,
+ normalOpenOrClose, deviceID, timeoutMs);
+}
+/**
+ * Sets the enable state for limit switches.
+ *
+ * This routine can be used to DISABLE the limit switch feature.
+ * This is helpful to force off the limit switch detection.
+ * For example, a module can leave limit switches enable for home-ing
+ * a continuous mechanism, and once done this routine can force off
+ * disabling of the motor controller.
+ *
+ * Limit switches must be enabled using the Config routines first.
+ *
+ * @param enable
+ * Enable state for limit switches.
+ */
+void BaseMotorController::OverrideLimitSwitchesEnable(bool enable) {
+ c_MotController_OverrideLimitSwitchesEnable(m_handle, enable);
+}
+
+//------ local limit switch ----------//
+/**
+ * Configures a limit switch for a local/remote source.
+ *
+ * For example, a CAN motor controller may need to monitor the Limit-R pin
+ * of another Talon, CANifier, or local Gadgeteer feedback connector.
+ *
+ * If the sensor is remote, a device ID of zero is assumed.
+ * If that's not desired, use the four parameter version of this function.
+ *
+ * @param type
+ * Limit switch source. @see #LimitSwitchSource
+ * User can choose between the feedback connector, remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigForwardLimitSwitchSource(
+ LimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int timeoutMs) {
+ return c_MotController_ConfigForwardLimitSwitchSource(m_handle, type,
+ normalOpenOrClose, 0, timeoutMs);
+}
+/**
+ * Configures a limit switch for a local/remote source.
+ *
+ * For example, a CAN motor controller may need to monitor the Limit-R pin
+ * of another Talon, CANifier, or local Gadgeteer feedback connector.
+ *
+ * If the sensor is remote, a device ID of zero is assumed.
+ * If that's not desired, use the four parameter version of this function.
+ *
+ * @param type
+ * Limit switch source. @see #LimitSwitchSource
+ * User can choose between the feedback connector, remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigReverseLimitSwitchSource(
+ LimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
+ int timeoutMs) {
+ return c_MotController_ConfigReverseLimitSwitchSource(m_handle, type,
+ normalOpenOrClose, 0, timeoutMs);
+}
+
+//------ soft limit ----------//
+/**
+ * Configures the forward soft limit threshold.
+ *
+ * @param forwardSensorLimit
+ * Forward Sensor Position Limit (in raw sensor units).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigForwardSoftLimitThreshold(int forwardSensorLimit,
+ int timeoutMs) {
+ return c_MotController_ConfigForwardSoftLimitThreshold(m_handle, forwardSensorLimit,
+ timeoutMs);
+}
+
+/**
+ * Configures the reverse soft limit threshold.
+ *
+ * @param reverseSensorLimit
+ * Reverse Sensor Position Limit (in raw sensor units).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigReverseSoftLimitThreshold(int reverseSensorLimit,
+ int timeoutMs) {
+ return c_MotController_ConfigReverseSoftLimitThreshold(m_handle, reverseSensorLimit,
+ timeoutMs);
+}
+
+/**
+ * Configures the forward soft limit enable .
+ *
+ * @param enable
+ * True to enable soft limit. False to disable.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigForwardSoftLimitEnable(bool enable,
+ int timeoutMs) {
+ return c_MotController_ConfigForwardSoftLimitEnable(m_handle, enable,
+ timeoutMs);
+}
+
+
+/**
+ * Configures the reverse soft limit enable.
+ *
+ * @param enable
+ * True to enable soft limit. False to disable.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigReverseSoftLimitEnable(bool enable,
+ int timeoutMs) {
+ return c_MotController_ConfigReverseSoftLimitEnable(m_handle, enable,
+ timeoutMs);
+}
+
+/**
+ * Can be used to override-disable the soft limits.
+ * This function can be used to quickly disable soft limits without
+ * having to modify the persistent configuration.
+ *
+ * @param enable
+ * Enable state for soft limit switches.
+ **/
+void BaseMotorController::OverrideSoftLimitsEnable(bool enable) {
+ c_MotController_OverrideSoftLimitsEnable(m_handle, enable);
+}
+
+//------ Current Lim ----------//
+/* not available in base */
+
+//------ General Close loop ----------//
+/**
+ * Sets the 'P' constant in the given parameter slot.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param value
+ * Value of the P constant.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::Config_kP(int slotIdx, double value,
+ int timeoutMs) {
+ return c_MotController_Config_kP(m_handle, slotIdx, value, timeoutMs);
+}
+
+/**
+ * Sets the 'I' constant in the given parameter slot.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param value
+ * Value of the I constant.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::Config_kI(int slotIdx, double value,
+ int timeoutMs) {
+ return c_MotController_Config_kI(m_handle, slotIdx, value, timeoutMs);
+}
+
+/**
+ * Sets the 'D' constant in the given parameter slot.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param value
+ * Value of the D constant.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::Config_kD(int slotIdx, double value,
+ int timeoutMs) {
+ return c_MotController_Config_kD(m_handle, slotIdx, value, timeoutMs);
+}
+
+/**
+ * Sets the 'F' constant in the given parameter slot.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param value
+ * Value of the F constant.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::Config_kF(int slotIdx, double value,
+ int timeoutMs) {
+ return c_MotController_Config_kF(m_handle, slotIdx, value, timeoutMs);
+}
+
+/**
+ * Sets the Integral Zone constant in the given parameter slot.
+ * If the (absolute) closed-loop error is outside of this zone, integral accumulator
+ * is automatically cleared. This ensures than integral wind up events will stop after
+ * the sensor gets far enough from its target.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param izone
+ * Value of the Integral Zone constant (closed loop error units X 1ms).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::Config_IntegralZone(int slotIdx, int izone,
+ int timeoutMs) {
+ return c_MotController_Config_IntegralZone(m_handle, slotIdx, izone,
+ timeoutMs);
+}
+
+/**
+ * Sets the allowable closed-loop error in the given parameter slot.
+ * If (absolute) closed-loop error is within this value, the motor output is neutral.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param allowableCloseLoopError
+ * Value of the allowable closed-loop error.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigAllowableClosedloopError(int slotIdx,
+ int allowableCloseLoopError, int timeoutMs) {
+ return c_MotController_ConfigAllowableClosedloopError(m_handle, slotIdx,
+ allowableCloseLoopError, timeoutMs);
+}
+
+/**
+ * Sets the maximum integral accumulator in the given parameter slot.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param iaccum
+ * Value of the maximum integral accumulator (closed loop error units X 1ms).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigMaxIntegralAccumulator(int slotIdx,
+ double iaccum, int timeoutMs) {
+ return c_MotController_ConfigMaxIntegralAccumulator(m_handle, slotIdx,
+ iaccum, timeoutMs);
+}
+
+/**
+ * Sets the peak closed-loop output. This peak output is slot-specific and
+ * is applied to the output of the associated PID loop.
+ * This setting is seperate from the generic Peak Output setting.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param percentOut
+ * Peak Percent Output from 0 to 1. This value is absolute and
+ * the magnitude will apply in both forward and reverse directions.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigClosedLoopPeakOutput(int slotIdx, double percentOut, int timeoutMs) {
+ return c_MotController_ConfigClosedLoopPeakOutput(m_handle, slotIdx, percentOut, timeoutMs);
+}
+
+/**
+ * Sets the loop time (in milliseconds) of the PID closed-loop calculations.
+ * Default value is 1 ms.
+ *
+ * @param slotIdx
+ * Parameter slot for the constant.
+ * @param loopTimeMs
+ * Loop timing of the closed-loop calculations. Minimum value of
+ * 1 ms, maximum of 64 ms.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigClosedLoopPeriod(int slotIdx, int loopTimeMs, int timeoutMs) {
+ return c_MotController_ConfigClosedLoopPeriod(m_handle, slotIdx, loopTimeMs, timeoutMs);
+}
+
+/**
+ * Configures the Polarity of the Auxiliary PID (PID1).
+ *
+ * Standard Polarity:
+ * Primary Output = PID0 + PID1
+ * Auxiliary Output = PID0 - PID1
+ *
+ * Inverted Polarity:
+ * Primary Output = PID0 - PID1
+ * Auxiliary Output = PID0 + PID1
+ *
+ * @param invert
+ * If true, use inverted PID1 output polarity.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for config
+ * success and report an error if it times out. If zero, no
+ * blocking or checking is performed.
+ * @return Error Code
+ */
+ ErrorCode BaseMotorController::ConfigAuxPIDPolarity(bool invert, int timeoutMs){
+ return ConfigSetParameter(ParamEnum::ePIDLoopPolarity, invert, 0, 1, timeoutMs);
+ }
+
+/**
+ * Sets the integral accumulator. Typically this is used to clear/zero
+ * the integral accumulator, however some use cases may require seeding
+ * the accumulator for a faster response.
+ *
+ * @param iaccum
+ * Value to set for the integral accumulator (closed loop error units X 1ms).
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::SetIntegralAccumulator(double iaccum, int pidIdx,
+ int timeoutMs) {
+ return c_MotController_SetIntegralAccumulator(m_handle, iaccum, pidIdx,
+ timeoutMs);
+}
+
+/**
+ * Gets the closed-loop error.
+ * The units depend on which control mode is in use.
+ * See Phoenix-Documentation information on units.
+ *
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @return Closed-loop error value.
+ */
+int BaseMotorController::GetClosedLoopError(int pidIdx) {
+ int closedLoopError = 0;
+ c_MotController_GetClosedLoopError(m_handle, &closedLoopError, pidIdx);
+ return closedLoopError;
+}
+
+/**
+ * Gets the iaccum value.
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @return Integral accumulator value (Closed-loop error X 1ms).
+ */
+double BaseMotorController::GetIntegralAccumulator(int pidIdx) {
+ double iaccum = 0;
+ c_MotController_GetIntegralAccumulator(m_handle, &iaccum, pidIdx);
+ return iaccum;
+}
+
+
+/**
+ * Gets the derivative of the closed-loop error.
+ *
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @return The error derivative value.
+ */
+double BaseMotorController::GetErrorDerivative(int pidIdx) {
+ double derror = 0;
+ c_MotController_GetErrorDerivative(m_handle, &derror, pidIdx);
+ return derror;
+}
+
+/**
+ * Selects which profile slot to use for closed-loop control.
+ *
+ * @param slotIdx
+ * Profile slot to select.
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ **/
+ErrorCode BaseMotorController::SelectProfileSlot(int slotIdx, int pidIdx) {
+ return c_MotController_SelectProfileSlot(m_handle, slotIdx, pidIdx);
+}
+/**
+ * Gets the current target of a given closed loop.
+ *
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @return The closed loop target.
+ */
+int BaseMotorController::GetClosedLoopTarget(int pidIdx) {
+ int param = 0;
+ c_MotController_GetClosedLoopTarget(m_handle, ¶m, pidIdx);
+ return param;
+}
+/**
+ * Gets the active trajectory target position using
+ * MotionMagic/MotionProfile control modes.
+ *
+ * @return The Active Trajectory Position in sensor units.
+ */
+int BaseMotorController::GetActiveTrajectoryPosition() {
+ int param = 0;
+ c_MotController_GetActiveTrajectoryPosition(m_handle, ¶m);
+ return param;
+}
+/**
+ * Gets the active trajectory target velocity using
+ * MotionMagic/MotionProfile control modes.
+ *
+ * @return The Active Trajectory Velocity in sensor units per 100ms.
+ */
+int BaseMotorController::GetActiveTrajectoryVelocity() {
+ int param = 0;
+ c_MotController_GetActiveTrajectoryVelocity(m_handle, ¶m);
+ return param;
+}
+/**
+ * Gets the active trajectory target heading using
+ * MotionMagicArc/MotionProfileArc control modes.
+ *
+ * @return The Active Trajectory Heading in degreees.
+ */
+double BaseMotorController::GetActiveTrajectoryHeading() {
+ double param = 0;
+ c_MotController_GetActiveTrajectoryHeading(m_handle, ¶m);
+ return param;
+}
+
+//------ Motion Profile Settings used in Motion Magic and Motion Profile ----------//
+
+/**
+ * Sets the Motion Magic Cruise Velocity. This is the peak target velocity
+ * that the motion magic curve generator can use.
+ *
+ * @param sensorUnitsPer100ms
+ * Motion Magic Cruise Velocity (in raw sensor units per 100 ms).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigMotionCruiseVelocity(
+ int sensorUnitsPer100ms, int timeoutMs) {
+ return c_MotController_ConfigMotionCruiseVelocity(m_handle,
+ sensorUnitsPer100ms, timeoutMs);
+}
+/**
+ * Sets the Motion Magic Acceleration. This is the target acceleration
+ * that the motion magic curve generator can use.
+ *
+ * @param sensorUnitsPer100msPerSec
+ * Motion Magic Acceleration (in raw sensor units per 100 ms per
+ * second).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigMotionAcceleration(
+ int sensorUnitsPer100msPerSec, int timeoutMs) {
+ return c_MotController_ConfigMotionAcceleration(m_handle,
+ sensorUnitsPer100msPerSec, timeoutMs);
+}
+
+//------ Motion Profile Buffer ----------//
+/**
+ * Clear the buffered motion profile in both motor controller's RAM (bottom), and in the API
+ * (top).
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ClearMotionProfileTrajectories() {
+ return c_MotController_ClearMotionProfileTrajectories(m_handle);
+}
+/**
+ * Retrieve just the buffer count for the api-level (top) buffer.
+ * This routine performs no CAN or data structure lookups, so its fast and ideal
+ * if caller needs to quickly poll the progress of trajectory points being
+ * emptied into motor controller's RAM. Otherwise just use GetMotionProfileStatus.
+ * @return number of trajectory points in the top buffer.
+ */
+int BaseMotorController::GetMotionProfileTopLevelBufferCount() {
+ int param = 0;
+ c_MotController_GetMotionProfileTopLevelBufferCount(m_handle, ¶m);
+ return param;
+}
+/**
+ * Push another trajectory point into the top level buffer (which is emptied
+ * into the motor controller's bottom buffer as room allows).
+ * @param trajPt to push into buffer.
+ * The members should be filled in with these values...
+ *
+ * targPos: servo position in sensor units.
+ * targVel: velocity to feed-forward in sensor units
+ * per 100ms.
+ * profileSlotSelect0 Which slot to get PIDF gains. PID is used for position servo. F is used
+ * as the Kv constant for velocity feed-forward. Typically this is hardcoded
+ * to the a particular slot, but you are free gain schedule if need be.
+ * Choose from [0,3]
+ * profileSlotSelect1 Which slot to get PIDF gains for auxiliary PId.
+ * This only has impact during MotionProfileArc Control mode.
+ * Choose from [0,1].
+ * isLastPoint set to nonzero to signal motor controller to keep processing this
+ * trajectory point, instead of jumping to the next one
+ * when timeDurMs expires. Otherwise MP executer will
+ * eventually see an empty buffer after the last point
+ * expires, causing it to assert the IsUnderRun flag.
+ * However this may be desired if calling application
+ * never wants to terminate the MP.
+ * zeroPos set to nonzero to signal motor controller to "zero" the selected
+ * position sensor before executing this trajectory point.
+ * Typically the first point should have this set only thus
+ * allowing the remainder of the MP positions to be relative to
+ * zero.
+ * timeDur Duration to apply this trajectory pt.
+ * This time unit is ADDED to the exising base time set by
+ * configMotionProfileTrajectoryPeriod().
+ * @return CTR_OKAY if trajectory point push ok. ErrorCode if buffer is
+ * full due to kMotionProfileTopBufferCapacity.
+ */
+ErrorCode BaseMotorController::PushMotionProfileTrajectory(
+ const ctre::phoenix::motion::TrajectoryPoint & trajPt) {
+ ErrorCode retval = c_MotController_PushMotionProfileTrajectory_2(m_handle,
+ trajPt.position, trajPt.velocity, trajPt.auxiliaryPos,
+ trajPt.profileSlotSelect0, trajPt.profileSlotSelect1, trajPt.isLastPoint, trajPt.zeroPos,
+ (int)trajPt.timeDur);
+ return retval;
+}
+/**
+ * Retrieve just the buffer full for the api-level (top) buffer.
+ * This routine performs no CAN or data structure lookups, so its fast and ideal
+ * if caller needs to quickly poll. Otherwise just use GetMotionProfileStatus.
+ * @return number of trajectory points in the top buffer.
+ */
+bool BaseMotorController::IsMotionProfileTopLevelBufferFull() {
+ bool retval = false;
+ c_MotController_IsMotionProfileTopLevelBufferFull(m_handle, &retval);
+ return retval;
+}
+/**
+ * This must be called periodically to funnel the trajectory points from the
+ * API's top level buffer to the controller's bottom level buffer. Recommendation
+ * is to call this twice as fast as the execution rate of the motion profile.
+ * So if MP is running with 20ms trajectory points, try calling this routine
+ * every 10ms. All motion profile functions are thread-safe through the use of
+ * a mutex, so there is no harm in having the caller utilize threading.
+ */
+void BaseMotorController::ProcessMotionProfileBuffer() {
+ c_MotController_ProcessMotionProfileBuffer(m_handle);
+}
+/**
+ * Retrieve all status information.
+ * For best performance, Caller can snapshot all status information regarding the
+ * motion profile executer.
+ *
+ * @param [out] statusToFill Caller supplied object to fill.
+ *
+ * The members are filled, as follows...
+ *
+ * topBufferRem: The available empty slots in the trajectory buffer.
+ * The robot API holds a "top buffer" of trajectory points, so your applicaion
+ * can dump several points at once. The API will then stream them into the
+ * low-level buffer, allowing the motor controller to act on them.
+ *
+ * topBufferRem: The number of points in the top trajectory buffer.
+ *
+ * btmBufferCnt: The number of points in the low level controller buffer.
+ *
+ * hasUnderrun: Set if isUnderrun ever gets set.
+ * Only is cleared by clearMotionProfileHasUnderrun() to ensure
+ *
+ * isUnderrun: This is set if controller needs to shift a point from its buffer into
+ * the active trajectory point however
+ * the buffer is empty.
+ * This gets cleared automatically when is resolved.
+ *
+ * activePointValid: True if the active trajectory point has not empty, false otherwise. The members in activePoint are only valid if this signal is set.
+ *
+ * isLast: is set/cleared based on the MP executer's current
+ * trajectory point's IsLast value. This assumes
+ * IsLast was set when PushMotionProfileTrajectory
+ * was used to insert the currently processed trajectory
+ * point.
+ *
+ * profileSlotSelect0: The currently processed trajectory point's
+ * selected slot. This can differ in the currently selected slot used
+ * for Position and Velocity servo modes. Must be within [0,3].
+*
+ * profileSlotSelect1: The currently processed trajectory point's
+ * selected slot for auxiliary PID. This can differ in the currently selected slot used
+ * for Position and Velocity servo modes. Must be within [0,1].
+ *
+ * outputEnable: The current output mode of the motion profile
+ * executer (disabled, enabled, or hold). When changing the set()
+ * value in MP mode, it's important to check this signal to
+ * confirm the change takes effect before interacting with the top buffer.
+ */
+ErrorCode BaseMotorController::GetMotionProfileStatus(
+ ctre::phoenix::motion::MotionProfileStatus & statusToFill) {
+
+ int outputEnable = 0;
+ ErrorCode retval = c_MotController_GetMotionProfileStatus_2(m_handle,
+ &statusToFill.topBufferRem, &statusToFill.topBufferCnt,
+ &statusToFill.btmBufferCnt, &statusToFill.hasUnderrun,
+ &statusToFill.isUnderrun, &statusToFill.activePointValid,
+ &statusToFill.isLast, &statusToFill.profileSlotSelect0,
+ &outputEnable, &statusToFill.timeDurMs, &statusToFill.profileSlotSelect1);
+
+ statusToFill.outputEnable =
+ (ctre::phoenix::motion::SetValueMotionProfile) outputEnable;
+
+ return retval;
+}
+/**
+ * Clear the "Has Underrun" flag. Typically this is called after application
+ * has confirmed an underrun had occured.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ClearMotionProfileHasUnderrun(int timeoutMs) {
+ return c_MotController_ClearMotionProfileHasUnderrun(m_handle, timeoutMs);
+}
+/**
+ * Calling application can opt to speed up the handshaking between the robot API
+ * and the controller to increase the download rate of the controller's Motion Profile.
+ * Ideally the period should be no more than half the period of a trajectory
+ * point.
+ * @param periodMs The transmit period in ms.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ChangeMotionControlFramePeriod(int periodMs) {
+ return c_MotController_ChangeMotionControlFramePeriod(m_handle, periodMs);
+}
+/**
+ * When trajectory points are processed in the motion profile executer, the MPE determines
+ * how long to apply the active trajectory point by summing baseTrajDurationMs with the
+ * timeDur of the trajectory point (see TrajectoryPoint).
+ *
+ * This allows general selection of the execution rate of the points with 1ms resolution,
+ * while allowing some degree of change from point to point.
+ * @param baseTrajDurationMs The base duration time of every trajectory point.
+ * This is summed with the trajectory points unique timeDur.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigMotionProfileTrajectoryPeriod(int baseTrajDurationMs, int timeoutMs) {
+ return c_MotController_ConfigMotionProfileTrajectoryPeriod(m_handle, baseTrajDurationMs, timeoutMs);
+}
+
+//------ error ----------//
+/**
+ * Gets the last error generated by this object.
+ * Not all functions return an error code but can potentially report errors.
+ * This function can be used to retrieve those error codes.
+ *
+ * @return Last Error Code generated by a function.
+ */
+ErrorCode BaseMotorController::GetLastError() {
+ return c_MotController_GetLastError(m_handle);
+}
+
+//------ Faults ----------//
+/**
+ * Polls the various fault flags.
+ * @param toFill Caller's object to fill with latest fault flags.
+ * @return Last Error Code generated by a function.
+ */
+ErrorCode BaseMotorController::GetFaults(Faults & toFill) {
+ int faultBits;
+ ErrorCode retval = c_MotController_GetFaults(m_handle, &faultBits);
+ toFill = Faults(faultBits);
+ return retval;
+}
+/**
+ * Polls the various sticky fault flags.
+ * @param toFill Caller's object to fill with latest sticky fault flags.
+ * @return Last Error Code generated by a function.
+ */
+ErrorCode BaseMotorController::GetStickyFaults(StickyFaults & toFill) {
+ int faultBits;
+ ErrorCode retval = c_MotController_GetStickyFaults(m_handle, &faultBits);
+ toFill = StickyFaults(faultBits);
+ return retval;
+}
+/**
+ * Clears all sticky faults.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Last Error Code generated by a function.
+ */
+ErrorCode BaseMotorController::ClearStickyFaults(int timeoutMs) {
+ return c_MotController_ClearStickyFaults(m_handle, timeoutMs);
+}
+
+//------ Firmware ----------//
+/**
+ * Gets the firmware version of the device.
+ *
+ * @return Firmware version of device. For example: version 1-dot-2 is 0x0102.
+ */
+int BaseMotorController::GetFirmwareVersion() {
+ int retval = -1;
+ c_MotController_GetFirmwareVersion(m_handle, &retval);
+ return retval;
+}
+/**
+ * Returns true if the device has reset since last call.
+ *
+ * @return Has a Device Reset Occurred?
+ */
+bool BaseMotorController::HasResetOccurred() {
+ bool retval = false;
+ c_MotController_HasResetOccurred(m_handle, &retval);
+ return retval;
+}
+
+//------ Custom Persistent Params ----------//
+/**
+ * Sets the value of a custom parameter. This is for arbitrary use.
+ *
+ * Sometimes it is necessary to save calibration/limit/target
+ * information in the device. Particularly if the
+ * device is part of a subsystem that can be replaced.
+ *
+ * @param newValue
+ * Value for custom parameter.
+ * @param paramIndex
+ * Index of custom parameter [0,1]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigSetCustomParam(int newValue,
+ int paramIndex, int timeoutMs) {
+ return c_MotController_ConfigSetCustomParam(m_handle, newValue, paramIndex,
+ timeoutMs);
+}
+
+/**
+ * Gets the value of a custom parameter.
+ *
+ * @param paramIndex
+ * Index of custom parameter [0,1].
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Value of the custom param.
+ */
+int BaseMotorController::ConfigGetCustomParam(int paramIndex, int timeoutMs) {
+ int readValue;
+ c_MotController_ConfigGetCustomParam(m_handle, &readValue, paramIndex,
+ timeoutMs);
+ return readValue;
+}
+
+//------ Generic Param API ----------//
+/**
+ * Sets a parameter. Generally this is not used.
+ * This can be utilized in
+ * - Using new features without updating API installation.
+ * - Errata workarounds to circumvent API implementation.
+ * - Allows for rapid testing / unit testing of firmware.
+ *
+ * @param param
+ * Parameter enumeration.
+ * @param value
+ * Value of parameter.
+ * @param subValue
+ * Subvalue for parameter. Maximum value of 255.
+ * @param ordinal
+ * Ordinal of parameter.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode BaseMotorController::ConfigSetParameter(ParamEnum param, double value,
+ uint8_t subValue, int ordinal, int timeoutMs) {
+ return c_MotController_ConfigSetParameter(m_handle, param, value, subValue,
+ ordinal, timeoutMs);
+}
+
+/**
+ * Gets a parameter.
+ *
+ * @param param
+ * Parameter enumeration.
+ * @param ordinal
+ * Ordinal of parameter.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Value of parameter.
+ */
+double BaseMotorController::ConfigGetParameter(ParamEnum param, int ordinal,
+ int timeoutMs) {
+ double value = 0;
+ c_MotController_ConfigGetParameter(m_handle, param, &value, ordinal,
+ timeoutMs);
+ return (double) value;
+}
+
+//------ Misc. ----------//
+int BaseMotorController::GetBaseID() {
+ return _arbId;
+}
+/**
+ * @return control mode motor controller is in
+ */
+ControlMode BaseMotorController::GetControlMode() {
+ return m_controlMode;
+}
+
+// ----- Follower ------//
+/**
+ * Set the control mode and output value so that this motor controller will
+ * follow another motor controller. Currently supports following Victor SPX
+ * and Talon SRX.
+ *
+ * @param masterToFollow
+ * Motor Controller object to follow.
+ * @param followerType
+ * Type of following control. Use AuxOutput1 to follow the master
+ * device's auxiliary output 1.
+ * Use PercentOutput for standard follower mode.
+ */
+void BaseMotorController::Follow(IMotorController & masterToFollow, FollowerType followerType) {
+ uint32_t baseId = masterToFollow.GetBaseID();
+ uint32_t id24 = (uint16_t) (baseId >> 0x10);
+ id24 <<= 8;
+ id24 |= (uint8_t) (baseId);
+
+ switch (followerType) {
+ case FollowerType_PercentOutput:
+ Set(ControlMode::Follower, (double) id24);
+ break;
+ case FollowerType_AuxOutput1:
+ /* follow the motor controller, but set the aux flag
+ * to ensure we follow the processed output */
+ Set(ControlMode::Follower, (double) id24, DemandType_AuxPID, 0);
+ break;
+ default:
+ NeutralOutput();
+ break;
+ }
+}
+/**
+ * Set the control mode and output value so that this motor controller will
+ * follow another motor controller.
+ * Currently supports following Victor SPX and Talon SRX.
+ */
+void BaseMotorController::Follow(IMotorController & masterToFollow) {
+ Follow(masterToFollow, FollowerType_PercentOutput);
+}
+/** When master makes a device, this routine is called to signal the update. */
+void BaseMotorController::ValueUpdated() {
+ //do nothing
+}
+/**
+ * @return object that can get/set individual raw sensor values.
+ */
+ctre::phoenix::motorcontrol::SensorCollection & BaseMotorController::GetSensorCollection() {
+ return *_sensorColl;
+}
diff --git a/cpp/src/MotorControl/CAN/TalonSRX.cpp b/cpp/src/MotorControl/CAN/TalonSRX.cpp
new file mode 100644
index 0000000..c18800c
--- /dev/null
+++ b/cpp/src/MotorControl/CAN/TalonSRX.cpp
@@ -0,0 +1,343 @@
+#include "ctre/phoenix/MotorControl/CAN/TalonSRX.h"
+#include "ctre/phoenix/CCI/MotController_CCI.h"
+#include "HAL/HAL.h"
+
+using namespace ctre::phoenix;
+using namespace ctre::phoenix::motorcontrol::can;
+using namespace ctre::phoenix::motorcontrol;
+
+/**
+ * Constructor
+ * @param deviceNumber [0,62]
+ */
+TalonSRX::TalonSRX(int deviceNumber) :
+ BaseMotorController(deviceNumber | 0x02040000) {
+ HAL_Report(HALUsageReporting::kResourceType_CANTalonSRX, deviceNumber + 1);
+}
+/**
+ * Select the feedback device for the motor controller.
+ *
+ * @param feedbackDevice
+ * Feedback Device to select.
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigSelectedFeedbackSensor(FeedbackDevice feedbackDevice,
+ int pidIdx, int timeoutMs) {
+ return BaseMotorController::ConfigSelectedFeedbackSensor(feedbackDevice,
+ pidIdx, timeoutMs);
+}
+/**
+ * Select the remote feedback device for the motor controller.
+ * Most CTRE CAN motor controllers will support remote sensors over CAN.
+ *
+ * @param feedbackDevice
+ * Remote Feedback Device to select.
+ * @param pidIdx
+ * 0 for Primary closed-loop. 1 for auxiliary closed-loop.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigSelectedFeedbackSensor(RemoteFeedbackDevice feedbackDevice,
+ int pidIdx, int timeoutMs) {
+ return BaseMotorController::ConfigSelectedFeedbackSensor(feedbackDevice,
+ pidIdx, timeoutMs);
+}
+/**
+ * Sets the period of the given status frame.
+ *
+ * User ensure CAN Bus utilization is not high.
+ *
+ * This setting is not persistent and is lost when device is reset.
+ * If this is a concern, calling application can use HasReset()
+ * to determine if the status frame needs to be reconfigured.
+ *
+ * @param frame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::SetStatusFramePeriod(StatusFrameEnhanced frame,
+ int periodMs, int timeoutMs) {
+ return BaseMotorController::SetStatusFramePeriod(frame, periodMs, timeoutMs);
+}
+/**
+ * Sets the period of the given status frame.
+ *
+ * User ensure CAN Bus utilization is not high.
+ *
+ * This setting is not persistent and is lost when device is reset.
+ * If this is a concern, calling application can use HasReset()
+ * to determine if the status frame needs to be reconfigured.
+ *
+ * @param frame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::SetStatusFramePeriod(StatusFrame frame,
+ int periodMs, int timeoutMs) {
+ return BaseMotorController::SetStatusFramePeriod(frame, periodMs, timeoutMs);
+}
+/**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Period of the given status frame.
+ */
+int TalonSRX::GetStatusFramePeriod(StatusFrameEnhanced frame, int timeoutMs) {
+ return BaseMotorController::GetStatusFramePeriod(frame, timeoutMs);
+}
+/**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Period of the given status frame.
+ */
+int TalonSRX::GetStatusFramePeriod(StatusFrame frame, int timeoutMs) {
+ return BaseMotorController::GetStatusFramePeriod(frame, timeoutMs);
+}
+/**
+ * Configures the period of each velocity sample.
+ * Every 1ms a position value is sampled, and the delta between that sample
+ * and the position sampled kPeriod ms ago is inserted into a filter.
+ * kPeriod is configured with this function.
+ *
+ * @param period
+ * Desired period for the velocity measurement. @see
+ * #VelocityMeasPeriod
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigVelocityMeasurementPeriod(VelocityMeasPeriod period,
+ int timeoutMs) {
+ return BaseMotorController::ConfigVelocityMeasurementPeriod(period,
+ timeoutMs);
+}
+/**
+ * Sets the number of velocity samples used in the rolling average velocity
+ * measurement.
+ *
+ * @param windowSize
+ * Number of samples in the rolling average of velocity
+ * measurement. Valid values are 1,2,4,8,16,32. If another
+ * value is specified, it will truncate to nearest support value.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigVelocityMeasurementWindow(int windowSize,
+ int timeoutMs) {
+ return BaseMotorController::ConfigVelocityMeasurementWindow(windowSize,
+ timeoutMs);
+}
+/**
+ * Configures a limit switch for a local/remote source.
+ *
+ * For example, a CAN motor controller may need to monitor the Limit-R pin
+ * of another Talon, CANifier, or local Gadgeteer feedback connector.
+ *
+ * If the sensor is remote, a device ID of zero is assumed.
+ * If that's not desired, use the four parameter version of this function.
+ *
+ * @param limitSwitchSource
+ * Limit switch source.
+ * User can choose between the feedback connector, remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigForwardLimitSwitchSource(
+ LimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs) {
+
+ return BaseMotorController::ConfigForwardLimitSwitchSource(
+ limitSwitchSource, normalOpenOrClose, timeoutMs);
+}
+/**
+ * Configures a limit switch for a local/remote source.
+ *
+ * For example, a CAN motor controller may need to monitor the Limit-R pin
+ * of another Talon, CANifier, or local Gadgeteer feedback connector.
+ *
+ * If the sensor is remote, a device ID of zero is assumed.
+ * If that's not desired, use the four parameter version of this function.
+ *
+ * @param limitSwitchSource
+ * Limit switch source. @see #LimitSwitchSource
+ * User can choose between the feedback connector, remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigReverseLimitSwitchSource(
+ LimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int timeoutMs) {
+ return BaseMotorController::ConfigReverseLimitSwitchSource(
+ limitSwitchSource, normalOpenOrClose, timeoutMs);
+}
+/**
+ * Configures the forward limit switch for a remote source.
+ * For example, a CAN motor controller may need to monitor the Limit-F pin
+ * of another Talon or CANifier.
+ *
+ * @param limitSwitchSource
+ * Remote limit switch source.
+ * User can choose between a remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param deviceID
+ * Device ID of remote source (Talon SRX or CANifier device ID).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigForwardLimitSwitchSource(
+ RemoteLimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int deviceID, int timeoutMs) {
+
+ return BaseMotorController::ConfigForwardLimitSwitchSource(
+ limitSwitchSource, normalOpenOrClose, deviceID, timeoutMs);
+}
+/**
+ * Configures the reverse limit switch for a remote source.
+ * For example, a CAN motor controller may need to monitor the Limit-R pin
+ * of another Talon or CANifier.
+ *
+ * @param limitSwitchSource
+ * Remote limit switch source.
+ * User can choose between a remote Talon SRX, CANifier, or deactivate the feature.
+ * @param normalOpenOrClose
+ * Setting for normally open, normally closed, or disabled. This setting
+ * matches the web-based configuration drop down.
+ * @param deviceID
+ * Device ID of remote source (Talon SRX or CANifier device ID).
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigReverseLimitSwitchSource(
+ RemoteLimitSwitchSource limitSwitchSource,
+ LimitSwitchNormal normalOpenOrClose, int deviceID, int timeoutMs) {
+
+ return BaseMotorController::ConfigReverseLimitSwitchSource(
+ limitSwitchSource, normalOpenOrClose, deviceID, timeoutMs);
+}
+
+//------ Current Lim ----------//
+/**
+ * Configure the peak allowable current (when current limit is enabled).
+ *
+ * Current limit is activated when current exceeds the peak limit for longer than the peak duration.
+ * Then software will limit to the continuous limit.
+ * This ensures current limiting while allowing for momentary excess current events.
+ *
+ * For simpler current-limiting (single threshold) use ConfigContinuousCurrentLimit()
+ * and set the peak to zero: ConfigPeakCurrentLimit(0).
+ *
+ * @param amps Amperes to limit.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigPeakCurrentLimit(int amps, int timeoutMs) {
+ return c_MotController_ConfigPeakCurrentLimit(m_handle, amps, timeoutMs);
+}
+/**
+ * Configure the peak allowable duration (when current limit is enabled).
+ *
+ * Current limit is activated when current exceeds the peak limit for longer than the peak duration.
+ * Then software will limit to the continuous limit.
+ * This ensures current limiting while allowing for momentary excess current events.
+ *
+ * For simpler current-limiting (single threshold) use ConfigContinuousCurrentLimit()
+ * and set the peak to zero: ConfigPeakCurrentLimit(0).
+ *
+ * @param milliseconds How long to allow current-draw past peak limit.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigPeakCurrentDuration(int milliseconds, int timeoutMs) {
+ return c_MotController_ConfigPeakCurrentDuration(m_handle, milliseconds,
+ timeoutMs);
+}
+/**
+ * Configure the continuous allowable current-draw (when current limit is enabled).
+ *
+ * Current limit is activated when current exceeds the peak limit for longer than the peak duration.
+ * Then software will limit to the continuous limit.
+ * This ensures current limiting while allowing for momentary excess current events.
+ *
+ * For simpler current-limiting (single threshold) use ConfigContinuousCurrentLimit()
+ * and set the peak to zero: ConfigPeakCurrentLimit(0).
+ *
+ * @param amps Amperes to limit.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ */
+ctre::phoenix::ErrorCode TalonSRX::ConfigContinuousCurrentLimit(int amps, int timeoutMs) {
+ return c_MotController_ConfigContinuousCurrentLimit(m_handle, amps, timeoutMs);
+}
+/**
+ * Enable or disable Current Limit.
+ * @param enable
+ * Enable state of current limit.
+ * @see ConfigPeakCurrentLimit, ConfigPeakCurrentDuration, ConfigContinuousCurrentLimit
+ */
+void TalonSRX::EnableCurrentLimit(bool enable) {
+ c_MotController_EnableCurrentLimit(m_handle, enable);
+}
+
diff --git a/cpp/src/MotorControl/CAN/VictorSPX.cpp b/cpp/src/MotorControl/CAN/VictorSPX.cpp
new file mode 100644
index 0000000..11bcdf8
--- /dev/null
+++ b/cpp/src/MotorControl/CAN/VictorSPX.cpp
@@ -0,0 +1,13 @@
+#include "ctre/phoenix/MotorControl/CAN/VictorSPX.h"
+#include "HAL/HAL.h"
+
+using namespace ctre::phoenix;
+using namespace ctre::phoenix::motorcontrol::can;
+/**
+ * Constructor
+ * @param deviceNumber [0,62]
+ */
+VictorSPX::VictorSPX(int deviceNumber) :
+ BaseMotorController(deviceNumber | 0x01040000) {
+ HAL_Report(HALUsageReporting::kResourceType_CTRE_future1, deviceNumber + 1);
+ }
diff --git a/cpp/src/MotorControl/CAN/WPI_TalonSRX.cpp b/cpp/src/MotorControl/CAN/WPI_TalonSRX.cpp
new file mode 100644
index 0000000..30a8bc9
--- /dev/null
+++ b/cpp/src/MotorControl/CAN/WPI_TalonSRX.cpp
@@ -0,0 +1,157 @@
+/**
+ * WPI Compliant motor controller class.
+ * WPILIB's object model requires many interfaces to be implemented to use
+ * the various features.
+ * This includes...
+ * - Software PID loops running in the robot controller
+ * - LiveWindow/Test mode features
+ * - Motor Safety (auto-turn off of motor if Set stops getting called)
+ * - Single Parameter set that assumes a simple motor controller.
+ */
+#include "ctre/phoenix/MotorControl/CAN/WPI_TalonSRX.h"
+#include "ctre/phoenix/MotorControl/CAN/BaseMotorController.h"
+#include "HAL/HAL.h"
+#include <sstream>
+
+using namespace ctre::phoenix::motorcontrol::can;
+
+
+/** Constructor */
+WPI_TalonSRX::WPI_TalonSRX(int deviceNumber) :
+ BaseMotorController(deviceNumber | 0x02040000),
+ TalonSRX(deviceNumber),
+ _safetyHelper(this) {
+ HAL_Report(HALUsageReporting::kResourceType_CTRE_future2, deviceNumber + 1);
+ /* build string description */
+ std::stringstream work;
+ work << "Talon SRX " << deviceNumber;
+ _desc = work.str();
+ /* prep motor safety */
+ _safetyHelper.SetExpiration(0.0);
+ _safetyHelper.SetSafetyEnabled(false);
+ SetName("Talon SRX ", deviceNumber);
+}
+WPI_TalonSRX::~WPI_TalonSRX() {
+ /* MT */
+}
+
+//----------------------- set/get routines for WPILIB interfaces -------------------//
+/**
+ * Common interface for setting the speed of a simple speed controller.
+ *
+ * @param speed The speed to set. Value should be between -1.0 and 1.0.
+ * Value is also saved for Get().
+ */
+void WPI_TalonSRX::Set(double speed) {
+ _speed = speed;
+ TalonSRX::Set(ControlMode::PercentOutput, speed);
+ _safetyHelper.Feed();
+}
+void WPI_TalonSRX::PIDWrite(double output) {
+ Set(output);
+}
+
+/**
+ * Common interface for getting the current set speed of a speed controller.
+ *
+ * @return The current set speed. Value is between -1.0 and 1.0.
+ */
+double WPI_TalonSRX::Get() const {
+ return _speed;
+}
+
+//----------------------- Intercept CTRE calls for motor safety -------------------//
+void WPI_TalonSRX::Set(ControlMode mode, double value) {
+ /* intercept the advanced Set and feed motor-safety */
+ TalonSRX::Set(mode, value);
+ _safetyHelper.Feed();
+}
+void WPI_TalonSRX::Set(ControlMode mode, double demand0, double demand1) {
+ /* intercept the advanced Set and feed motor-safety */
+ TalonSRX::Set(mode, demand0, demand1);
+ _safetyHelper.Feed();
+}
+//----------------------- Invert routines -------------------//
+/**
+ * Common interface for inverting direction of a speed controller.
+ *
+ * @param isInverted The state of inversion, true is inverted.
+ */
+void WPI_TalonSRX::SetInverted(bool isInverted) {
+ TalonSRX::SetInverted(isInverted);
+}
+/**
+ * Common interface for returning the inversion state of a speed controller.
+ *
+ * @return isInverted The state of inversion, true is inverted.
+ */
+bool WPI_TalonSRX::GetInverted() const {
+ return BaseMotorController::GetInverted();
+}
+//----------------------- turn-motor-off routines-------------------//
+/**
+ * Common interface for disabling a motor.
+ */
+void WPI_TalonSRX::Disable() {
+ NeutralOutput();
+}
+/**
+ * Common interface to stop the motor until Set is called again.
+ */
+void WPI_TalonSRX::StopMotor() {
+ NeutralOutput();
+}
+
+//----------------------- Motor Safety-------------------//
+
+/**
+ * Set the safety expiration time.
+ *
+ * @param timeout The timeout (in seconds) for this motor object
+ */
+void WPI_TalonSRX::SetExpiration(double timeout) {
+ _safetyHelper.SetExpiration(timeout);
+}
+
+/**
+ * Return the safety expiration time.
+ *
+ * @return The expiration time value.
+ */
+double WPI_TalonSRX::GetExpiration() const {
+ return _safetyHelper.GetExpiration();
+}
+
+/**
+ * Check if the motor is currently alive or stopped due to a timeout.
+ *
+ * @return a bool value that is true if the motor has NOT timed out and should
+ * still be running.
+ */
+bool WPI_TalonSRX::IsAlive() const {
+ return _safetyHelper.IsAlive();
+}
+
+/**
+ * Check if motor safety is enabled.
+ *
+ * @return True if motor safety is enforced for this object
+ */
+bool WPI_TalonSRX::IsSafetyEnabled() const {
+ return _safetyHelper.IsSafetyEnabled();
+}
+
+void WPI_TalonSRX::SetSafetyEnabled(bool enabled) {
+ _safetyHelper.SetSafetyEnabled(enabled);
+}
+
+void WPI_TalonSRX::GetDescription(llvm::raw_ostream& desc) const {
+ desc << _desc.c_str();
+}
+
+void WPI_TalonSRX::InitSendable(frc::SendableBuilder& builder) {
+ builder.SetSmartDashboardType("Speed Controller");
+ builder.SetSafeState([=]() {StopMotor();});
+ builder.AddDoubleProperty("Value", [=]() {return Get();},
+ [=](double value) {Set(value);});
+}
diff --git a/cpp/src/MotorControl/CAN/WPI_VictorSPX.cpp b/cpp/src/MotorControl/CAN/WPI_VictorSPX.cpp
new file mode 100644
index 0000000..cc8ddbd
--- /dev/null
+++ b/cpp/src/MotorControl/CAN/WPI_VictorSPX.cpp
@@ -0,0 +1,157 @@
+/**
+ * WPI Compliant motor controller class.
+ * WPILIB's object model requires many interfaces to be implemented to use
+ * the various features.
+ * This includes...
+ * - Software PID loops running in the robot controller
+ * - LiveWindow/Test mode features
+ * - Motor Safety (auto-turn off of motor if Set stops getting called)
+ * - Single Parameter set that assumes a simple motor controller.
+ */
+#include "ctre/phoenix/MotorControl/CAN/WPI_VictorSPX.h"
+#include "ctre/phoenix/MotorControl/CAN/BaseMotorController.h"
+#include "HAL/HAL.h"
+#include <sstream>
+
+using namespace ctre::phoenix::motorcontrol::can;
+
+
+/** Constructor */
+WPI_VictorSPX::WPI_VictorSPX(int deviceNumber) :
+ BaseMotorController(deviceNumber | 0x01040000),
+ VictorSPX(deviceNumber),
+ _safetyHelper(this) {
+ HAL_Report(HALUsageReporting::kResourceType_CTRE_future3, deviceNumber + 1);
+ /* build string description */
+ std::stringstream work;
+ work << "Victor SPX " << deviceNumber;
+ _desc = work.str();
+ /* prep motor safety */
+ _safetyHelper.SetExpiration(0.0);
+ _safetyHelper.SetSafetyEnabled(false);
+ SetName("Victor SPX ", deviceNumber);
+}
+WPI_VictorSPX::~WPI_VictorSPX() {
+ /* MT */
+}
+
+//----------------------- set/get routines for WPILIB interfaces -------------------//
+/**
+ * Common interface for setting the speed of a simple speed controller.
+ *
+ * @param speed The speed to set. Value should be between -1.0 and 1.0.
+ * Value is also saved for Get().
+ */
+void WPI_VictorSPX::Set(double speed) {
+ _speed = speed;
+ VictorSPX::Set(ControlMode::PercentOutput, speed);
+ _safetyHelper.Feed();
+}
+void WPI_VictorSPX::PIDWrite(double output) {
+ Set(output);
+}
+
+/**
+ * Common interface for getting the current set speed of a speed controller.
+ *
+ * @return The current set speed. Value is between -1.0 and 1.0.
+ */
+double WPI_VictorSPX::Get() const {
+ return _speed;
+}
+
+//----------------------- Intercept CTRE calls for motor safety -------------------//
+void WPI_VictorSPX::Set(ControlMode mode, double value) {
+ /* intercept the advanced Set and feed motor-safety */
+ VictorSPX::Set(mode, value);
+ _safetyHelper.Feed();
+}
+void WPI_VictorSPX::Set(ControlMode mode, double demand0, double demand1) {
+ /* intercept the advanced Set and feed motor-safety */
+ VictorSPX::Set(mode, demand0, demand1);
+ _safetyHelper.Feed();
+}
+//----------------------- Invert routines -------------------//
+/**
+ * Common interface for inverting direction of a speed controller.
+ *
+ * @param isInverted The state of inversion, true is inverted.
+ */
+void WPI_VictorSPX::SetInverted(bool isInverted) {
+ VictorSPX::SetInverted(isInverted);
+}
+/**
+ * Common interface for returning the inversion state of a speed controller.
+ *
+ * @return isInverted The state of inversion, true is inverted.
+ */
+bool WPI_VictorSPX::GetInverted() const {
+ return BaseMotorController::GetInverted();
+}
+//----------------------- turn-motor-off routines-------------------//
+/**
+ * Common interface for disabling a motor.
+ */
+void WPI_VictorSPX::Disable() {
+ NeutralOutput();
+}
+/**
+ * Common interface to stop the motor until Set is called again.
+ */
+void WPI_VictorSPX::StopMotor() {
+ NeutralOutput();
+}
+
+//----------------------- Motor Safety-------------------//
+
+/**
+ * Set the safety expiration time.
+ *
+ * @param timeout The timeout (in seconds) for this motor object
+ */
+void WPI_VictorSPX::SetExpiration(double timeout) {
+ _safetyHelper.SetExpiration(timeout);
+}
+
+/**
+ * Return the safety expiration time.
+ *
+ * @return The expiration time value.
+ */
+double WPI_VictorSPX::GetExpiration() const {
+ return _safetyHelper.GetExpiration();
+}
+
+/**
+ * Check if the motor is currently alive or stopped due to a timeout.
+ *
+ * @return a bool value that is true if the motor has NOT timed out and should
+ * still be running.
+ */
+bool WPI_VictorSPX::IsAlive() const {
+ return _safetyHelper.IsAlive();
+}
+
+/**
+ * Check if motor safety is enabled.
+ *
+ * @return True if motor safety is enforced for this object
+ */
+bool WPI_VictorSPX::IsSafetyEnabled() const {
+ return _safetyHelper.IsSafetyEnabled();
+}
+
+void WPI_VictorSPX::SetSafetyEnabled(bool enabled) {
+ _safetyHelper.SetSafetyEnabled(enabled);
+}
+
+void WPI_VictorSPX::GetDescription(llvm::raw_ostream& desc) const {
+ desc << _desc.c_str();
+}
+
+void WPI_VictorSPX::InitSendable(frc::SendableBuilder& builder) {
+ builder.SetSmartDashboardType("Speed Controller");
+ builder.SetSafeState([=]() {StopMotor();});
+ builder.AddDoubleProperty("Value", [=]() {return Get();},
+ [=](double value) {Set(value);});
+}
diff --git a/cpp/src/MotorControl/DeviceCatalog.cpp b/cpp/src/MotorControl/DeviceCatalog.cpp
new file mode 100644
index 0000000..c59f43a3
--- /dev/null
+++ b/cpp/src/MotorControl/DeviceCatalog.cpp
@@ -0,0 +1,6 @@
+#include <ctre/phoenix/MotorControl/DeviceCatalog.h>
+
+using namespace ctre::phoenix;
+using namespace ctre::phoenix::motorcontrol;
+
+DeviceCatalog * DeviceCatalog::_instance = 0;
diff --git a/cpp/src/MotorControl/GroupMotorControllers.cpp b/cpp/src/MotorControl/GroupMotorControllers.cpp
new file mode 100644
index 0000000..d2e126a
--- /dev/null
+++ b/cpp/src/MotorControl/GroupMotorControllers.cpp
@@ -0,0 +1,25 @@
+#include "ctre/phoenix/MotorControl/GroupMotorControllers.h"
+
+using namespace ctre::phoenix;
+
+namespace ctre {
+namespace phoenix {
+namespace motorcontrol {
+
+std::vector<IMotorController*> GroupMotorControllers::_mcs;
+
+void GroupMotorControllers::Register(IMotorController *motorController) {
+ _mcs.push_back(motorController);
+}
+
+int GroupMotorControllers::MotorControllerCount() {
+ return _mcs.size();
+}
+
+IMotorController* GroupMotorControllers::Get(int idx) {
+ return _mcs[idx];
+}
+
+}
+}
+}
diff --git a/cpp/src/MotorControl/SensorCollection.cpp b/cpp/src/MotorControl/SensorCollection.cpp
new file mode 100644
index 0000000..a1ff1b1
--- /dev/null
+++ b/cpp/src/MotorControl/SensorCollection.cpp
@@ -0,0 +1,241 @@
+#include "ctre/phoenix/MotorControl/SensorCollection.h"
+#include "ctre/phoenix/CCI/MotController_CCI.h"
+
+using namespace ctre::phoenix;
+using namespace ctre::phoenix::motorcontrol;
+
+SensorCollection::SensorCollection(void * handle) {
+ _handle = handle;
+}
+
+/**
+ * Get the position of whatever is in the analog pin of the Talon, regardless of
+ * whether it is actually being used for feedback.
+ *
+ * @return the 24bit analog value. The bottom ten bits is the ADC (0 - 1023)
+ * on the analog pin of the Talon. The upper 14 bits tracks the overflows and underflows
+ * (continuous sensor).
+ */
+
+int SensorCollection::GetAnalogIn() {
+ int retval = 0;
+ c_MotController_GetAnalogIn(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Sets analog position.
+ *
+ * @param newPosition The new position.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ *
+ * @return an ErrorCode.
+ */
+
+ErrorCode SensorCollection::SetAnalogPosition(int newPosition, int timeoutMs) {
+ return c_MotController_SetAnalogPosition(_handle, newPosition, timeoutMs);
+}
+
+/**
+ * Get the position of whatever is in the analog pin of the Talon, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the ADC (0 - 1023) on analog pin of the Talon.
+ */
+
+int SensorCollection::GetAnalogInRaw() {
+ int retval = 0;
+ c_MotController_GetAnalogInRaw(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Get the velocity of whatever is in the analog pin of the Talon, regardless of
+ * whether it is actually being used for feedback.
+ *
+ * @return the speed in units per 100ms where 1024 units is one rotation.
+ */
+
+int SensorCollection::GetAnalogInVel() {
+ int retval = 0;
+ c_MotController_GetAnalogInVel(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Get the quadrature position of the Talon, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the quadrature position.
+ */
+
+int SensorCollection::GetQuadraturePosition() {
+ int retval = 0;
+ c_MotController_GetQuadraturePosition(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Change the quadrature reported position. Typically this is used to "zero" the
+ * sensor. This only works with Quadrature sensor. To set the selected sensor position
+ * regardless of what type it is, see SetSelectedSensorPosition in the motor controller class.
+ *
+ * @param newPosition The position value to apply to the sensor.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ *
+ * @return error code.
+ */
+
+ErrorCode SensorCollection::SetQuadraturePosition(int newPosition,
+ int timeoutMs) {
+ return c_MotController_SetQuadraturePosition(_handle, newPosition,
+ timeoutMs);
+}
+
+/**
+ * Get the quadrature velocity, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the quadrature velocity in units per 100ms.
+ */
+
+int SensorCollection::GetQuadratureVelocity() {
+ int retval = 0;
+ c_MotController_GetQuadratureVelocity(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Gets pulse width position, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the pulse width position.
+ */
+
+int SensorCollection::GetPulseWidthPosition() {
+ int retval = 0;
+ c_MotController_GetPulseWidthPosition(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Sets pulse width position.
+ *
+ * @param newPosition The position value to apply to the sensor.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ *
+ * @return an ErrErrorCode
+ */
+ErrorCode SensorCollection::SetPulseWidthPosition(int newPosition,
+ int timeoutMs) {
+ return c_MotController_SetPulseWidthPosition(_handle, newPosition,
+ timeoutMs);
+}
+
+/**
+ * Gets pulse width velocity, regardless of whether
+ * it is actually being used for feedback.
+ *
+ * @return the pulse width velocity in units per 100ms (where 4096 units is 1 rotation).
+ */
+
+int SensorCollection::GetPulseWidthVelocity() {
+ int retval = 0;
+ c_MotController_GetPulseWidthVelocity(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Gets pulse width rise to fall time.
+ *
+ * @return the pulse width rise to fall time in microseconds.
+ */
+
+int SensorCollection::GetPulseWidthRiseToFallUs() {
+ int retval = 0;
+ c_MotController_GetPulseWidthRiseToFallUs(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Gets pulse width rise to rise time.
+ *
+ * @return the pulse width rise to rise time in microseconds.
+ */
+
+int SensorCollection::GetPulseWidthRiseToRiseUs() {
+ int retval = 0;
+ c_MotController_GetPulseWidthRiseToRiseUs(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Gets pin state quad a.
+ *
+ * @return the pin state of quad a (1 if asserted, 0 if not asserted).
+ */
+
+int SensorCollection::GetPinStateQuadA() {
+ int retval = 0;
+ c_MotController_GetPinStateQuadA(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Gets pin state quad b.
+ *
+ * @return Digital level of QUADB pin (1 if asserted, 0 if not asserted).
+ */
+
+int SensorCollection::GetPinStateQuadB() {
+ int retval = 0;
+ c_MotController_GetPinStateQuadB(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Gets pin state quad index.
+ *
+ * @return Digital level of QUAD Index pin (1 if asserted, 0 if not asserted).
+ */
+
+int SensorCollection::GetPinStateQuadIdx() {
+ int retval = 0;
+ c_MotController_GetPinStateQuadIdx(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Is forward limit switch closed.
+ *
+ * @return '1' iff forward limit switch is closed, 0 iff switch is open. This function works
+ * regardless if limit switch feature is enabled.
+ */
+
+int SensorCollection::IsFwdLimitSwitchClosed() {
+ int retval = 0;
+ c_MotController_IsFwdLimitSwitchClosed(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Is reverse limit switch closed.
+ *
+ * @return '1' iff reverse limit switch is closed, 0 iff switch is open. This function works
+ * regardless if limit switch feature is enabled.
+ */
+
+int SensorCollection::IsRevLimitSwitchClosed() {
+ int retval = 0;
+ c_MotController_IsRevLimitSwitchClosed(_handle, &retval);
+ return retval;
+}
diff --git a/cpp/src/RCRadio3Ch.cpp b/cpp/src/RCRadio3Ch.cpp
new file mode 100644
index 0000000..2fea763
--- /dev/null
+++ b/cpp/src/RCRadio3Ch.cpp
@@ -0,0 +1,113 @@
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+
+#include "ctre/phoenix/RCRadio3Ch.h"
+#include <vector>
+
+namespace ctre {
+namespace phoenix {
+
+RCRadio3Ch::RCRadio3Ch(ctre::phoenix::CANifier *canifier) {
+ _canifier = canifier;
+}
+
+float RCRadio3Ch::GetDutyCycleUs(Channel channel) {
+ return _dutyCycleAndPeriods[(int) channel][0];
+}
+
+float RCRadio3Ch::GetDutyCyclePerc(Channel channel) {
+ float retval = RCRadio3Ch::GetDutyCycleUs(channel);
+
+ std::vector<double> xData = { 1000, 2000 };
+ std::vector<double> yData = { -1, 1 };
+
+ retval = RCRadio3Ch::Interpolate(xData, yData, retval, true);
+
+ if (retval < -1) {
+ retval = -1;
+ } else if (retval > +1) {
+ retval = +1;
+ }
+
+ return retval;
+}
+
+bool RCRadio3Ch::GetSwitchValue(Channel channel) {
+ float retval = RCRadio3Ch::GetDutyCyclePerc(channel);
+
+ return retval > 0.5f;
+}
+
+float RCRadio3Ch::GetPeriodUs(Channel channel) {
+ return _dutyCycleAndPeriods[(int) channel][1];
+}
+
+void RCRadio3Ch::Process() {
+ //Does some error code stuff, which we don't have...
+ _errorCodes[0] = _canifier->GetPWMInput(
+ ctre::phoenix::CANifier::PWMChannel::PWMChannel0, _dutyCycleAndPeriods[0]);
+ _errorCodes[1] = _canifier->GetPWMInput(
+ ctre::phoenix::CANifier::PWMChannel::PWMChannel1, _dutyCycleAndPeriods[1]);
+ _errorCodes[2] = _canifier->GetPWMInput(
+ ctre::phoenix::CANifier::PWMChannel::PWMChannel2, _dutyCycleAndPeriods[2]);
+ _errorCodes[3] = _canifier->GetPWMInput(
+ ctre::phoenix::CANifier::PWMChannel::PWMChannel3, _dutyCycleAndPeriods[3]);
+
+ Status health = Status::Okay;
+ if (health == Status::Okay) {
+ if (_errorCodes[0] < 0) {
+ health = Status::LossOfCAN;
+ }
+ if (_errorCodes[1] < 0) {
+ health = Status::LossOfCAN;
+ }
+ if (_errorCodes[2] < 0) {
+ health = Status::LossOfCAN;
+ }
+ if (_errorCodes[3] < 0) {
+ health = Status::LossOfCAN;
+ }
+ }
+
+ if (health == Status::Okay) {
+ if (RCRadio3Ch::GetPeriodUs(RCRadio3Ch::Channel1) == 0) {
+ health = Status::LossOfPwm;
+ }
+ if (RCRadio3Ch::GetPeriodUs(RCRadio3Ch::Channel2) == 0) {
+ health = Status::LossOfPwm;
+ }
+ if (RCRadio3Ch::GetPeriodUs(RCRadio3Ch::Channel3) == 0) {
+ health = Status::LossOfPwm;
+ }
+ }
+ CurrentStatus = health; //Will have to change this to a getter and a setter
+}
+
+double RCRadio3Ch::Interpolate(std::vector<double> &xData,
+ std::vector<double> &yData, double x, bool extrapolate) {
+ int size = xData.size();
+
+ int i = 0; // find left end of interval for interpolation
+ if (x >= xData[size - 2]) // special case: beyond right end
+ {
+ i = size - 2;
+ } else {
+ while (x > xData[i + 1])
+ i++;
+ }
+ double xL = xData[i], yL = yData[i], xR = xData[i + 1], yR = yData[i + 1]; // points on either side (unless beyond ends)
+ if (!extrapolate) // if beyond ends of array and not extrapolating
+ {
+ if (x < xL)
+ yR = yL;
+ if (x > xR)
+ yL = yR;
+ }
+
+ double dydx = (yR - yL) / (xR - xL); // gradient
+
+ return yL + dydx * (x - xL);
+}
+
+}
+}
+#endif
diff --git a/cpp/src/Sensors/PigeonIMU.cpp b/cpp/src/Sensors/PigeonIMU.cpp
new file mode 100644
index 0000000..4755e43
--- /dev/null
+++ b/cpp/src/Sensors/PigeonIMU.cpp
@@ -0,0 +1,779 @@
+/*
+ * Software License Agreement
+ *
+ * Copyright (C) Cross The Road Electronics. All rights
+ * reserved.
+ *
+ * Cross The Road Electronics (CTRE) licenses to you the right to
+ * use, publish, and distribute copies of CRF (Cross The Road) firmware files (*.crf) and Software
+ * API Libraries ONLY when in use with Cross The Road Electronics hardware products.
+ *
+ * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
+ * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * CROSS THE ROAD ELECTRONICS BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
+ * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
+ * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
+ * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
+ * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE
+ */
+
+#include <memory>
+
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+#include "ctre/phoenix/Sensors/PigeonIMU.h"
+#include "ctre/phoenix/CTRLogger.h"
+#include "ctre/phoenix/CCI/Logger_CCI.h"
+#include "ctre/phoenix/CCI/PigeonIMU_CCI.h"
+#include "ctre/phoenix/MotorControl/CAN/TalonSRX.h"
+
+#include "FRC_NetworkCommunication/CANSessionMux.h"
+
+#include "Utility.h"
+#include "HAL/HAL.h"
+
+using namespace ctre::phoenix::motorcontrol::can;
+
+namespace ctre {
+namespace phoenix {
+namespace sensors {
+
+/**
+ * Create a Pigeon object that communicates with Pigeon on CAN Bus.
+ * @param deviceNumber CAN Device Id of Pigeon [0,62]
+ */
+PigeonIMU::PigeonIMU(int deviceNumber) :
+ CANBusAddressable(deviceNumber) {
+ _handle = c_PigeonIMU_Create1(deviceNumber);
+ _deviceNumber = deviceNumber;
+ HAL_Report(HALUsageReporting::kResourceType_PigeonIMU, _deviceNumber + 1);
+}
+
+/**
+ * Create a Pigeon object that communciates with Pigeon through the Gadgeteer ribbon cable connected to a Talon on CAN Bus.
+ * @param talonSrx Object for the TalonSRX connected via ribbon cable.
+ */
+PigeonIMU::PigeonIMU(ctre::phoenix::motorcontrol::can::TalonSRX * talonSrx) :
+ CANBusAddressable(0) {
+ _handle = c_PigeonIMU_Create2(talonSrx->GetDeviceID());
+ _deviceNumber = talonSrx->GetDeviceID();
+ HAL_Report(HALUsageReporting::kResourceType_PigeonIMU, _deviceNumber + 1);
+ HAL_Report(HALUsageReporting::kResourceType_CTRE_future0, _deviceNumber + 1); //record as Pigeon-via-Uart
+}
+
+/**
+ * Sets the Yaw register to the specified value.
+ *
+ * @param angleDeg Degree of Yaw [+/- 23040 degrees]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::SetYaw(double angleDeg, int timeoutMs) {
+ int errCode = c_PigeonIMU_SetYaw(_handle, angleDeg, timeoutMs);
+ return errCode;
+}
+/**
+ * Atomically add to the Yaw register.
+ *
+ * @param angleDeg Degrees to add to the Yaw register.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::AddYaw(double angleDeg, int timeoutMs) {
+ int errCode = c_PigeonIMU_AddYaw(_handle, angleDeg, timeoutMs);
+ return errCode;
+}
+/**
+ * Sets the Yaw register to match the current compass value.
+ *
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::SetYawToCompass(int timeoutMs) {
+ int errCode = c_PigeonIMU_SetYawToCompass(_handle, timeoutMs);
+ return errCode;
+}
+/**
+ * Sets the Fused Heading to the specified value.
+ *
+ * @param angleDeg Degree of heading [+/- 23040 degrees]
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::SetFusedHeading(double angleDeg, int timeoutMs) {
+ int errCode = c_PigeonIMU_SetFusedHeading(_handle, angleDeg, timeoutMs);
+ return errCode;
+}
+/**
+ * Sets the AccumZAngle.
+ *
+ * @param angleDeg Degrees to set AccumZAngle to.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::SetAccumZAngle(double angleDeg, int timeoutMs) {
+ int errCode = c_PigeonIMU_SetAccumZAngle(_handle, angleDeg, timeoutMs);
+ return errCode;
+}
+/**
+ * Enable/Disable Temp compensation. Pigeon defaults with this on at boot.
+ *
+ * @param bTempCompEnable Set to "True" to enable temperature compensation.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::ConfigTemperatureCompensationEnable(bool bTempCompEnable,
+ int timeoutMs) {
+ int errCode = c_PigeonIMU_ConfigTemperatureCompensationEnable(_handle,
+ bTempCompEnable, timeoutMs);
+ return errCode;
+}
+/**
+ * Atomically add to the Fused Heading register.
+ *
+ * @param angleDeg Degrees to add to the Fused Heading register.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::AddFusedHeading(double angleDeg, int timeoutMs) {
+ int errCode = c_PigeonIMU_AddFusedHeading(_handle, angleDeg, timeoutMs);
+ return errCode;
+}
+/**
+ * Sets the Fused Heading register to match the current compass value.
+ *
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::SetFusedHeadingToCompass(int timeoutMs) {
+ int errCode = c_PigeonIMU_SetFusedHeadingToCompass(_handle, timeoutMs);
+ return errCode;
+}
+/**
+ * Set the declination for compass. Declination is the difference between
+ * Earth Magnetic north, and the geographic "True North".
+ *
+ * @param angleDegOffset Degrees to set Compass Declination to.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::SetCompassDeclination(double angleDegOffset, int timeoutMs) {
+ int errCode = c_PigeonIMU_SetCompassDeclination(_handle, angleDegOffset,
+ timeoutMs);
+ return errCode;
+}
+/**
+ * Sets the compass angle. Although compass is absolute [0,360) degrees, the
+ * continuous compass register holds the wrap-arounds.
+ *
+ * @param angleDeg Degrees to set continuous compass angle to.
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::SetCompassAngle(double angleDeg, int timeoutMs) {
+ int errCode = c_PigeonIMU_SetCompassAngle(_handle, angleDeg, timeoutMs);
+ return errCode;
+}
+//----------------------- Calibration routines -----------------------//
+/**
+ * Enters the Calbration mode. See the Pigeon IMU documentation for More
+ * information on Calibration.
+ *
+ * @param calMode Calibration to execute
+ * @param timeoutMs
+ * Timeout value in ms. If nonzero, function will wait for
+ * config success and report an error if it times out.
+ * If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::EnterCalibrationMode(CalibrationMode calMode, int timeoutMs) {
+ return c_PigeonIMU_EnterCalibrationMode(_handle, calMode, timeoutMs);
+}
+/**
+ * Get the status of the current (or previousley complete) calibration.
+ *
+ * @param statusToFill Container for the status information.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+int PigeonIMU::GetGeneralStatus(PigeonIMU::GeneralStatus & statusToFill) {
+ int state;
+ int currentMode;
+ int calibrationError;
+ int bCalIsBooting;
+ double tempC;
+ int upTimeSec;
+ int noMotionBiasCount;
+ int tempCompensationCount;
+ int lastError;
+
+ int errCode = c_PigeonIMU_GetGeneralStatus(_handle, &state, ¤tMode,
+ &calibrationError, &bCalIsBooting, &tempC, &upTimeSec,
+ &noMotionBiasCount, &tempCompensationCount, &lastError);
+
+ statusToFill.currentMode = (PigeonIMU::CalibrationMode) currentMode;
+ statusToFill.calibrationError = calibrationError;
+ statusToFill.bCalIsBooting = bCalIsBooting;
+ statusToFill.state = (PigeonIMU::PigeonState) state;
+ statusToFill.tempC = tempC;
+ statusToFill.noMotionBiasCount = noMotionBiasCount;
+ statusToFill.tempCompensationCount = tempCompensationCount;
+ statusToFill.upTimeSec = upTimeSec;
+ statusToFill.lastError = errCode;
+
+ /* build description string */
+ if (errCode != 0) { // same as NoComm
+ statusToFill.description =
+ "Status frame was not received, check wired connections and web-based config.";
+ } else if (statusToFill.bCalIsBooting) {
+ statusToFill.description =
+ "Pigeon is boot-caling to properly bias accel and gyro. Do not move Pigeon. When finished biasing, calibration mode will start.";
+ } else if (statusToFill.state == UserCalibration) {
+ /* mode specific descriptions */
+ switch (currentMode) {
+ case BootTareGyroAccel:
+ statusToFill.description =
+ "Boot-Calibration: Gyro and Accelerometer are being biased.";
+ break;
+ case Temperature:
+ statusToFill.description =
+ "Temperature-Calibration: Pigeon is collecting temp data and will finish when temp range is reached. "
+ "Do not move Pigeon.";
+ break;
+ case Magnetometer12Pt:
+ statusToFill.description =
+ "Magnetometer Level 1 calibration: Orient the Pigeon PCB in the 12 positions documented in the User's Manual.";
+ break;
+ case Magnetometer360:
+ statusToFill.description =
+ "Magnetometer Level 2 calibration: Spin robot slowly in 360' fashion. ";
+ break;
+ case Accelerometer:
+ statusToFill.description =
+ "Accelerometer Calibration: Pigeon PCB must be placed on a level source. Follow User's Guide for how to level surfacee. ";
+ break;
+ }
+ } else if (statusToFill.state == Ready) {
+ /* definitely not doing anything cal-related. So just instrument the motion driver state */
+ statusToFill.description =
+ "Pigeon is running normally. Last CAL error code was ";
+ statusToFill.description += std::to_string(calibrationError);
+ statusToFill.description += ".";
+ } else if (statusToFill.state == Initializing) {
+ /* definitely not doing anything cal-related. So just instrument the motion driver state */
+ statusToFill.description =
+ "Pigeon is boot-caling to properly bias accel and gyro. Do not move Pigeon.";
+ } else {
+ statusToFill.description = "Not enough data to determine status.";
+ }
+
+ return errCode;
+}
+//----------------------- General Error status -----------------------//
+/**
+ * Call GetLastError() generated by this object.
+ * Not all functions return an error code but can
+ * potentially report errors.
+ *
+ * This function can be used to retrieve those error codes.
+ *
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetLastError() {
+ return c_PigeonIMU_GetLastError(_handle);
+}
+
+
+//----------------------- Strongly typed Signal decoders -----------------------//
+/**
+ * Get 6d Quaternion data.
+ *
+ * @param wxyz Array to fill with quaternion data w[0], x[1], y[2], z[3]
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::Get6dQuaternion(double wxyz[4]) {
+ int errCode = c_PigeonIMU_Get6dQuaternion(_handle, wxyz);
+ return errCode;
+}
+/**
+ * Get Yaw, Pitch, and Roll data.
+ *
+ * @param ypr Array to fill with yaw[0], pitch[1], and roll[2] data
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetYawPitchRoll(double ypr[3]) {
+ int errCode = c_PigeonIMU_GetYawPitchRoll(_handle, ypr);
+ return errCode;
+}
+/**
+ * Get AccumGyro data.
+ * AccumGyro is the integrated gyro value on each axis.
+ *
+ * @param xyz_deg Array to fill with x[0], y[1], and z[2] AccumGyro data
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetAccumGyro(double xyz_deg[3]) {
+ int errCode = c_PigeonIMU_GetAccumGyro(_handle, xyz_deg);
+ return errCode;
+}
+/**
+ * Get the absolute compass heading.
+ * @return compass heading [0,360) degrees.
+ */
+double PigeonIMU::GetAbsoluteCompassHeading() {
+ double retval;
+ c_PigeonIMU_GetAbsoluteCompassHeading(_handle, &retval);
+ return retval;
+}
+/**
+ * Get the continuous compass heading.
+ * @return continuous compass heading [-23040, 23040) degrees. Use
+ * SetCompassHeading to modify the wrap-around portion.
+ */
+double PigeonIMU::GetCompassHeading() {
+ double retval;
+ c_PigeonIMU_GetCompassHeading(_handle, &retval);
+ return retval;
+}
+/**
+ * Gets the compass' measured magnetic field strength.
+ * @return field strength in Microteslas (uT).
+ */
+double PigeonIMU::GetCompassFieldStrength() {
+ double retval;
+ c_PigeonIMU_GetCompassFieldStrength(_handle, &retval);
+ return retval;
+}
+/**
+ * Gets the temperature of the pigeon.
+ *
+ * @return Temperature in ('C)
+ */
+double PigeonIMU::GetTemp() {
+ double tempC;
+ c_PigeonIMU_GetTemp(_handle, &tempC);
+ return tempC;
+}
+/**
+ * Gets the current Pigeon state
+ *
+ * @return PigeonState enum
+ */
+PigeonIMU::PigeonState PigeonIMU::GetState() {
+ int retval;
+ c_PigeonIMU_GetState(_handle, &retval);
+ return (PigeonIMU::PigeonState) retval;
+}
+/**
+ * Gets the current Pigeon uptime.
+ *
+ * @return How long has Pigeon been running in whole seconds. Value caps at
+ * 255.
+ */
+uint32_t PigeonIMU::GetUpTime() {
+ int timeSec;
+ c_PigeonIMU_GetUpTime(_handle, &timeSec);
+ return timeSec;
+}
+/**
+ * Get Raw Magnetometer data.
+ *
+ * @param rm_xyz Array to fill with x[0], y[1], and z[2] data
+ * Number is equal to 0.6 microTeslas per unit.
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetRawMagnetometer(int16_t rm_xyz[3]) {
+ int errCode = c_PigeonIMU_GetRawMagnetometer(_handle, rm_xyz);
+ return errCode;
+}
+/**
+ * Get Biased Magnetometer data.
+ *
+ * @param bm_xyz Array to fill with x[0], y[1], and z[2] data
+ * Number is equal to 0.6 microTeslas per unit.
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetBiasedMagnetometer(int16_t bm_xyz[3]) {
+ int errCode = c_PigeonIMU_GetBiasedMagnetometer(_handle, bm_xyz);
+ return errCode;
+}
+/**
+ * Get Biased Accelerometer data.
+ *
+ * @param ba_xyz Array to fill with x[0], y[1], and z[2] data
+ * These are in fixed point notation Q2.14. eg. 16384 = 1G
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetBiasedAccelerometer(int16_t ba_xyz[3]) {
+ int errCode = c_PigeonIMU_GetBiasedAccelerometer(_handle, ba_xyz);
+ return errCode;
+}
+/**
+ * Get Raw Gyro data.
+ *
+ * @param xyz_dps Array to fill with x[0], y[1], and z[2] data in degrees per second.
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetRawGyro(double xyz_dps[3]) {
+ int errCode = c_PigeonIMU_GetRawGyro(_handle, xyz_dps);
+ return errCode;
+}
+/**
+ * Get Accelerometer tilt angles.
+ *
+ * @param tiltAngles Array to fill with x[0], y[1], and z[2] angles in degrees.
+ * @return The last ErrorCode generated.
+ */
+int PigeonIMU::GetAccelerometerAngles(double tiltAngles[3]) {
+ int errCode = c_PigeonIMU_GetAccelerometerAngles(_handle, tiltAngles);
+ return errCode;
+}
+/**
+ * Get the current Fusion Status (including fused heading)
+ *
+ * @param status object reference to fill with fusion status flags.
+ * Caller may pass null if flags are not needed.
+ * @return The fused heading in degrees.
+ */
+double PigeonIMU::GetFusedHeading(FusionStatus & status) {
+ int bIsFusing, bIsValid;
+ double fusedHeading;
+ int lastError;
+
+ int errCode = c_PigeonIMU_GetFusedHeading2(_handle, &bIsFusing, &bIsValid,
+ &fusedHeading, &lastError);
+
+ std::string description;
+
+ if (errCode != 0) {
+ bIsFusing = false;
+ bIsValid = false;
+ description =
+ "Could not receive status frame. Check wiring and web-config.";
+ } else {
+ if (bIsValid == false) {
+ description = "Fused Heading is not valid.";
+ } else if (bIsFusing == false) {
+ description = "Fused Heading is valid.";
+ } else {
+ description = "Fused Heading is valid and is fusing compass.";
+ }
+ }
+
+ /* fill caller's struct */
+ status.heading = fusedHeading;
+ status.bIsFusing = (bool) bIsFusing;
+ status.bIsValid = (bool) bIsValid;
+ status.description = description;
+ status.lastError = errCode;
+
+ return fusedHeading;
+}
+/**
+ * Gets the Fused Heading
+ *
+ * @return The fused heading in degrees.
+ */
+double PigeonIMU::GetFusedHeading() {
+ double fusedHeading;
+ c_PigeonIMU_GetFusedHeading1(_handle, &fusedHeading);
+ return fusedHeading;
+}
+//----------------------- Startup/Reset status -----------------------//
+/**
+ * Use HasResetOccurred() instead.
+ */
+uint32_t PigeonIMU::GetResetCount() {
+ int retval;
+ c_PigeonIMU_GetResetCount(_handle, &retval);
+ return retval;
+}
+uint32_t PigeonIMU::GetResetFlags() {
+ int retval;
+ c_PigeonIMU_GetResetCount(_handle, &retval);
+ return (uint32_t) retval;
+}
+/**
+ * @return holds the version of the device. Device must be powered cycled at least once.
+ */
+uint32_t PigeonIMU::GetFirmVers() {
+ int retval;
+ c_PigeonIMU_GetFirmwareVersion(_handle, &retval);
+ return retval;
+}
+/**
+ * @return true iff a reset has occurred since last call.
+ */
+bool PigeonIMU::HasResetOccurred() {
+ bool retval = false;
+ c_PigeonIMU_HasResetOccurred(_handle, &retval);
+ return retval;
+}
+
+/**
+ * Convert PigeonState to string.
+ * This function is static.
+ */
+std::string PigeonIMU::ToString(PigeonState state) {
+ std::string retval = "Unknown";
+ switch (state) {
+ case Initializing:
+ return "Initializing";
+ case Ready:
+ return "Ready";
+ case UserCalibration:
+ return "UserCalibration";
+ case NoComm:
+ return "NoComm";
+ }
+ return retval;
+}
+
+/**
+ * Convert CalibrationMode to string.
+ * This function is static.
+ */
+std::string PigeonIMU::ToString(CalibrationMode cm) {
+ std::string retval = "Unknown";
+ switch (cm) {
+ case BootTareGyroAccel:
+ return "BootTareGyroAccel";
+ case Temperature:
+ return "Temperature";
+ case Magnetometer12Pt:
+ return "Magnetometer12Pt";
+ case Magnetometer360:
+ return "Magnetometer360";
+ case Accelerometer:
+ return "Accelerometer";
+ }
+ return retval;
+}
+/**
+ * Sets the value of a custom parameter. This is for arbitrary use.
+ *
+ * Sometimes it is necessary to save calibration/declination/offset
+ * information in the device. Particularly if the
+ * device is part of a subsystem that can be replaced.
+ *
+ * @param newValue
+ * Value for custom parameter.
+ * @param paramIndex
+ * Index of custom parameter. [0-1]
+ * @param timeoutMs
+* Timeout value in ms. If nonzero, function will wait for
+* config success and report an error if it times out.
+* If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode PigeonIMU::ConfigSetCustomParam(int newValue, int paramIndex,
+ int timeoutMs) {
+ return c_PigeonIMU_ConfigSetCustomParam(_handle, newValue, paramIndex,
+ timeoutMs);
+}
+/**
+ * Gets the value of a custom parameter. This is for arbitrary use.
+ *
+ * Sometimes it is necessary to save calibration/declination/offset
+ * information in the device. Particularly if the
+ * device is part of a subsystem that can be replaced.
+ *
+ * @param paramIndex
+ * Index of custom parameter. [0-1]
+ * @param timeoutMs
+* Timeout value in ms. If nonzero, function will wait for
+* config success and report an error if it times out.
+* If zero, no blocking or checking is performed.
+ * @return Value of the custom param.
+ */
+int PigeonIMU::ConfigGetCustomParam(int paramIndex, int timeoutMs) {
+ int readValue;
+ c_PigeonIMU_ConfigGetCustomParam(_handle, &readValue, paramIndex,
+ timeoutMs);
+ return readValue;
+}
+/**
+ * Sets a parameter. Generally this is not used.
+ * This can be utilized in
+ * - Using new features without updating API installation.
+ * - Errata workarounds to circumvent API implementation.
+ * - Allows for rapid testing / unit testing of firmware.
+ *
+ * @param param
+ * Parameter enumeration.
+ * @param value
+ * Value of parameter.
+ * @param subValue
+ * Subvalue for parameter. Maximum value of 255.
+ * @param ordinal
+ * Ordinal of parameter.
+ * @param timeoutMs
+* Timeout value in ms. If nonzero, function will wait for
+* config success and report an error if it times out.
+* If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode PigeonIMU::ConfigSetParameter(ctre::phoenix::ParamEnum param, double value,
+ uint8_t subValue, int ordinal, int timeoutMs) {
+ return c_PigeonIMU_ConfigSetParameter(_handle, param, value, subValue,
+ ordinal, timeoutMs);
+
+}
+/**
+ * Gets a parameter. Generally this is not used.
+ * This can be utilized in
+ * - Using new features without updating API installation.
+ * - Errata workarounds to circumvent API implementation.
+ * - Allows for rapid testing / unit testing of firmware.
+ *
+ * @param param
+ * Parameter enumeration.
+ * @param ordinal
+ * Ordinal of parameter.
+ * @param timeoutMs
+* Timeout value in ms. If nonzero, function will wait for
+* config success and report an error if it times out.
+* If zero, no blocking or checking is performed.
+ * @return Value of parameter.
+ */
+double PigeonIMU::ConfigGetParameter(ctre::phoenix::ParamEnum param, int ordinal,
+ int timeoutMs) {
+ double value = 0;
+ c_PigeonIMU_ConfigGetParameter(_handle, param, &value, ordinal, timeoutMs);
+ return value;
+}
+
+
+//------ Frames ----------//
+/**
+ * Sets the period of the given status frame.
+ *
+ * @param statusFrame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @param timeoutMs
+* Timeout value in ms. If nonzero, function will wait for
+* config success and report an error if it times out.
+* If zero, no blocking or checking is performed.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode PigeonIMU::SetStatusFramePeriod(PigeonIMU_StatusFrame statusFrame,
+ int periodMs, int timeoutMs) {
+ return c_PigeonIMU_SetStatusFramePeriod(_handle, statusFrame, periodMs,
+ timeoutMs);
+}
+/**
+ * Gets the period of the given status frame.
+ *
+ * @param frame
+ * Frame to get the period of.
+ * @param timeoutMs
+* Timeout value in ms. If nonzero, function will wait for
+* config success and report an error if it times out.
+* If zero, no blocking or checking is performed.
+ * @return Period of the given status frame.
+ */
+int PigeonIMU::GetStatusFramePeriod(PigeonIMU_StatusFrame frame,
+ int timeoutMs) {
+ int periodMs = 0;
+ c_PigeonIMU_GetStatusFramePeriod(_handle, frame, &periodMs, timeoutMs);
+ return periodMs;
+}
+/**
+ * Sets the period of the given control frame.
+ *
+ * @param frame
+ * Frame whose period is to be changed.
+ * @param periodMs
+ * Period in ms for the given frame.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode PigeonIMU::SetControlFramePeriod(PigeonIMU_ControlFrame frame,
+ int periodMs) {
+ return c_PigeonIMU_SetControlFramePeriod(_handle, frame, periodMs);
+}
+//------ Firmware ----------//
+/**
+ * Gets the firmware version of the device.
+ *
+ * @return The firmware version of the device. Device must be powered
+ * cycled at least once.
+ */
+int PigeonIMU::GetFirmwareVersion() {
+ int retval = -1;
+ c_PigeonIMU_GetFirmwareVersion(_handle, &retval);
+ return retval;
+}
+//------ Faults ----------//
+/**
+ * Gets the fault status
+ *
+ * @param toFill
+ * Container for fault statuses.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode PigeonIMU::GetFaults(PigeonIMU_Faults & toFill) {
+ int faultBits;
+ ErrorCode retval = c_PigeonIMU_GetFaults(_handle, &faultBits);
+ toFill = PigeonIMU_Faults(faultBits);
+ return retval;
+}
+/**
+ * Gets the sticky fault status
+ *
+ * @param toFill
+ * Container for sticky fault statuses.
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode PigeonIMU::GetStickyFaults(PigeonIMU_StickyFaults & toFill) {
+ int faultBits;
+ ErrorCode retval = c_PigeonIMU_GetFaults(_handle, &faultBits);
+ toFill = PigeonIMU_StickyFaults(faultBits);
+ return retval;
+}
+/**
+ * Clears the Sticky Faults
+ *
+ * @return Error Code generated by function. 0 indicates no error.
+ */
+ErrorCode PigeonIMU::ClearStickyFaults(int timeoutMs) {
+ return c_PigeonIMU_ClearStickyFaults(_handle, timeoutMs);
+}
+
+} // namespace signals
+} // namespace phoenix
+} // namespace ctre
+#endif // CTR_EXCLUDE_WPILIB_CLASSES
diff --git a/cpp/src/Stopwatch.cpp b/cpp/src/Stopwatch.cpp
new file mode 100644
index 0000000..522965b
--- /dev/null
+++ b/cpp/src/Stopwatch.cpp
@@ -0,0 +1,20 @@
+#include "ctre/phoenix/Stopwatch.h"
+
+namespace ctre {
+namespace phoenix {
+
+void Stopwatch::Start(){
+ _t0 = (float)clock();
+}
+unsigned int Stopwatch::DurationMs(){
+ return Stopwatch::Duration() * 1000;
+}
+float Stopwatch::Duration(){
+ _t1 = (float)clock();
+ long retval = _t1 - _t0;
+ if(retval < 0) retval = 0;
+ return retval * _scalar;
+}
+
+} // namespace phoenix
+}
diff --git a/cpp/src/Tasking/ButtonMonitor.cpp b/cpp/src/Tasking/ButtonMonitor.cpp
new file mode 100644
index 0000000..d420e34
--- /dev/null
+++ b/cpp/src/Tasking/ButtonMonitor.cpp
@@ -0,0 +1,46 @@
+#include "ctre/phoenix/Tasking/ButtonMonitor.h"
+#include <GenericHID.h> // WPILIB
+
+#ifndef CTR_EXCLUDE_WPILIB_CLASSES
+
+namespace ctre {
+namespace phoenix {
+namespace tasking {
+
+ButtonMonitor::ButtonMonitor(frc::GenericHID * controller, int buttonIndex,
+ IButtonPressEventHandler * ButtonPressEventHandler) {
+ _gameCntrlr = controller;
+ _btnIdx = buttonIndex;
+ _handler = ButtonPressEventHandler;
+}
+ButtonMonitor::ButtonMonitor(const ButtonMonitor & rhs) {
+ _gameCntrlr = rhs._gameCntrlr;
+ _btnIdx = rhs._btnIdx;
+ _handler = rhs._handler;
+}
+
+void ButtonMonitor::Process() {
+ bool down = ((frc::GenericHID*)_gameCntrlr)->GetRawButton(_btnIdx);
+
+ if (!_isDown && down)
+ _handler->OnButtonPress(_btnIdx, down);
+
+ _isDown = down;
+}
+
+void ButtonMonitor::OnStart() {
+}
+void ButtonMonitor::OnLoop() {
+ Process();
+}
+bool ButtonMonitor::IsDone() {
+ return false;
+}
+void ButtonMonitor::OnStop() {
+}
+
+} // namespace tasking
+} // namespace phoenix
+} // namespace ctre
+
+#endif // CTR_EXCLUDE_WPILIB_CLASSES
diff --git a/cpp/src/Tasking/Schedulers/ConcurrentScheduler.cpp b/cpp/src/Tasking/Schedulers/ConcurrentScheduler.cpp
new file mode 100644
index 0000000..c8d6773
--- /dev/null
+++ b/cpp/src/Tasking/Schedulers/ConcurrentScheduler.cpp
@@ -0,0 +1,88 @@
+#include "ctre/phoenix/Tasking/Schedulers/ConcurrentScheduler.h"
+
+namespace ctre {
+namespace phoenix {
+namespace tasking {
+namespace schedulers {
+
+ConcurrentScheduler::ConcurrentScheduler() {
+}
+ConcurrentScheduler::~ConcurrentScheduler() {
+}
+void ConcurrentScheduler::Add(ILoopable *aLoop, bool enable) {
+ _loops.push_back(aLoop);
+ _enabs.push_back(enable);
+}
+void ConcurrentScheduler::RemoveAll() {
+ _loops.clear();
+ _enabs.clear();
+}
+void ConcurrentScheduler::Start(ILoopable* toStart) {
+ for (int i = 0; i < (int) _loops.size(); ++i) {
+ ILoopable* lp = (ILoopable*) _loops[i];
+
+ if (lp == toStart) {
+ _enabs[i] = true;
+ lp->OnStart();
+ return;
+ }
+ }
+
+}
+void ConcurrentScheduler::Stop(ILoopable* toStop) {
+ for (int i = 0; i < (int) _loops.size(); ++i) {
+ ILoopable* lp = (ILoopable*) _loops[i];
+
+ if (lp == toStop) {
+ _enabs[i] = false;
+ lp->OnStop();
+ return;
+ }
+ }
+}
+void ConcurrentScheduler::StartAll() { //All Loops
+ for (auto loop : _loops) {
+ loop->OnStart();
+ }
+ for (auto enable : _enabs) {
+ enable = true;
+ }
+}
+void ConcurrentScheduler::StopAll() { //All Loops
+ for (auto loop : _loops) {
+ loop->OnStop();
+ }
+ for (auto enable : _enabs) {
+ enable = false;
+ }
+}
+void ConcurrentScheduler::Process() {
+ for (int i = 0; i < (int) _loops.size(); ++i) {
+ ILoopable* loop = (ILoopable*) _loops[i];
+ bool en = (bool) _enabs[i];
+ if (en) {
+ loop->OnLoop();
+ } else {
+ /* Current ILoopable is turned off, don't call OnLoop for it */
+ }
+ }
+}
+/* ILoopable */
+void ConcurrentScheduler::OnStart() {
+ ConcurrentScheduler::StartAll();
+}
+void ConcurrentScheduler::OnLoop() {
+ ConcurrentScheduler::Process();
+}
+void ConcurrentScheduler::OnStop() {
+ ConcurrentScheduler::StopAll();
+}
+bool ConcurrentScheduler::IsDone() {
+ return false;
+}
+
+} // namespace schedulers
+} // namespace tasking
+} // namespace phoenix
+} // namespace ctre
+
diff --git a/cpp/src/Tasking/Schedulers/SequentialScheduler.cpp b/cpp/src/Tasking/Schedulers/SequentialScheduler.cpp
new file mode 100644
index 0000000..edac7bd
--- /dev/null
+++ b/cpp/src/Tasking/Schedulers/SequentialScheduler.cpp
@@ -0,0 +1,86 @@
+#include "ctre/phoenix/Tasking/Schedulers/SequentialScheduler.h"
+
+namespace ctre {
+namespace phoenix {
+namespace tasking {
+namespace schedulers {
+
+SequentialScheduler::SequentialScheduler() {
+}
+SequentialScheduler::~SequentialScheduler() {
+}
+void SequentialScheduler::Add(ILoopable *aLoop) {
+ _loops.push_back(aLoop);
+}
+ILoopable * SequentialScheduler::GetCurrent() {
+ ILoopable* retval = nullptr;
+ if (_idx < _loops.size()) {
+ retval = _loops[_idx];
+ }
+ return retval;
+}
+
+void SequentialScheduler::RemoveAll() {
+ _loops.clear();
+}
+void SequentialScheduler::Start() {
+ /* reset iterator regardless of loopable container */
+ _idx = 0;
+ /* do we have any to loop? */
+ if (_idx >= _loops.size()) {
+ /* there are no loopables */
+ _running = false;
+ } else {
+ /* start the first one */
+ _loops[_idx]->OnStart();
+ _running = true;
+ }
+
+}
+void SequentialScheduler::Stop() {
+ for (unsigned int i = 0; i < _loops.size(); i++) {
+ _loops[i]->OnStop();
+ }
+ _running = false;
+}
+void SequentialScheduler::Process() {
+ if (_idx < _loops.size()) {
+ if (_running) {
+ ILoopable* loop = _loops[_idx];
+ loop->OnLoop();
+ if (loop->IsDone()) {
+ /* iterate to next loopable */
+ ++_idx;
+ if (_idx < _loops.size()) {
+ /* callback to start it */
+ _loops[_idx]->OnStart();
+ }
+ }
+ }
+ } else {
+ _running = false;
+ }
+}
+/* ILoopable */
+void SequentialScheduler::OnStart() {
+ SequentialScheduler::Start();
+}
+void SequentialScheduler::OnLoop() {
+ SequentialScheduler::Process();
+}
+void SequentialScheduler::OnStop() {
+ SequentialScheduler::Stop();
+}
+bool SequentialScheduler::IsDone() {
+ /* Have to return something to know if we are done */
+ if (_running == false)
+ return true;
+ else
+ return false;
+}
+
+} // namespace schedulers
+} // namespace tasking
+} // namespace phoenix
+} // namespace ctre
+
diff --git a/cpp/src/Utilities.cpp b/cpp/src/Utilities.cpp
new file mode 100644
index 0000000..5c749b2
--- /dev/null
+++ b/cpp/src/Utilities.cpp
@@ -0,0 +1,69 @@
+#include "ctre/phoenix/Utilities.h"
+
+namespace ctre {
+namespace phoenix {
+
+float Utilities::abs(float f) {
+ if (f >= 0)
+ return f;
+ return -f;
+}
+
+float Utilities::bound(float value, float capValue) {
+ if (value > capValue)
+ return capValue;
+ if (value < -capValue)
+ return -capValue;
+ return value;
+}
+
+float Utilities::cap(float value, float peak) {
+ if (value < -peak)
+ return -peak;
+ if (value > +peak)
+ return +peak;
+ return value;
+}
+
+bool Utilities::Contains(char array[], char item) {
+ //Not sure how to implement in c++ yet, made private
+ (void)array;
+ (void)item;
+ return false;
+}
+
+void Utilities::Deadband(float &value, float deadband) {
+ if (value < -deadband) {
+ /* outside of deadband */
+ } else if (value > +deadband) {
+ /* outside of deadband */
+ } else {
+ /* within 10% so zero it */
+ value = 0;
+ }
+}
+
+bool Utilities::IsWithin(float value, float compareTo, float allowDelta) {
+ float f = value - compareTo;
+ if (f < 0)
+ f *= -1;
+ return (f < allowDelta);
+}
+
+int Utilities::SmallerOf(int value_1, int value_2) {
+ if (value_1 > value_2)
+ return value_2;
+ else
+ return value_1;
+}
+
+void Utilities::Split_1(float forward, float turn, float *left, float *right) {
+ *left = forward + turn;
+ *right = forward - turn;
+}
+void Utilities::Split_2(float left, float right, float *forward, float *turn) {
+ *forward = (left + right) * 0.5f;
+ *turn = (left - right) * 0.5f;
+}
+}
+}