#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/InvertType.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"
#include "ctre/phoenix/motion/BufferedTrajectoryPointStream.h"
#include "ctre/phoenix/CANBusAddressable.h"
#include "ctre/phoenix/CustomParamConfiguration.h"
#include "ctre/phoenix/motorcontrol/VictorSPXSimCollection.h"
#include "ctre/phoenix/sensors/SensorVelocityMeasPeriod.h"

#include <string>

/* forward proto's */
/** namespace ctre */
namespace ctre {
	/** namespace phoenix */
	namespace phoenix {
		/** namespace motorcontrol */
		namespace motorcontrol {
			/** namespace lowlevel */
			namespace lowlevel {
				class MotControllerWithBuffer_LowLevel;
				class MotController_LowLevel;
			}
		}
	}
}

namespace ctre {
	namespace phoenix {
		namespace motorcontrol {
			/** namespace can */
			namespace can {

				/**
				 * Base set of configurables related to PID
				 */
				struct BasePIDSetConfiguration {

					/**
					 *  Feedback coefficient of selected sensor
					 */
					double selectedFeedbackCoefficient;

					BasePIDSetConfiguration() :
						selectedFeedbackCoefficient(1.0)
					{
					}

					/**
					 * @return String representation of configs
					 */
					std::string toString() {
						return toString("");
					}

					/**
					 * @param prependString
					 *              String to prepend to configs
					 * @return String representation of configs
					 */
					std::string toString(const std::string& prependString) {
						return prependString + ".selectedFeedbackCoefficient = " + std::to_string(selectedFeedbackCoefficient) + ";\n";

					}
				};// struct BasePIDSetConfiguration

				/**
				 * Configurations for filters
				 */
				struct FilterConfiguration {

					/**
					 * Remote Sensor's device ID
					 */
					int remoteSensorDeviceID;
					/**
					 * The remote sensor device and signal type to bind.
					 */
					RemoteSensorSource remoteSensorSource;

					FilterConfiguration() :
						remoteSensorDeviceID(0),
						remoteSensorSource(RemoteSensorSource::RemoteSensorSource_Off)
					{
					}

					/**
					 * @return string representation of currently selected configs
					 */
					std::string toString() {
						return toString("");
					}

					/**
					 * @param prependString String to prepend to all the configs
					 * @return string representation fo currently selected configs
					 */
					std::string toString(std::string prependString) {
						std::string retstr = prependString + ".remoteSensorDeviceID = " + std::to_string(remoteSensorDeviceID) + ";\n";
						retstr += prependString + ".remoteSensorSource = " + RemoteSensorSourceRoutines::toString(remoteSensorSource) + ";\n";
						return retstr;
					}


				}; // struct FilterConfiguration

				/**
				 * Util class to help with filter configs
				 */
				struct FilterConfigUtil {
				private:
					static FilterConfiguration _default;
				public:
					/**
					 * Determine if specified value is different from default
					 * @param settings settings to compare against
					 * @return if specified value is different from default
					 * @{
					 */
					static bool RemoteSensorDeviceIDDifferent(const FilterConfiguration& settings) { return (!(settings.remoteSensorDeviceID == _default.remoteSensorDeviceID)); }
					static bool RemoteSensorSourceDifferent(const FilterConfiguration& settings) { return (!(settings.remoteSensorSource == _default.remoteSensorSource)); }
					static bool FilterConfigurationDifferent(const FilterConfiguration& settings) { return RemoteSensorDeviceIDDifferent(settings) || RemoteSensorSourceDifferent(settings); }
					/** @} */
				};

				/**
				 * Configurables available to a slot
				 */
				struct SlotConfiguration {

					/**
					 * P Gain
					 *
					 * This is multiplied by closed loop error in sensor units.
					 * Note the closed loop output interprets a final value of 1023 as full output.
					 * So use a gain of '0.25' to get full output if err is 4096u (Mag Encoder 1 rotation)
					 */
					double kP;
					/**
					 * I Gain
					 *
					 * This is multiplied by accumulated closed loop error in sensor units every PID Loop.
					 * Note the closed loop output interprets a final value of 1023 as full output.
					 * So use a gain of '0.00025' to get full output if err is 4096u for 1000 loops (accumulater holds 4,096,000),
					 * [which is equivalent to one CTRE mag encoder rotation for 1000 milliseconds].
					 */
					double kI;
					/**
					 * D Gain
					 *
					 * This is multiplied by derivative error (sensor units per PID loop, typically 1ms).
					 * Note the closed loop output interprets a final value of 1023 as full output.
					 * So use a gain of '250' to get full output if derr is 4096u (Mag Encoder 1 rotation) per 1000 loops (typ 1 sec)
					 */
					double kD;
					/**
					 * F Gain
					 *
					 * See documentation for calculation details.
					 * If using velocity, motion magic, or motion profile,
					 * use (1023 * duty-cycle / sensor-velocity-sensor-units-per-100ms).
					 *
					 */
					double kF;
					/**
					 * Integral zone (in native units)
					 *
					 * 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.
					 */
					double integralZone;
					/**
					 * Allowable closed loop error to neutral (in native units)
					 *
					 */
					double allowableClosedloopError;
					/**
					 * Max integral accumulator (in native units)
					 */
					double maxIntegralAccumulator;
					/**
					 * Peak output from closed loop [0,1]
					 */
					double closedLoopPeakOutput;
					/**
					 * Desired period of closed loop [1,64]ms
					 */
					int closedLoopPeriod;

					SlotConfiguration() :
						kP(0.0),
						kI(0.0),
						kD(0.0),
						kF(0.0),
						integralZone(0.0),
						allowableClosedloopError(0.0),
						maxIntegralAccumulator(0.0),
						closedLoopPeakOutput(1.0),
						closedLoopPeriod(1)
					{
					}

					/**
					 * @return String representation of configs
					 */
					std::string toString() {
						return toString("");
					}

					/**
					 * @param prependString
					 *              String to prepend to configs
					 * @return String representation of configs
					 */
					std::string toString(std::string prependString) {

						std::string retstr = prependString + ".kP = " + std::to_string(kP) + ";\n";
						retstr += prependString + ".kI = " + std::to_string(kI) + ";\n";
						retstr += prependString + ".kD = " + std::to_string(kD) + ";\n";
						retstr += prependString + ".kF = " + std::to_string(kF) + ";\n";
						retstr += prependString + ".integralZone = " + std::to_string(integralZone) + ";\n";
						retstr += prependString + ".allowableClosedloopError = " + std::to_string(allowableClosedloopError) + ";\n";
						retstr += prependString + ".maxIntegralAccumulator = " + std::to_string(maxIntegralAccumulator) + ";\n";
						retstr += prependString + ".closedLoopPeakOutput = " + std::to_string(closedLoopPeakOutput) + ";\n";
						retstr += prependString + ".closedLoopPeriod = " + std::to_string(closedLoopPeriod) + ";\n";

						return retstr;

					}

				};// struct BaseSlotConfiguration

