import Foundation
import Phidget22_C

/**
The Stepper class powers and controls the stepper motor connected to the Phidget controller, allowing you to change the position, velocity, acceleration, and current limit.
*/
public class StepperBase : Phidget {

	public init() {
		var h: PhidgetHandle?
		PhidgetStepper_create(&h)
		super.init(h!)
		initializeEvents()
	}

	internal override init(_ handle: PhidgetHandle) {
		super.init(handle)
	}

	deinit {
		if (retained) {
			Phidget_release(&chandle)
		} else {
			uninitializeEvents()
			PhidgetStepper_delete(&chandle)
		}
	}

	/**
	The rate at which the controller can change the motor's `Velocity`.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.
	*   Changing the acceleration value while the stepper is in motion (especially at speeds higher than 1000 1/16th steps/s) can cause unpredictable results due to the inability of the processor tocalculate a new acceleration curve quickly enough. Generally you should wait until the motor is stationary until calling this function.

	- returns:
	The acceleration value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getAcceleration() throws -> Double {
		let result: PhidgetReturnCode
		var acceleration: Double = 0
		result = PhidgetStepper_getAcceleration(chandle, &acceleration)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return acceleration
	}

	/**
	The rate at which the controller can change the motor's `Velocity`.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.
	*   Changing the acceleration value while the stepper is in motion (especially at speeds higher than 1000 1/16th steps/s) can cause unpredictable results due to the inability of the processor tocalculate a new acceleration curve quickly enough. Generally you should wait until the motor is stationary until calling this function.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- acceleration: The acceleration value
	*/
	public func setAcceleration(_ acceleration: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setAcceleration(chandle, acceleration)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The minimum value that `Acceleration` can be set to.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The acceleration value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMinAcceleration() throws -> Double {
		let result: PhidgetReturnCode
		var minAcceleration: Double = 0
		result = PhidgetStepper_getMinAcceleration(chandle, &minAcceleration)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return minAcceleration
	}

	/**
	The maximum value that `Acceleration` can be set to.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The acceleration value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxAcceleration() throws -> Double {
		let result: PhidgetReturnCode
		var maxAcceleration: Double = 0
		result = PhidgetStepper_getMaxAcceleration(chandle, &maxAcceleration)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxAcceleration
	}

	/**
	Use `StepperControlMode.step` mode when you want to set a `TargetPosition` for the Stepper motor. Use `StepperControlMode.run` mode when you simply want the Stepper motor to rotate continuously in a specific direction.  
	  
	Changing the control mode while the motor is running will not have an effect on the motor's movements until a new `TargetPosition` or `VelocityLimit` is set.  
	  
	In `StepperControlMode.run` mode, setting a `VelocityLimit` will also set the target position of the controller to `MinPosition` or `MaxPosition`, corresponding to the direction of movement.

	- returns:
	The control mode value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getControlMode() throws -> StepperControlMode {
		let result: PhidgetReturnCode
		var controlMode: PhidgetStepper_ControlMode = CONTROL_MODE_STEP
		result = PhidgetStepper_getControlMode(chandle, &controlMode)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return StepperControlMode(rawValue: controlMode.rawValue)!
	}

	/**
	Use `StepperControlMode.step` mode when you want to set a `TargetPosition` for the Stepper motor. Use `StepperControlMode.run` mode when you simply want the Stepper motor to rotate continuously in a specific direction.  
	  
	Changing the control mode while the motor is running will not have an effect on the motor's movements until a new `TargetPosition` or `VelocityLimit` is set.  
	  
	In `StepperControlMode.run` mode, setting a `VelocityLimit` will also set the target position of the controller to `MinPosition` or `MaxPosition`, corresponding to the direction of movement.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- controlMode: The control mode value
	*/
	public func setControlMode(_ controlMode: StepperControlMode) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setControlMode(chandle, PhidgetStepper_ControlMode(controlMode.rawValue))
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The current through the motor will be limited by the `CurrentLimit`.

	*   See your Stepper motor's data sheet for more information about what value the `CurrentLimit` should be.

	- returns:
	The current limit value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getCurrentLimit() throws -> Double {
		let result: PhidgetReturnCode
		var currentLimit: Double = 0
		result = PhidgetStepper_getCurrentLimit(chandle, &currentLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return currentLimit
	}

	/**
	The current through the motor will be limited by the `CurrentLimit`.

	*   See your Stepper motor's data sheet for more information about what value the `CurrentLimit` should be.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- currentLimit: The current limit value
	*/
	public func setCurrentLimit(_ currentLimit: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setCurrentLimit(chandle, currentLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The minimum value that `CurrentLimit` and `HoldingCurrentLimit` can be set to.

	*   Reference your controller's User Guide for more information about how the `HoldingCurrentLimit` and `CurrentLimit` can be used in your application.

	- returns:
	The current limit

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMinCurrentLimit() throws -> Double {
		let result: PhidgetReturnCode
		var minCurrentLimit: Double = 0
		result = PhidgetStepper_getMinCurrentLimit(chandle, &minCurrentLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return minCurrentLimit
	}

	/**
	The maximum value that `CurrentLimit` and `HoldingCurrentLimit` can be set to.

	*   Reference your controller's User Guide for more information about how the `HoldingCurrentLimit` and `CurrentLimit` can be used in your application.

	- returns:
	The current limit

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxCurrentLimit() throws -> Double {
		let result: PhidgetReturnCode
		var maxCurrentLimit: Double = 0
		result = PhidgetStepper_getMaxCurrentLimit(chandle, &maxCurrentLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxCurrentLimit
	}

	/**
	The `DataInterval` is the time that must elapse before the channel will fire another `PositionChange` / `VelocityChange` event.

	*   The data interval is bounded by `MinDataInterval` and `MaxDataInterval`.

	- returns:
	The data interval value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getDataInterval() throws -> UInt32 {
		let result: PhidgetReturnCode
		var dataInterval: UInt32 = 0
		result = PhidgetStepper_getDataInterval(chandle, &dataInterval)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return dataInterval
	}

	/**
	The `DataInterval` is the time that must elapse before the channel will fire another `PositionChange` / `VelocityChange` event.

	*   The data interval is bounded by `MinDataInterval` and `MaxDataInterval`.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- dataInterval: The data interval value
	*/
	public func setDataInterval(_ dataInterval: UInt32) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setDataInterval(chandle, dataInterval)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The minimum value that `DataInterval` can be set to.

	- returns:
	The data interval value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMinDataInterval() throws -> UInt32 {
		let result: PhidgetReturnCode
		var minDataInterval: UInt32 = 0
		result = PhidgetStepper_getMinDataInterval(chandle, &minDataInterval)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return minDataInterval
	}

	/**
	The maximum value that `DataInterval` can be set to.

	- returns:
	The data interval value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxDataInterval() throws -> UInt32 {
		let result: PhidgetReturnCode
		var maxDataInterval: UInt32 = 0
		result = PhidgetStepper_getMaxDataInterval(chandle, &maxDataInterval)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxDataInterval
	}

	/**
	The `DataRate` is the frequency of events from the device.

	*   The data rate is bounded by `MinDataRate` and `MaxDataRate`.
	*   Changing `DataRate` will change the channel's `DataInterval` to a corresponding value, rounded to the nearest integer number of milliseconds.
	*   The timing between events can also affected by the change trigger.

	- returns:
	The data rate for the channel

	- throws:
	An error or type `PhidgetError`
	*/
	public func getDataRate() throws -> Double {
		let result: PhidgetReturnCode
		var dataRate: Double = 0
		result = PhidgetStepper_getDataRate(chandle, &dataRate)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return dataRate
	}

	/**
	The `DataRate` is the frequency of events from the device.

	*   The data rate is bounded by `MinDataRate` and `MaxDataRate`.
	*   Changing `DataRate` will change the channel's `DataInterval` to a corresponding value, rounded to the nearest integer number of milliseconds.
	*   The timing between events can also affected by the change trigger.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- dataRate: The data rate for the channel
	*/
	public func setDataRate(_ dataRate: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setDataRate(chandle, dataRate)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The minimum value that `DataRate` can be set to.

	- returns:
	The data rate value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMinDataRate() throws -> Double {
		let result: PhidgetReturnCode
		var minDataRate: Double = 0
		result = PhidgetStepper_getMinDataRate(chandle, &minDataRate)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return minDataRate
	}

	/**
	The maximum value that `DataRate` can be set to.

	- returns:
	The data rate value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxDataRate() throws -> Double {
		let result: PhidgetReturnCode
		var maxDataRate: Double = 0
		result = PhidgetStepper_getMaxDataRate(chandle, &maxDataRate)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxDataRate
	}

	/**
	When this property is true, the controller will supply power to the motor coils.

	*   The controller must be `Engaged` in order to move the Stepper motor, or have it hold position.

	- returns:
	The engaged state

	- throws:
	An error or type `PhidgetError`
	*/
	public func getEngaged() throws -> Bool {
		let result: PhidgetReturnCode
		var engaged: Int32 = 0
		result = PhidgetStepper_getEngaged(chandle, &engaged)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return (engaged == 0 ? false : true)
	}

	/**
	When this property is true, the controller will supply power to the motor coils.

	*   The controller must be `Engaged` in order to move the Stepper motor, or have it hold position.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- engaged: The engaged state
	*/
	public func setEngaged(_ engaged: Bool) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setEngaged(chandle, (engaged ? 1 : 0))
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Enables the **failsafe** feature for the channel, with the specified **failsafe time**.

	Enabling the failsafe feature starts a recurring **failsafe timer** for the channel. Once the failsafe is enabled, the timer must be reset within the specified time or the channel will enter a **failsafe state**. For Stepper Motor channels, this will disengage the motor. The failsafe timer can be reset by using any of the following API calls:

	*   `setAcceleration()`
	*   `setControlMode()`
	*   `setCurrentLimit()`
	*   `setDataInterval()`
	*   `setDataRate()`
	*   `setEngaged()`
	*   `setHoldingCurrentLimit()`
	*   `setVelocityLimit()`
	*   `resetFailsafe()`

	For more information about failsafe, visit our [Failsafe Guide](/docs/Failsafe_Guide).

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- failsafeTime: Failsafe timeout in milliseconds
	*/
	public func enableFailsafe(failsafeTime: UInt32) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_enableFailsafe(chandle, failsafeTime)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The minimum value that `failsafeTime` can be set to when calling `enableFailsafe()`.

	- returns:
	The failsafe time

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMinFailsafeTime() throws -> UInt32 {
		let result: PhidgetReturnCode
		var minFailsafeTime: UInt32 = 0
		result = PhidgetStepper_getMinFailsafeTime(chandle, &minFailsafeTime)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return minFailsafeTime
	}

	/**
	The maximum value that `failsafeTime` can be set to when calling `enableFailsafe()`.

	- returns:
	The failsafe time

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxFailsafeTime() throws -> UInt32 {
		let result: PhidgetReturnCode
		var maxFailsafeTime: UInt32 = 0
		result = PhidgetStepper_getMaxFailsafeTime(chandle, &maxFailsafeTime)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxFailsafeTime
	}

	/**
	The `HoldingCurrentLimit` will activate when the `TargetPosition` has been reached. It will limit current through the motor.

	*   When the motor is not stopped, the current through the motor is limited by the `CurrentLimit`.
	*   If no `HoldingCurrentLimit` is specified, the `CurrentLimit` value will persist when the motor is stopped.
	*   Reference your controller's User Guide for more information about how the `HoldingCurrentLimit` and `CurrentLimit` can be used in your application.

	- returns:
	The current value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getHoldingCurrentLimit() throws -> Double {
		let result: PhidgetReturnCode
		var holdingCurrentLimit: Double = 0
		result = PhidgetStepper_getHoldingCurrentLimit(chandle, &holdingCurrentLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return holdingCurrentLimit
	}

	/**
	The `HoldingCurrentLimit` will activate when the `TargetPosition` has been reached. It will limit current through the motor.

	*   When the motor is not stopped, the current through the motor is limited by the `CurrentLimit`.
	*   If no `HoldingCurrentLimit` is specified, the `CurrentLimit` value will persist when the motor is stopped.
	*   Reference your controller's User Guide for more information about how the `HoldingCurrentLimit` and `CurrentLimit` can be used in your application.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- holdingCurrentLimit: The current value
	*/
	public func setHoldingCurrentLimit(_ holdingCurrentLimit: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setHoldingCurrentLimit(chandle, holdingCurrentLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	`IsMoving` returns true while the controller is sending commands to the motor. Note: there is no feedback to the controller, so it does not know whether the motor shaft is actually moving or not.

	- returns:
	The moving state

	- throws:
	An error or type `PhidgetError`
	*/
	public func getIsMoving() throws -> Bool {
		let result: PhidgetReturnCode
		var isMoving: Int32 = 0
		result = PhidgetStepper_getIsMoving(chandle, &isMoving)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return (isMoving == 0 ? false : true)
	}

	/**
	The most recent position value that the controller has reported.

	*   This value will always be between `MinPosition` and `MaxPosition`.
	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The position value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getPosition() throws -> Double {
		let result: PhidgetReturnCode
		var position: Double = 0
		result = PhidgetStepper_getPosition(chandle, &position)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return position
	}

	/**
	The minimum value that `TargetPosition` can be set to.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The position value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMinPosition() throws -> Double {
		let result: PhidgetReturnCode
		var minPosition: Double = 0
		result = PhidgetStepper_getMinPosition(chandle, &minPosition)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return minPosition
	}

	/**
	The maximum value that `TargetPosition` can be set to.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The position value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxPosition() throws -> Double {
		let result: PhidgetReturnCode
		var maxPosition: Double = 0
		result = PhidgetStepper_getMaxPosition(chandle, &maxPosition)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxPosition
	}

	/**
	Adds an offset (positive or negative) to the current position and target position.

	*   This is especially useful for zeroing position.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- positionOffset: Amount to offset the position by
	*/
	public func addPositionOffset(positionOffset: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_addPositionOffset(chandle, positionOffset)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Applies a factor to the \[user units\] per step to all movement parameters to make the units in your application is more intuitive.

	*   For example, starting from position 0 and setting a new position with a rescale factor, the stepper will move `Position` / `RescaleFactor` steps.
	*   In this way, units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`. The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	  

	RescaleFactor = (1/16) * (MotorStepAngle/Degrees Per UserUnit)

	- returns:
	The rescale factor value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getRescaleFactor() throws -> Double {
		let result: PhidgetReturnCode
		var rescaleFactor: Double = 0
		result = PhidgetStepper_getRescaleFactor(chandle, &rescaleFactor)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return rescaleFactor
	}

	/**
	Applies a factor to the \[user units\] per step to all movement parameters to make the units in your application is more intuitive.

	*   For example, starting from position 0 and setting a new position with a rescale factor, the stepper will move `Position` / `RescaleFactor` steps.
	*   In this way, units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`. The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	  

	RescaleFactor = (1/16) * (MotorStepAngle/Degrees Per UserUnit)

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- rescaleFactor: The rescale factor value
	*/
	public func setRescaleFactor(_ rescaleFactor: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setRescaleFactor(chandle, rescaleFactor)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Resets the failsafe timer, if one has been set. See `enableFailsafe()` for details.

	This function will fail if no failsafe timer has been set for the channel.

	- throws:
	An error or type `PhidgetError`
	*/
	public func resetFailsafe() throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_resetFailsafe(chandle)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	If the controller is configured and the `TargetPosition` is set, the Stepper motor will move towards the `TargetPosition` at the specified `Acceleration` and `Velocity`.

	*   `TargetPosition` is only used when the `ControlMode` is set to step mode.
	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The position value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getTargetPosition() throws -> Double {
		let result: PhidgetReturnCode
		var targetPosition: Double = 0
		result = PhidgetStepper_getTargetPosition(chandle, &targetPosition)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return targetPosition
	}

	/**
	If the controller is configured and the `TargetPosition` is set, the Stepper motor will move towards the `TargetPosition` at the specified `Acceleration` and `Velocity`.

	*   `TargetPosition` is only used when the `ControlMode` is set to step mode.
	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- parameters:
		- targetPosition: The position value
		- completion: Asynchronous completion callback
	*/
	public func setTargetPosition(_ targetPosition: Double, completion: @escaping (ErrorCode) -> ()) {
		let callback = AsyncCallback(completion)
		let callbackCtx = Unmanaged.passRetained(callback)
		PhidgetStepper_setTargetPosition_async(chandle, targetPosition, AsyncCallback.nativeAsyncCallback, UnsafeMutableRawPointer(callbackCtx.toOpaque()))
	}

	/**
	If the controller is configured and the `TargetPosition` is set, the Stepper motor will move towards the `TargetPosition` at the specified `Acceleration` and `Velocity`.

	*   `TargetPosition` is only used when the `ControlMode` is set to step mode.
	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- targetPosition: The position value
	*/
	public func setTargetPosition(_ targetPosition: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setTargetPosition(chandle, targetPosition)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The most recent velocity value that the controller has reported.

	*   This value is bounded by `MinVelocityLimit` and `MaxVelocityLimit`.
	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The velocity value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getVelocity() throws -> Double {
		let result: PhidgetReturnCode
		var velocity: Double = 0
		result = PhidgetStepper_getVelocity(chandle, &velocity)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return velocity
	}

	/**
	When moving, the Stepper motor velocity will be limited by this value.

	*   The `VelocityLimit` is bounded by `MinVelocityLimit` and `MaxVelocityLimit`.
	*   When in step mode, the `MinVelocityLimit` has a value of 0. This is because the sign (±) of the `TargetPosition` will indicate the direction.
	*   When in run mode, the `MinVelocityLimit` has a value of -`MaxVelocityLimit`. This is because there is no target position, so the direction is defined by the sign (±) of the `VelocityLimit`.
	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.
	*   While `VelocityLimit` is listed as a double, it is rounded down to an integer number of 1/16th steps when sent to the board since the board is limited by a minimum unit of 1/16th steps/s. This is especially important to consider when using different `RescaleFactor` values where converting to units of, for example, RPM results in 1.5RPM (80 1/16th steps/s) and 1.509375 RPM (80.5 1/16th steps/s) both being sent to the board as 80 1/16th steps/s.

	- returns:
	Velocity limit

	- throws:
	An error or type `PhidgetError`
	*/
	public func getVelocityLimit() throws -> Double {
		let result: PhidgetReturnCode
		var velocityLimit: Double = 0
		result = PhidgetStepper_getVelocityLimit(chandle, &velocityLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return velocityLimit
	}

	/**
	When moving, the Stepper motor velocity will be limited by this value.

	*   The `VelocityLimit` is bounded by `MinVelocityLimit` and `MaxVelocityLimit`.
	*   When in step mode, the `MinVelocityLimit` has a value of 0. This is because the sign (±) of the `TargetPosition` will indicate the direction.
	*   When in run mode, the `MinVelocityLimit` has a value of -`MaxVelocityLimit`. This is because there is no target position, so the direction is defined by the sign (±) of the `VelocityLimit`.
	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.
	*   While `VelocityLimit` is listed as a double, it is rounded down to an integer number of 1/16th steps when sent to the board since the board is limited by a minimum unit of 1/16th steps/s. This is especially important to consider when using different `RescaleFactor` values where converting to units of, for example, RPM results in 1.5RPM (80 1/16th steps/s) and 1.509375 RPM (80.5 1/16th steps/s) both being sent to the board as 80 1/16th steps/s.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- velocityLimit: Velocity limit
	*/
	public func setVelocityLimit(_ velocityLimit: Double) throws {
		let result: PhidgetReturnCode
		result = PhidgetStepper_setVelocityLimit(chandle, velocityLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	The minimum value that `VelocityLimit` can be set to.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The velocity limit value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMinVelocityLimit() throws -> Double {
		let result: PhidgetReturnCode
		var minVelocityLimit: Double = 0
		result = PhidgetStepper_getMinVelocityLimit(chandle, &minVelocityLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return minVelocityLimit
	}

	/**
	The maximum value that `VelocityLimit` can be set to.

	*   Units for `Position`, `Velocity`, and `Acceleration` can be set by the user through the `RescaleFactor`.The `RescaleFactor` allows you to use more intuitive units such as rotations, or degrees.
	*   The default units for this motor controller are **1/16steps per count**.

	- returns:
	The velocity value

	- throws:
	An error or type `PhidgetError`
	*/
	public func getMaxVelocityLimit() throws -> Double {
		let result: PhidgetReturnCode
		var maxVelocityLimit: Double = 0
		result = PhidgetStepper_getMaxVelocityLimit(chandle, &maxVelocityLimit)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
		return maxVelocityLimit
	}

	internal override func initializeEvents() {
		initializeBaseEvents()
		PhidgetStepper_setOnPositionChangeHandler(chandle, nativePositionChangeHandler, UnsafeMutableRawPointer(selfCtx!.toOpaque()))
		PhidgetStepper_setOnStoppedHandler(chandle, nativeStoppedHandler, UnsafeMutableRawPointer(selfCtx!.toOpaque()))
		PhidgetStepper_setOnVelocityChangeHandler(chandle, nativeVelocityChangeHandler, UnsafeMutableRawPointer(selfCtx!.toOpaque()))
	}

	internal override func uninitializeEvents() {
		uninitializeBaseEvents()
		PhidgetStepper_setOnPositionChangeHandler(chandle, nil, nil)
		PhidgetStepper_setOnStoppedHandler(chandle, nil, nil)
		PhidgetStepper_setOnVelocityChangeHandler(chandle, nil, nil)
	}

	/**
	Occurs when the controller updates the stepper motor position.

	*   This event will still fire even if the motor is blocked from physically moving or misses steps.

	---
	## Parameters:
	*   `position`: The current stepper position
	*/
	public let positionChange = Event<Stepper, Double> ()
	let nativePositionChangeHandler : PhidgetStepper_OnPositionChangeCallback = { ch, ctx, position in
		let me = Unmanaged<Stepper>.fromOpaque(ctx!).takeUnretainedValue()
		me.positionChange.raise(me, position);
	}

	/**
	Occurs when the motor controller stops.

	*   The motor may still be physically moving if the inertia is great enough to make it misstep.
	*/
	public let stopped = SimpleEvent<Stepper> ()
	let nativeStoppedHandler : PhidgetStepper_OnStoppedCallback = { ch, ctx in
		let me = Unmanaged<Stepper>.fromOpaque(ctx!).takeUnretainedValue()
		me.stopped.raise(me);
	}

	/**
	Occurs when the stepper motor velocity changes.

	---
	## Parameters:
	*   `velocity`: Velocity of the stepper. Sign indicates direction.
	*/
	public let velocityChange = Event<Stepper, Double> ()
	let nativeVelocityChangeHandler : PhidgetStepper_OnVelocityChangeCallback = { ch, ctx, velocity in
		let me = Unmanaged<Stepper>.fromOpaque(ctx!).takeUnretainedValue()
		me.velocityChange.raise(me, velocity);
	}

}