				/**
				 * Util Class to help with slot configs
				 */
				class SlotConfigUtil {
				private:
					static struct SlotConfiguration _default;
				public:
					/**
					 * Determine if specified value is different from default
					 * @param settings settings to compare against
					 * @return if specified value is different from default
					 * @{
					 */
					static bool KPDifferent(const SlotConfiguration& settings) { return (!(settings.kP == _default.kP)); }
					static bool KIDifferent(const SlotConfiguration& settings) { return (!(settings.kI == _default.kI)); }
					static bool KDDifferent(const SlotConfiguration& settings) { return (!(settings.kD == _default.kD)); }
					static bool KFDifferent(const SlotConfiguration& settings) { return (!(settings.kF == _default.kF)); }
					static bool IntegralZoneDifferent(const SlotConfiguration& settings) { return (!(settings.integralZone == _default.integralZone)); }
					static bool AllowableClosedloopErrorDifferent(const SlotConfiguration& settings) { return (!(settings.allowableClosedloopError == _default.allowableClosedloopError)); }
					static bool MaxIntegralAccumulatorDifferent(const SlotConfiguration& settings) { return (!(settings.maxIntegralAccumulator == _default.maxIntegralAccumulator)); }
					static bool ClosedLoopPeakOutputDifferent(const SlotConfiguration& settings) { return (!(settings.closedLoopPeakOutput == _default.closedLoopPeakOutput)); }
					static bool ClosedLoopPeriodDifferent(const SlotConfiguration& settings) { return (!(settings.closedLoopPeriod == _default.closedLoopPeriod)); }
					/** @} */
				};


				/**
				 * Configurables available to base motor controllers
				 */
				struct BaseMotorControllerConfiguration : ctre::phoenix::CustomParamConfiguration {
					/**
					 * Seconds to go from 0 to full in open loop
					 */
					double openloopRamp;
					/**
					 * Seconds to go from 0 to full in closed loop
					 */
					double closedloopRamp;
					/**
					 * Peak output in forward direction [0,1]
					 */
					double peakOutputForward;
					/**
					 * Peak output in reverse direction [-1,0]
					 */
					double peakOutputReverse;
					/**
					 * Nominal/Minimum output in forward direction [0,1]
					 */
					double nominalOutputForward;
					/**
					 * Nominal/Minimum output in reverse direction [-1,0]
					 */
					double nominalOutputReverse;
					/**
					 * Neutral deadband [0.001, 0.25]
					 */
					double neutralDeadband;
					/**
					 * 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.
					 */
					double voltageCompSaturation;
					/**
					 * Number of samples in rolling average for voltage
					 */
					int voltageMeasurementFilter;
					/**
					 * Desired period for velocity measurement
					 */
					ctre::phoenix::sensors::SensorVelocityMeasPeriod velocityMeasurementPeriod;
					/**
					 * Desired window for velocity measurement
					 */
					int velocityMeasurementWindow;
					/**
					 * Threshold for soft limits in forward direction (in raw sensor units)
					 */
					double forwardSoftLimitThreshold;
					/**
					 * Threshold for soft limits in reverse direction (in raw sensor units)
					 */
					double reverseSoftLimitThreshold;
					/**
					 * Enable forward soft limit
					 */
					bool forwardSoftLimitEnable;
					/**
					 * Enable reverse soft limit
					 */
					bool reverseSoftLimitEnable;
					/**
					 * Configuration for slot 0
					 */
					SlotConfiguration slot0;
					/**
					 * Configuration for slot 1
					 */
					SlotConfiguration slot1;
					/**
					 * Configuration for slot 2
					 */
					SlotConfiguration slot2;
					/**
					 * Configuration for slot 3
					 */
					SlotConfiguration slot3;
					/**
					 * PID polarity inversion
					 *
					 * Standard Polarity:
					 *    Primary Output = PID0 + PID1,
					 *    Auxiliary Output = PID0 - PID1,
					 *
					 * Inverted Polarity:
					 *    Primary Output = PID0 - PID1,
					 *    Auxiliary Output = PID0 + PID1,
					 */
					bool auxPIDPolarity;
					/**
					 * Configuration for RemoteFilter 0
					 */
					FilterConfiguration remoteFilter0;
					/**
					 * Configuration for RemoteFilter 1
					 */
					FilterConfiguration remoteFilter1;
					/**
					 * Motion Magic cruise velocity in raw sensor units per 100 ms.
					 */
					double motionCruiseVelocity;
					/**
					 * Motion Magic acceleration in (raw sensor units per 100 ms) per second.
					 */
					double motionAcceleration;
					/**
					 * Zero to use trapezoidal motion during motion magic.  [1,8] for S-Curve, higher value for greater smoothing.
					 */
					int motionCurveStrength;
					/**
					 * Motion profile base trajectory period in milliseconds.
					 *
					 * The period specified in a trajectory point will be
					 * added on to this value
					 */
					int motionProfileTrajectoryPeriod;
					/**
					 * Determine whether feedback sensor is continuous or not
					 */
					bool feedbackNotContinuous;
					/**
					 * Disable neutral'ing the motor when remote sensor is lost on CAN bus
					 */
					bool remoteSensorClosedLoopDisableNeutralOnLOS;
					/**
					 * Clear the position on forward limit
					 */
					bool clearPositionOnLimitF;
					/**
					 * Clear the position on reverse limit
					 */
					bool clearPositionOnLimitR;
					/**
					 * Clear the position on index
					 */
					bool clearPositionOnQuadIdx;
					/**
					 * Disable neutral'ing the motor when remote limit switch is lost on CAN bus
					 */
					bool limitSwitchDisableNeutralOnLOS;
					/**
					 * Disable neutral'ing the motor when remote soft limit is lost on CAN bus
					 */
					bool softLimitDisableNeutralOnLOS;
					/**
					 * Number of edges per rotation for a tachometer sensor
					 */
					int pulseWidthPeriod_EdgesPerRot;
					/**
					 * Desired window size for a tachometer sensor
					 */
					int pulseWidthPeriod_FilterWindowSz;
					/**
					* Enable motion profile trajectory point interpolation (defaults to true).
					*/
					bool trajectoryInterpolationEnable;

					BaseMotorControllerConfiguration() :
						openloopRamp(0.0),
						closedloopRamp(0.0),
						peakOutputForward(1.0),
						peakOutputReverse(-1.0),
						nominalOutputForward(0.0),
						nominalOutputReverse(0.0),
						neutralDeadband(41.0 / 1023.0),
						voltageCompSaturation(0.0),
						voltageMeasurementFilter(32),
						velocityMeasurementPeriod(ctre::phoenix::sensors::SensorVelocityMeasPeriod::Period_100Ms),
						velocityMeasurementWindow(64),
						forwardSoftLimitThreshold(0.0),
						reverseSoftLimitThreshold(0.0),
						forwardSoftLimitEnable(false),
						reverseSoftLimitEnable(false),
						auxPIDPolarity(false),
						motionCruiseVelocity(0.0),
						motionAcceleration(0.0),
						motionCurveStrength(0),
						motionProfileTrajectoryPeriod(0),
						feedbackNotContinuous(false),
						remoteSensorClosedLoopDisableNeutralOnLOS(false),
						clearPositionOnLimitF(false),
						clearPositionOnLimitR(false),
						clearPositionOnQuadIdx(false),
						limitSwitchDisableNeutralOnLOS(false),
						softLimitDisableNeutralOnLOS(false),
						pulseWidthPeriod_EdgesPerRot(1),
						pulseWidthPeriod_FilterWindowSz(1),
						trajectoryInterpolationEnable(true)

					{
					}

					/**
					 * @return String representation of configs
					 */
					std::string toString() {
						return toString("");
					}

					/**
					 * @param prependString
					 *              String to prepend to configs
					 * @return String representation of configs
					 */
					std::string toString(std::string prependString) {

						std::string retstr = prependString + ".openloopRamp = " + std::to_string(openloopRamp) + ";\n";
						retstr += prependString + ".closedloopRamp = " + std::to_string(closedloopRamp) + ";\n";
						retstr += prependString + ".peakOutputForward = " + std::to_string(peakOutputForward) + ";\n";
						retstr += prependString + ".peakOutputReverse = " + std::to_string(peakOutputReverse) + ";\n";
						retstr += prependString + ".nominalOutputForward = " + std::to_string(nominalOutputForward) + ";\n";
						retstr += prependString + ".nominalOutputReverse = " + std::to_string(nominalOutputReverse) + ";\n";
						retstr += prependString + ".neutralDeadband = " + std::to_string(neutralDeadband) + ";\n";
						retstr += prependString + ".voltageCompSaturation = " + std::to_string(voltageCompSaturation) + ";\n";
						retstr += prependString + ".voltageMeasurementFilter = " + std::to_string(voltageMeasurementFilter) + ";\n";
						retstr += prependString + ".velocityMeasurementPeriod = " + ctre::phoenix::sensors::SensorVelocityMeasPeriodRoutines::toString(velocityMeasurementPeriod) + ";\n";
						retstr += prependString + ".velocityMeasurementWindow = " + std::to_string(velocityMeasurementWindow) + ";\n";
						retstr += prependString + ".forwardSoftLimitThreshold = " + std::to_string(forwardSoftLimitThreshold) + ";\n";
						retstr += prependString + ".reverseSoftLimitThreshold = " + std::to_string(reverseSoftLimitThreshold) + ";\n";
						retstr += prependString + ".forwardSoftLimitEnable = " + std::to_string(forwardSoftLimitEnable) + ";\n";
						retstr += prependString + ".reverseSoftLimitEnable = " + std::to_string(reverseSoftLimitEnable) + ";\n";
						retstr += slot0.toString(prependString + ".slot0");
						retstr += slot1.toString(prependString + ".slot1");
						retstr += slot2.toString(prependString + ".slot2");
						retstr += slot3.toString(prependString + ".slot3");
						retstr += prependString + ".auxPIDPolarity = " + std::to_string(auxPIDPolarity) + ";\n";
						retstr += remoteFilter0.toString(prependString + ".remoteFilter0");
						retstr += remoteFilter1.toString(prependString + ".remoteFilter1");
						retstr += prependString + ".motionCruiseVelocity = " + std::to_string(motionCruiseVelocity) + ";\n";
						retstr += prependString + ".motionAcceleration = " + std::to_string(motionAcceleration) + ";\n";
						retstr += prependString + ".motionCurveStrength = " + std::to_string(motionCurveStrength) + ";\n";
						retstr += prependString + ".motionProfileTrajectoryPeriod = " + std::to_string(motionProfileTrajectoryPeriod) + ";\n";
						retstr += prependString + ".feedbackNotContinuous = " + std::to_string(feedbackNotContinuous) + ";\n";
						retstr += prependString + ".remoteSensorClosedLoopDisableNeutralOnLOS = " + std::to_string(remoteSensorClosedLoopDisableNeutralOnLOS) + ";\n";
						retstr += prependString + ".clearPositionOnLimitF = " + std::to_string(clearPositionOnLimitF) + ";\n";
						retstr += prependString + ".clearPositionOnLimitR = " + std::to_string(clearPositionOnLimitR) + ";\n";
						retstr += prependString + ".clearPositionOnQuadIdx = " + std::to_string(clearPositionOnQuadIdx) + ";\n";
						retstr += prependString + ".limitSwitchDisableNeutralOnLOS = " + std::to_string(limitSwitchDisableNeutralOnLOS) + ";\n";
						retstr += prependString + ".softLimitDisableNeutralOnLOS = " + std::to_string(softLimitDisableNeutralOnLOS) + ";\n";
						retstr += prependString + ".pulseWidthPeriod_EdgesPerRot = " + std::to_string(pulseWidthPeriod_EdgesPerRot) + ";\n";
						retstr += prependString + ".pulseWidthPeriod_FilterWindowSz = " + std::to_string(pulseWidthPeriod_FilterWindowSz) + ";\n";
						retstr += prependString + ".trajectoryInterpolationEnable = " + std::to_string(trajectoryInterpolationEnable) + ";\n";

						retstr += CustomParamConfiguration::toString(prependString);

						return retstr;
					}


				};// struct BaseMotorControllerConfiguration

				/**
				 * Util class to help with Base Motor Controller configs
				 */
				class BaseMotorControllerUtil : public ctre::phoenix::CustomParamConfigUtil {
				private:
					static struct BaseMotorControllerConfiguration _default;
				public:
					/**
					 * Determine if specified value is different from default
					 * @param settings settings to compare against
					 * @return if specified value is different from default
					 * @{
					 */
					static bool OpenloopRampDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.openloopRamp == _default.openloopRamp)) || !settings.enableOptimizations; }
					static bool ClosedloopRampDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.closedloopRamp == _default.closedloopRamp)) || !settings.enableOptimizations; }
					static bool PeakOutputForwardDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.peakOutputForward == _default.peakOutputForward)) || !settings.enableOptimizations; }
					static bool PeakOutputReverseDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.peakOutputReverse == _default.peakOutputReverse)) || !settings.enableOptimizations; }
					static bool NominalOutputForwardDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.nominalOutputForward == _default.nominalOutputForward)) || !settings.enableOptimizations; }
					static bool NominalOutputReverseDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.nominalOutputReverse == _default.nominalOutputReverse)) || !settings.enableOptimizations; }
					static bool NeutralDeadbandDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.neutralDeadband == _default.neutralDeadband)) || !settings.enableOptimizations; }
					static bool VoltageCompSaturationDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.voltageCompSaturation == _default.voltageCompSaturation)) || !settings.enableOptimizations; }
					static bool VoltageMeasurementFilterDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.voltageMeasurementFilter == _default.voltageMeasurementFilter)) || !settings.enableOptimizations; }
					static bool VelocityMeasurementPeriodDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.velocityMeasurementPeriod == _default.velocityMeasurementPeriod)) || !settings.enableOptimizations; }
					static bool VelocityMeasurementWindowDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.velocityMeasurementWindow == _default.velocityMeasurementWindow)) || !settings.enableOptimizations; }
					static bool ForwardSoftLimitThresholdDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.forwardSoftLimitThreshold == _default.forwardSoftLimitThreshold)) || !settings.enableOptimizations; }
					static bool ReverseSoftLimitThresholdDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.reverseSoftLimitThreshold == _default.reverseSoftLimitThreshold)) || !settings.enableOptimizations; }
					static bool ForwardSoftLimitEnableDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.forwardSoftLimitEnable == _default.forwardSoftLimitEnable)) || !settings.enableOptimizations; }
					static bool ReverseSoftLimitEnableDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.reverseSoftLimitEnable == _default.reverseSoftLimitEnable)) || !settings.enableOptimizations; }
					static bool AuxPIDPolarityDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.auxPIDPolarity == _default.auxPIDPolarity)) || !settings.enableOptimizations; }
					static bool MotionCruiseVelocityDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.motionCruiseVelocity == _default.motionCruiseVelocity)) || !settings.enableOptimizations; }
					static bool MotionAccelerationDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.motionAcceleration == _default.motionAcceleration)) || !settings.enableOptimizations; }
					static bool MotionSCurveStrength(const BaseMotorControllerConfiguration& settings) { return (!(settings.motionCurveStrength == _default.motionCurveStrength)) || !settings.enableOptimizations; }
					static bool MotionProfileTrajectoryPeriodDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.motionProfileTrajectoryPeriod == _default.motionProfileTrajectoryPeriod)) || !settings.enableOptimizations; }
					static bool FeedbackNotContinuousDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.feedbackNotContinuous == _default.feedbackNotContinuous)) || !settings.enableOptimizations; }
					static bool RemoteSensorClosedLoopDisableNeutralOnLOSDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.remoteSensorClosedLoopDisableNeutralOnLOS == _default.remoteSensorClosedLoopDisableNeutralOnLOS)) || !settings.enableOptimizations; }
					static bool ClearPositionOnLimitFDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.clearPositionOnLimitF == _default.clearPositionOnLimitF)) || !settings.enableOptimizations; }
					static bool ClearPositionOnLimitRDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.clearPositionOnLimitR == _default.clearPositionOnLimitR)) || !settings.enableOptimizations; }
					static bool ClearPositionOnQuadIdxDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.clearPositionOnQuadIdx == _default.clearPositionOnQuadIdx)) || !settings.enableOptimizations; }
					static bool LimitSwitchDisableNeutralOnLOSDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.limitSwitchDisableNeutralOnLOS == _default.limitSwitchDisableNeutralOnLOS)) || !settings.enableOptimizations; }
					static bool SoftLimitDisableNeutralOnLOSDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.softLimitDisableNeutralOnLOS == _default.softLimitDisableNeutralOnLOS)) || !settings.enableOptimizations; }
					static bool PulseWidthPeriod_EdgesPerRotDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.pulseWidthPeriod_EdgesPerRot == _default.pulseWidthPeriod_EdgesPerRot)) || !settings.enableOptimizations; }
					static bool PulseWidthPeriod_FilterWindowSzDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.pulseWidthPeriod_FilterWindowSz == _default.pulseWidthPeriod_FilterWindowSz)) || !settings.enableOptimizations; }
					static bool TrajectoryInterpolationEnableDifferent(const BaseMotorControllerConfiguration& settings) { return (!(settings.trajectoryInterpolationEnable == _default.trajectoryInterpolationEnable)) || !settings.enableOptimizations; }
					/** @} */
				};
				/**
				 * 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;

					double m_setPoint = 0;
					InvertType _invert = InvertType::None;

					ctre::phoenix::ErrorCode ConfigureSlot(const SlotConfiguration& slot, int slotIdx, int timeoutMs, bool enableOptimizations);
					ctre::phoenix::ErrorCode ConfigureFilter(const FilterConfiguration& filter, int ordinal, int timeoutMs, bool enableOptimizations);

					/**
					 * Handle of device
					 */
					void* m_handle;

					bool _isVcompEn = false;

					ctre::phoenix::motorcontrol::VictorSPXSimCollection* _simCollSpx;

				protected:
					ctre::phoenix::motorcontrol::VictorSPXSimCollection& GetVictorSPXSimCollection() { return *_simCollSpx; }

					/**
					 * Configures all base persistant settings.
					 *
					 * @param allConfigs        Object with all of the base persistant settings
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode BaseConfigAllSettings(const BaseMotorControllerConfiguration& allConfigs, int timeoutMs);
					/**
					 * Gets all base persistant settings.
					 *
					 * @param allConfigs        Object with all of the base persistant settings
					 * @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.
					 */
					virtual void BaseGetAllConfigs(BaseMotorControllerConfiguration& allConfigs, int timeoutMs);
					/**
					 * Gets all base PID set persistant settings.
					 *
					 * @param pid           Object with all of the base PID set persistant settings
					 * @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.
					 */
					virtual void BaseGetPIDConfigs(BasePIDSetConfiguration& pid, int pidIdx, int timeoutMs);

					//------ General Status ----------//
					/**
					 * Gets the output current of the motor controller.
					 * In the case of TalonSRX class, this routine returns supply current for legacy reasons.  In order to get the "true" output current, call GetStatorCurrent().
					 * In the case of TalonFX class, this routine returns the true output stator current.
					 *
					 * [[deprecated("Use GetStatorCurrent/GetSupplyCurrent instead.")]]
					 *
					 * @return The output current (in amps).
					 */
					virtual double GetOutputCurrent();

				public:
					/**
					 * Constructor for motor controllers.
					 *
					 * @param arbId Device ID [0,62]
					 * @param model String model of device.
					 * Examples: "Talon SRX", "Talon FX", "Victor SPX".
					 * @param canbus Name of the CANbus; can be a SocketCAN interface (on Linux),
					 *               or a CANivore device name or serial number
					 */
					BaseMotorController(int deviceNumber, const char* model, std::string const &canbus = "");
					virtual ~BaseMotorController();
					BaseMotorController() = delete;
					BaseMotorController(BaseMotorController const&) = delete;
					BaseMotorController& operator=(BaseMotorController const&) = delete;

					/**
					 * Destructs all motor controller objects
					 */
					static void DestroyAllMotControllers();

					/**
					 * Returns the Device ID
					 *
					 * @return Device number.
					 */
					virtual int GetDeviceID();
					// ------ Set output routines. ----------//
					/**
					 * Sets the appropriate output on the talon, depending on the mode.
					 * @param mode The output mode 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);
					 */
					virtual void Set(ControlMode mode, double value);
					/**
					 * @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.  Auxiliary
					 *   PID is always executed as standard Position PID control.
					 * 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.
					 * AuxPID: Target position in Sensor Units
					 * ArbitraryFeedForward: Percent Output between -1.0 and 1.0
					 *
					 *
					 *  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);
					 */
					virtual void Set(ControlMode mode, double demand0, DemandType demand1Type, double demand1);
					/**
					 * Neutral the motor output by setting control mode to disabled.
					 */
					virtual void NeutralOutput();
					/**
					 * 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)
					 **/
					virtual void SetNeutralMode(NeutralMode neutralMode);
					//------ 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 SetInverted() with any value.
					 *
					 * @param PhaseSensor
					 *            Indicates whether to invert the phase of the sensor.
					 */
					virtual void SetSensorPhase(bool 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.
					 */
					virtual void SetInverted(bool invert);
					/**
					 * Inverts the hbridge output of the motor controller in relation to the master if present
					 *
					 * This does not impact sensor phase and should not be used to correct sensor polarity.
					 *
					 * This will allow you to either:
					 *  - Not invert the motor
					 *  - Invert the motor
					 *  - Always follow the master regardless of master's inversion
					 *  - Always oppose the master regardless of master's inversion
					 *
					 * @param invertType
					 *            Invert state to set.
					 */
					virtual void SetInverted(InvertType invertType);
					/**
					 * @return invert setting of motor output.
					 */
					virtual bool GetInverted() const;
					//----- Factory Default Configuration -----//
					/**
					* Revert all configurations to factory default values.
					* Use this before your individual config* calls to avoid having to config every single param.
					*
					* Alternatively you can use the configAllSettings routine.
					 *
					 * @param timeoutMs
					 *            Timeout value in ms. Function will generate error if config is
					 *            not successful within timeout.
					 * @return Error Code generated by function. 0 indicates no error.
					 */
					virtual ctre::phoenix::ErrorCode ConfigFactoryDefault(int timeoutMs = 50);
					//----- 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigOpenloopRamp(double secondsFromNeutralToFull,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigClosedloopRamp(double secondsFromNeutralToFull,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigPeakOutputForward(double percentOut, int timeoutMs = 0);
					/**
					 * Configures the reverse peak output percentage.
					 *
					 * @param percentOut
					 *            Desired peak output percentage.
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigPeakOutputReverse(double percentOut, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigNominalOutputForward(double percentOut,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigNominalOutputReverse(double percentOut,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigNeutralDeadband(double percentDeadband,
						int timeoutMs = 0);
					//------ 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigVoltageCompSaturation(double voltage, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigVoltageMeasurementFilter(int filterWindowSamples,
						int timeoutMs = 0);
					/**
					 * Enables voltage compensation. If enabled, voltage compensation works in
					 * all control modes.
					 *
					 * Be sure to configure the saturation voltage before enabling this.
					 *
					 * @param enable
					 *            Enable state of voltage compensation.
					 **/
					virtual void EnableVoltageCompensation(bool enable);
					/**
					 * Returns the enable state of Voltage Compensation that the caller has set.
					 *
					 * @return TRUE if voltage compensation is enabled.
					 */
					virtual bool IsVoltageCompensationEnabled();

					//------ General Status ----------//
					/**
					 * Gets the bus voltage seen by the device.
					 *
					 * @return The bus voltage value (in volts).
					 */
					virtual double GetBusVoltage();
					/**
					 * Gets the output percentage of the motor controller.
					 *
					 * @return Output of the motor controller (in percent).
					 */
					virtual double GetMotorOutputPercent();
					/**
					 * @return applied voltage to motor  in volts.
					 */
					virtual double GetMotorOutputVoltage();
					/**
					 * Gets the temperature of the motor controller.
					 *
					 * @return Temperature of the motor controller (in 'C)
					 */
					virtual double GetTemperature();

					//------ 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackSensor(
						RemoteFeedbackDevice feedbackDevice, int pidIdx = 0, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackSensor(
						FeedbackDevice feedbackDevice, int pidIdx = 0, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigSelectedFeedbackCoefficient(
						double coefficient, int pidIdx = 0, int timeoutMs = 0);
					/**
					 * 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 device 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigRemoteFeedbackFilter(int deviceID,
						RemoteSensorSource remoteSensorSource, int remoteOrdinal,
						int timeoutMs = 0);
					/**
					 * 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 canCoderRef
					 *            CANCoder device reference to use.
					 * @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.
					 */
					virtual ErrorCode ConfigRemoteFeedbackFilter(ctre::phoenix::sensors::CANCoder &canCoderRef, int remoteOrdinal, int timeoutMs = 0);
					/**
					 * 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 talonRef
					 *            Talon device reference to use.
					 * @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.
					 */
					virtual ErrorCode ConfigRemoteFeedbackFilter(ctre::phoenix::motorcontrol::can::BaseTalon &talonRef, int remoteOrdinal, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigSensorTerm(SensorTerm sensorTerm,
						FeedbackDevice feedbackDevice, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigSensorTerm(SensorTerm sensorTerm,
						RemoteFeedbackDevice feedbackDevice, int timeoutMs = 0);

					//------- 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).
					 */
					virtual double GetSelectedSensorPosition(int pidIdx = 0);
					/**
					 * 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.
					 */
					virtual double GetSelectedSensorVelocity(int pidIdx = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode SetSelectedSensorPosition(double sensorPos, int pidIdx = 0, int timeoutMs = 50);
					//------ 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.
					 */
					virtual ctre::phoenix::ErrorCode SetControlFramePeriod(ControlFrame frame, int 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 HasResetOccurred() 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.
					 */
					virtual ctre::phoenix::ErrorCode SetStatusFramePeriod(StatusFrame frame, uint8_t periodMs,
						int timeoutMs = 0);
					/**
					 * 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 HasResetOccurred() 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.
					 */
					virtual ctre::phoenix::ErrorCode SetStatusFramePeriod(StatusFrameEnhanced frame,
						uint8_t periodMs, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual int GetStatusFramePeriod(StatusFrame frame, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual int GetStatusFramePeriod(StatusFrameEnhanced frame, int timeoutMs = 0);
					//----- velocity signal conditionaing ------//
					/**
					 * Sets the period over which velocity measurements are taken.
					 *
					 * @param period
					 *            Desired period for the velocity measurement. @see
					 *            #SensorVelocityMeasPeriod
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigVelocityMeasurementPeriod(ctre::phoenix::sensors::SensorVelocityMeasPeriod period,
						int timeoutMs = 0);

					[[deprecated("Use the overload with SensorVelocityMeasPeriod instead.")]]
					virtual ctre::phoenix::ErrorCode ConfigVelocityMeasurementPeriod(VelocityMeasPeriod period,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigVelocityMeasurementWindow(int windowSize,
						int timeoutMs = 0);
					//------ 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 Phoenix Tuner 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigForwardLimitSwitchSource(
						RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
						int deviceID, int timeoutMs = 0);
					/**
					 * 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 Phoenix Tuner 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigReverseLimitSwitchSource(
						RemoteLimitSwitchSource type, LimitSwitchNormal normalOpenOrClose,
						int deviceID, int timeoutMs = 0);
					/**
					 * Sets the enable state for limit switches.
					 *
					 * @param enable
					 *            Enable state for limit switches.
					 **/
					void OverrideLimitSwitchesEnable(bool 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. 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 Phoenix Tuner 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigForwardLimitSwitchSource(LimitSwitchSource type,
						LimitSwitchNormal normalOpenOrClose, int timeoutMs = 0);
					/**
					 * 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. 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 Phoenix Tuner 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigReverseLimitSwitchSource(LimitSwitchSource type,
						LimitSwitchNormal normalOpenOrClose, int timeoutMs = 0);
					//------ soft limit ----------//
					/**
					 * Configures the forward soft limit threhold.
					 *
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigForwardSoftLimitThreshold(double forwardSensorLimit,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigReverseSoftLimitThreshold(double reverseSensorLimit,
						int timeoutMs = 0);
					/**
					 * Configures the forward soft limit enable.
					 *
					 * @param enable
					 *            Forward Sensor Position Limit Enable.
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigForwardSoftLimitEnable(bool enable,
						int timeoutMs = 0);
					/**
					 * Configures the reverse soft limit enable.
					 *
					 * @param enable
					 *            Reverse Sensor Position Limit Enable.
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigReverseSoftLimitEnable(bool enable,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual void OverrideSoftLimitsEnable(bool enable);
					//------ Current Lim ----------//
					/* not available in base */
					//------ General Close loop ----------//
					/**
					 * Sets the 'P' constant in the given parameter slot.
					 * This is multiplied by closed loop error in sensor units.
					 * Note the closed loop output interprets a final value of 1023 as full output.
					 * So use a gain of '0.25' to get full output if err is 4096u (Mag Encoder 1 rotation)
					 *
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode Config_kP(int slotIdx, double value, int timeoutMs = 0);
					/**
					 * Sets the 'I' constant in the given parameter slot.
					 * This is multiplied by accumulated closed loop error in sensor units every PID Loop.
					 * Note the closed loop output interprets a final value of 1023 as full output.
					 * So use a gain of '0.00025' to get full output if err is 4096u for 1000 loops (accumulater holds 4,096,000),
					 * [which is equivalent to one CTRE mag encoder rotation for 1000 milliseconds].
					 *
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode Config_kI(int slotIdx, double value, int timeoutMs = 0);
					/**
					 * Sets the 'D' constant in the given parameter slot.
					 *
					 * This is multiplied by derivative error (sensor units per PID loop, typically 1ms).
					 * Note the closed loop output interprets a final value of 1023 as full output.
					 * So use a gain of '250' to get full output if derr is 4096u (Mag Encoder 1 rotation) per 1000 loops (typ 1 sec)
					 *
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode Config_kD(int slotIdx, double value, int timeoutMs = 0);
					/**
					 * Sets the 'F' constant in the given parameter slot.
					 *
					 * See documentation for calculation details.
					 * If using velocity, motion magic, or motion profile,
					 * use (1023 * duty-cycle / sensor-velocity-sensor-units-per-100ms).
					 *
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode Config_kF(int slotIdx, double value, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode Config_IntegralZone(int slotIdx, double izone,
						int timeoutMs = 0);
					/**
					 * Sets the allowable closed-loop error in the given parameter slot.
					 *
					 * @param slotIdx
					 *            Parameter slot for the constant.
					 * @param allowableCloseLoopError
					 *            Value of the allowable closed-loop error in sensor units (or sensor units per 100ms for velocity).
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigAllowableClosedloopError(int slotIdx,
						double allowableCloseLoopError, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigMaxIntegralAccumulator(int slotIdx, double iaccum,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigClosedLoopPeakOutput(int slotIdx, double percentOut, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigClosedLoopPeriod(int slotIdx, int loopTimeMs, int timeoutMs = 0);

					/**
					 * 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
					 */
					virtual ctre::phoenix::ErrorCode ConfigAuxPIDPolarity(bool invert, int timeoutMs = 0);

					//------ Close loop State ----------//
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode SetIntegralAccumulator(double iaccum, int pidIdx = 0, int timeoutMs = 0);
					/**
					 * Gets the closed-loop error. The units depend on which control mode is in
					 * use.
					 *
					 * If closed-loop is seeking a target sensor position, closed-loop error is the difference between target
					 * and current sensor value (in sensor units.  Example 4096 units per rotation for CTRE Mag Encoder).
					 *
					 * If closed-loop is seeking a target sensor velocity, closed-loop error is the difference between target
					 * and current sensor value (in sensor units per 100ms).
					 *
					 * If using motion profiling or Motion Magic, closed loop error is calculated against the current target,
					 * and not the "final" target at the end of the profile/movement.
					 *
					 * See Phoenix-Documentation information on units.
					 *
					 * @param pidIdx
					 *            0 for Primary closed-loop. 1 for auxiliary closed-loop.
					 * @return Closed-loop error value.
					 */
					virtual double GetClosedLoopError(int pidIdx = 0);
					/**
					 * 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).
					 */
					virtual double GetIntegralAccumulator(int pidIdx = 0);
					/**
					 * 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.
					 */
					virtual double GetErrorDerivative(int pidIdx = 0);

					/**
					 * 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.
					 **/
					virtual ctre::phoenix::ErrorCode SelectProfileSlot(int slotIdx, int 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.
					 */
					virtual double GetClosedLoopTarget(int pidIdx = 0);
					/**
					 * Gets the active trajectory target position using
					 * MotionMagic/MotionProfile control modes.
					 *
					 * @return The Active Trajectory Position in sensor units.
					 */	virtual double GetActiveTrajectoryPosition(int pidIdx = 0);
					 /**
					  * Gets the active trajectory target velocity using
					  * MotionMagic/MotionProfile control modes.
					  *
					  * @return The Active Trajectory Velocity in sensor units per 100ms.
					  */
					virtual double GetActiveTrajectoryVelocity(int pidIdx = 0);	/**
					 * Gets the active trajectory arbitrary feedforward using
					 * MotionMagic/MotionProfile control modes.
					 *
					 * @param pidIdx
					 *            0 for Primary closed-loop. 1 for auxiliary closed-loop.
					 * @return The Active Trajectory ArbFeedFwd in units of percent output
					 * 			(where 0.01 is 1%).
					 */
					virtual double GetActiveTrajectoryArbFeedFwd(int pidIdx = 0);

					//------ Motion Profile Settings used in Motion Magic  ----------//
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigMotionCruiseVelocity(double sensorUnitsPer100ms,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigMotionAcceleration(double sensorUnitsPer100msPerSec,
						int timeoutMs = 0);
					/**
					 * Sets the Motion Magic S Curve Strength.
					 * Call this before using Motion Magic.
					 * Modifying this during a Motion Magic action should be avoided.
					 *
					 * @param curveStrength
					 *            0 to use Trapezoidal Motion Profile. [1,8] for S-Curve (greater value yields greater smoothing).
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigMotionSCurveStrength(int curveStrength, int timeoutMs = 0);
					//------ Motion Profile Buffer ----------//
					/**
					 * Clear the buffered motion profile in both controller's RAM (bottom), and in the
					 * API (top).
					 */
					virtual ErrorCode ClearMotionProfileTrajectories();
					/**
					 * 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 controller's RAM. Otherwise just use GetMotionProfileStatus.
					 *
					 * @return number of trajectory points in the top buffer.
					 */
					virtual int GetMotionProfileTopLevelBufferCount();
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode PushMotionProfileTrajectory(const ctre::phoenix::motion::TrajectoryPoint& trajPt);
					/**
					 * @brief Simple one-shot firing of a complete MP.
					 * Starting in 2019, MPs can be fired by building a Buffered Trajectory Point Stream, and calling this routine.
					 *
					 * Once called, the motor controller software will automatically ...
					 * [1] Clear the firmware buffer of trajectory points.
					 * [2] Clear the underrun flags
					 * [3] Reset an index within the Buffered Trajectory Point Stream (so that the same profile can be run again and again).
					 * [4] Start a background thread to manage MP streaming (if not already running).
					 * [5a] If current control mode already matches motionProfControlMode, set MPE Output to "Hold".
					 * [5b] If current control mode does not matches motionProfControlMode, apply motionProfControlMode and set MPE Output to "Disable".
					 * [6] Stream the trajectory points into the device's firmware buffer.
					 * [7] Once motor controller has at least minBufferedPts worth in the firmware buffer, MP will automatically start (MPE Output set to "Enable").
					 * [8] Wait until MP finishes, then transitions the Motion Profile Executor's output to "Hold".
					 * [9] IsMotionProfileFinished() will now return true.
					 *
					 * Calling application can use IsMotionProfileFinished() to determine when internal state machine reaches [7].
					 * Calling application can cancel MP by calling set().  Otherwise do not call set() until MP has completed.
					 *
					 * The legacy API from previous years requires the calling application to pass points via the ProcessMotionProfileBuffer and PushMotionProfileTrajectory.
					 * This is no longer required if using this StartMotionProfile/IsMotionProfileFinished API.
					 *
					 * @param stream	A buffer that will be used to stream the trajectory points.  Caller can fill this container with the entire trajectory point, regardless of size.
					 * @param minBufferedPts	Minimum number of firmware buffered points before starting MP.
					 *							Do not exceed device's firmware buffer capacity or MP will never fire (120 for Motion Profile, or 60 for Motion Profile Arc).
					 *							Recommendation value for this would be five to ten samples depending on timeDur of the trajectory point.
					 * @param motionProfControlMode		Pass MotionProfile or MotionProfileArc.
					 * @return nonzero error code if operation fails.
					 */
					virtual ctre::phoenix::ErrorCode StartMotionProfile(ctre::phoenix::motion::BufferedTrajectoryPointStream& stream, uint32_t minBufferedPts, ControlMode motionProfControlMode);
					/**
					 * @brief Determine if running MP is complete.
					 * This requires using the StartMotionProfile routine to start the MP.
					 * That is because managing the trajectory points is now done in a background thread (if StartMotionProfile is called).
					 *
					 * If calling application uses the legacy API  (more-complex buffering API) from previous years, than this API will
					 * not return true.
					 *
					 * @return true if MP was started using StartMotionProfile, and it has completed execution (MPE is now in "hold").
					 */
					virtual bool IsMotionProfileFinished();
					/**
					 * 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.
					 */
					virtual bool IsMotionProfileTopLevelBufferFull();
					/**
					 * 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.
					 */
					virtual void ProcessMotionProfileBuffer();
					/**
					 * Retrieve all status information.
					 * For best performance, Caller can snapshot all status information regarding the
					 * motion profile executer.
					 *
					 * @param 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.
					 * 	 	 	 	 	Can be manually cleared by ClearMotionProfileHasUnderrun() or automatically cleared by StartMotionProfile().
					 *
					 *	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 is 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.
					 *
					 *	profileSlotSelect: The currently processed trajectory point's
					 *      			  selected slot.  This can differ in the currently selected slot used
					 *       				 for Position and Velocity servo modes
					 *
					 *	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.
					 */
					virtual ctre::phoenix::ErrorCode GetMotionProfileStatus(ctre::phoenix::motion::MotionProfileStatus& statusToFill);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ClearMotionProfileHasUnderrun(int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ChangeMotionControlFramePeriod(int 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigMotionProfileTrajectoryPeriod(int baseTrajDurationMs, int timeoutMs = 0);
					/**
					 * When trajectory points are processed in the buffer, the motor controller can
					 * linearly interpolate additional trajectory points between the buffered
					 * points.  The time delta between these interpolated points is 1 ms.
					 *
					 * By default this feature is enabled.
					 *
					 * @param enable Whether to enable the trajectory point interpolation feature.
					 * @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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigMotionProfileTrajectoryInterpolationEnable(bool enable, int timeoutMs = 0);


					//------Feedback Device Interaction Settings---------//
					/**
					 * Disables continuous tracking of the position for analog and pulse-width.
					 * If the signal goes from 4095 to 0 (pulse-width) a motor controller will continue to read 4096 by default.
					 * If overflow tracking is disabled, it will wrap to 0 (not continuous)
					 *
					 * If using pulse-width on CTRE Mag Encoder (within one rotation) or absolute analog sensor (within one rotation),
					 * setting feedbackNotContinuous to true is recommended, to prevent intermittent
					 * connections from causing sensor "jumps" of 4096 (or 1024 for analog) units.
					 *
					 * @param feedbackNotContinuous     True to disable the overflow tracking.
					 *
					 * @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.
					 */
					virtual ErrorCode ConfigFeedbackNotContinuous(bool feedbackNotContinuous, int timeoutMs = 0);
					/**
					 * Disables going to neutral (brake/coast) when a remote sensor is no longer detected.
					 *
					 * @param remoteSensorClosedLoopDisableNeutralOnLOS     disable going to neutral
					 *
					 * @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.
					 */
					virtual ErrorCode ConfigRemoteSensorClosedLoopDisableNeutralOnLOS(bool remoteSensorClosedLoopDisableNeutralOnLOS, int timeoutMs = 0);
					/**
					 * Enables clearing the position of the feedback sensor when the forward
					 * limit switch is triggered
					 *
					 * @param clearPositionOnLimitF     Whether clearing is enabled, defaults false
					 * @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.
					 */
					virtual ErrorCode ConfigClearPositionOnLimitF(bool clearPositionOnLimitF, int timeoutMs = 0);
					/**
					 * Enables clearing the position of the feedback sensor when the reverse
					 * limit switch is triggered
					 *
					 * @param clearPositionOnLimitR     Whether clearing is enabled, defaults false
					 * @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.
					 */
					virtual ErrorCode ConfigClearPositionOnLimitR(bool clearPositionOnLimitR, int timeoutMs = 0);
					/**
					 * Enables clearing the position of the feedback sensor when the quadrature index signal
					 * is detected
					 *
					 * @param clearPositionOnQuadIdx    Whether clearing is enabled, defaults false
					 * @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.
					 */
					virtual ErrorCode ConfigClearPositionOnQuadIdx(bool clearPositionOnQuadIdx, int timeoutMs = 0);
					/**
					 * Disables limit switches triggering (if enabled) when the sensor is no longer detected.
					 *
					 * @param limitSwitchDisableNeutralOnLOS    disable triggering
					 *
					 * @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.
					 */
					virtual ErrorCode ConfigLimitSwitchDisableNeutralOnLOS(bool limitSwitchDisableNeutralOnLOS, int timeoutMs = 0);
					/**
					 * Disables soft limits triggering (if enabled) when the sensor is no longer detected.
					 *
					 * @param softLimitDisableNeutralOnLOS    disable triggering
					 *
					 * @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.
					 */
					virtual ErrorCode ConfigSoftLimitDisableNeutralOnLOS(bool softLimitDisableNeutralOnLOS, int timeoutMs = 0);
					/**
					 * Sets the edges per rotation of a pulse width sensor. (This should be set for
					 * tachometer use).
					 *
					 * @param pulseWidthPeriod_EdgesPerRot    edges per rotation
					 *
					 * @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.
					 */
					virtual ErrorCode ConfigPulseWidthPeriod_EdgesPerRot(int pulseWidthPeriod_EdgesPerRot, int timeoutMs = 0);
					/**
					 * Sets the number of samples to use in smoothing a pulse width sensor with a rolling
					 * average. Default is 1 (no smoothing).
					 *
					 * @param pulseWidthPeriod_FilterWindowSz   samples for rolling avg
					 *
					 * @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.
					 */
					virtual ErrorCode ConfigPulseWidthPeriod_FilterWindowSz(int pulseWidthPeriod_FilterWindowSz, int timeoutMs = 0);

					//------ 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.
					 */
					virtual ctre::phoenix::ErrorCode GetLastError();
					//------ 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.
					 */
					virtual ctre::phoenix::ErrorCode GetFaults(Faults& toFill);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode GetStickyFaults(StickyFaults& toFill);
					/**
					 * 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.
					 */
					virtual ctre::phoenix::ErrorCode ClearStickyFaults(int timeoutMs = 0);
					//------ Firmware ----------//
					/**
					 * Gets the firmware version of the device.
					 *
					 * @return Firmware version of device. For example: version 1-dot-2 is
					 *         0x0102.
					 */
					virtual int GetFirmwareVersion();
					/**
					 * Returns true if the device has reset since last call.
					 *
					 * @return Has a Device Reset Occurred?
					 */
					virtual bool HasResetOccurred();
					//------ 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigSetCustomParam(int newValue, int paramIndex,
						int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual int ConfigGetCustomParam(int paramIndex,
						int timeoutMs = 0);
					//------ 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.
					 */
					virtual ctre::phoenix::ErrorCode ConfigSetParameter(ctre::phoenix::ParamEnum param, double value,
						uint8_t subValue, int ordinal, int timeoutMs = 0);
					/**
					 * 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.
					 */
					virtual double ConfigGetParameter(ctre::phoenix::ParamEnum param, int ordinal, int timeoutMs = 0);
					/**
					 * Gets a parameter by passing an int by reference
					 *
					 * @param param
					 * 			  Parameter enumeration
					 * @param valueToSend
					 * 			  Value to send to parameter
					 * @param valueReceived
					 * 			  Reference to integer to receive
					 * @param subValue
					 * 			  SubValue of parameter
					 * @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.
					 */
					virtual ErrorCode ConfigGetParameter(ParamEnum param, int32_t valueToSend,
						int32_t& valueReceived, uint8_t& subValue, int32_t ordinal,
						int32_t timeoutMs);
					//------ Misc. ----------//
					virtual int GetBaseID();
					/**
					 * @return control mode motor controller is in
					 */
					virtual ControlMode GetControlMode();
					// ----- 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 Follow(IMotorController& masterToFollow, ctre::phoenix::motorcontrol::FollowerType followerType);
					/**
					 * 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.
					 */
					virtual void Follow(IMotorController& masterToFollow);
					/**
					 * When master makes a device, this routine is called to signal the update.
					 */
					virtual void ValueUpdated();


					//-------Config All----------//
					/**
					 * Gets all slot persistant settings.
					 *
					 * @param slot        Object with all of the slot persistant settings
					 * @param slotIdx     Parameter slot for the 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.
					 */
					void GetSlotConfigs(SlotConfiguration& slot, int slotIdx = 0, int timeoutMs = 50);
					/**
					 * Gets all filter persistant settings.
					 *
					 * @param Filter        Object with all of the filter persistant settings
					 * @param ordinal       0 for remote sensor 0 and 1 for 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.
					 */
					void GetFilterConfigs(FilterConfiguration& Filter, int ordinal = 0, int timeoutMs = 50);

					/**
					 * @return CCI handle for child classes.
					 */
					void* GetHandle();

				};// class BaseMotorController
			} // namespace can
		} // namespace motorcontrol
	} // namespace phoenix
} // namespace ctre
