Controller¶
Namespace:
CtrlDS4
Emulated DS4 controller.
Call begin() once from setup(), then update() on every iteration of loop(). Drive the controls by binding buttons to pins with bind(), or set them from the sketch with the setters (setButton(), setStick(), setTrigger()): update() reports the latest state to the host.
Declare a single Controller in a sketch, since the board presents itself as one DS4.
CtrlDS4::Controller controller;
void setup() {
controller.bind(CtrlDS4::Cross, 2);
controller.begin();
}
void loop() {
controller.update();
}
Type aliases¶
RumbleCallback¶
Function called when the host changes the rumble.
Parameters
strongMotor: New speed of the StrongMotor.weakMotor: New speed of the WeakMotor.
LightbarCallback¶
Function called when the host changes the color of the lightbar.
Parameters
color: New color of the lightbar.
LightbarBlinkCallback¶
Function called when the host changes the blinking of the lightbar.
Parameters
blink: New blinking of the lightbar.
Methods¶
begin()¶
Chooses the MAC address, then connects to the host as a DS4.
Call once from setup(). It removes the USB serial port unless setUsbSerialEnabled() keeps it, and briefly disconnects the board from the host, so the host sees it again as a DS4: open the Serial Monitor after begin(), or reopen it.
Returns
true if the board could present itself as a DS4, false otherwise.
update()¶
Exchanges the latest state with the host.
Reads the pins of the bound controls, applies the rumble and lightbar changes requested by the host (calling the callbacks set with onRumble(), onLightbarColor() and onLightbarBlink()), then sends the state of the controls once per report interval (see setReportInterval()).
Call on every iteration of loop(), without blocking it for long: the host expects a new report every few milliseconds. Does nothing until begin() has succeeded.
isReady()¶
Tells whether the library is ready to use.
Returns
true once begin() has completed successfully, false otherwise.
setReportInterval(uint16_t)¶
Sets how often update() sends the state of the controls to the host.
The host polls the controller every millisecond, so a report reaches it at most 1 ms after update() sends it.
Parameters
intervalMs: Time between two reports in milliseconds, DEFAULT_REPORT_INTERVAL_MS until set. Lower it for less latency, at the cost of more USB traffic. 0 sends a report at every poll of the host.
setUsbSerialEnabled(bool)¶
Keeps or removes the USB serial port of the board (Serial) next to the controller.
A real DS4 has no serial port, and some hosts refuse a controller that has one, so begin() removes it unless it's kept here. Without it, Serial prints nothing, and uploading a new sketch needs the board to be put in bootloader mode by hand.
Call it before begin(), which applies it. While the port is removed, don't call Serial.begin() after begin(): it would add the port back while the host already knows the device.
Parameters
isEnabled: true to keep the serial port, e.g. to print to the Serial Monitor while developing. false to remove it, the default.
setButton(Button, bool)¶
Presses or releases a button.
A button bound to a pin (see bind()) follows its pin instead: the next update() overrides the value set here.
Parameters
button: Button to change. Ignored if it's not a Button value.isPressed: true to press the button, false to release it.
setStick(Stick, uint8_t, uint8_t)¶
Moves a stick, with the values of the DS4 report.
See setAxis() to move a single axis with a value from -1 to 1. An axis bound to pins (see bind()) follows its pins instead: the next update() overrides the value set here.
Parameters
stick: Stick to move. Ignored if it's not a Stick value.x: Horizontal position, from STICK_MIN (left) to STICK_MAX (right).y: Vertical position, from STICK_MIN (up) to STICK_MAX (down), as in the DS4 report.
setAxis(StickAxis, float)¶
Moves a single axis of a stick.
An axis bound to pins (see bind()) follows its pins instead: the next update() overrides the value set here.
controller.setAxis(CtrlDS4::LeftStickX, 1); // Left stick fully right
controller.setAxis(CtrlDS4::LeftStickY, -0.5); // Left stick halfway down
Parameters
axis: Axis to move. Ignored if it's not a StickAxis value.value: Position on the axis, from -1 to 1, 0 being at rest: X goes from left (-1) to right (1), and Y from down (-1) to up (1). Clamped to that range.
setTrigger(Trigger, uint8_t)¶
Presses a trigger, with the values of the DS4 report.
The trigger is also reported as a pressed button as soon as its value is above TRIGGER_MIN, as a real DS4 does. See setTriggerValue() to press it with a value from 0 to 1. A trigger bound to a pin (see bind()) follows its pin instead: the next update() overrides the value set here.
Parameters
trigger: Trigger to press. Ignored if it's not a Trigger value.value: How far the trigger is pressed, from TRIGGER_MIN (released) to TRIGGER_MAX (fully pressed).
setTriggerValue(Trigger, float)¶
Presses a trigger.
The trigger is also reported as a pressed button as soon as its value is above 0, as a real DS4 does. A trigger bound to a pin (see bind()) follows its pin instead: the next update() overrides the value set here.
Parameters
trigger: Trigger to press. Ignored if it's not a Trigger value.value: How far the trigger is pressed, from 0 (released) to 1 (fully pressed). Clamped to that range.
releaseAll()¶
Puts all the controls at rest: buttons released, sticks centered and triggers released.
bind(Button, uint8_t, ButtonWiring)¶
Drives a button from a pin of the board.
Sets the mode of the pin for the wiring, then update() reads it and presses or releases the button, filtering the bounces of the contacts (see setDebounceTime()).
controller.bind(CtrlDS4::Cross, 2); // Button between pin 2 and GND
controller.bind(CtrlDS4::Circle, 3, CtrlDS4::ActiveHigh); // Button between pin 3 and 3.3V
Parameters
button: Button to drive. Ignored if it's not a Button value. Binding it again replaces its previous pin.pin: Pin the button is wired to.wiring: How the button is wired to the pin.
unbind(Button)¶
Stops driving a button from its pin, and releases it.
The mode of the pin is left as is.
Parameters
bind(Trigger, uint8_t, ButtonWiring)¶
Drives a trigger from a button wired to a pin of the board.
The trigger is fully pressed while the button is pressed, and released otherwise.
Parameters
trigger: Trigger to drive. Ignored if it's not a Trigger value. Binding it again replaces its previous pin.pin: Pin the button is wired to.wiring: How the button is wired to the pin.
bind(StickAxis, AxisHalf, uint8_t, ButtonWiring)¶
Drives a half of a stick axis from a button wired to a pin of the board.
The axis is pushed to the end of that half while the button is pressed. Bind a button to each half to drive the whole axis: pressed together, they cancel each other.
controller.bind(CtrlDS4::LeftStickY, CtrlDS4::Positive, 5); // Up while pressed
controller.bind(CtrlDS4::LeftStickY, CtrlDS4::Negative, 6); // Down while pressed
Parameters
axis: Axis to drive. Ignored if it's not a StickAxis value. Replaces the analog pin of the whole axis, if any (see bindAnalog()).half: Half of the axis the button pushes to. Ignored if it's not an AxisHalf value. Binding it again replaces its previous pin.pin: Pin the button is wired to.wiring: How the button is wired to the pin.
bindAnalog(Trigger, uint8_t, const AnalogCalibration &)¶
void bindAnalog(Trigger trigger, uint8_t pin, const AnalogCalibration &calibration = AnalogCalibration())
Drives a trigger from an analog pin of the board.
The trigger follows the reading of the pin: released at AnalogCalibration::minReading, fully pressed at AnalogCalibration::maxReading. The pin is read on the update() calls that send a report to the host.
controller.bindAnalog(CtrlDS4::R2, A0); // Whole range
controller.bindAnalog(CtrlDS4::L2, A1, CtrlDS4::AnalogCalibration(80, 950)); // Calibrated
Parameters
trigger: Trigger to drive. Ignored if it's not a Trigger value. Binding it again replaces its previous pin.pin: Analog pin to read.calibration: Readings that match the released and fully pressed trigger, and deadzone near the released trigger. The whole analogRead() range by default.
bindAnalog(StickAxis, uint8_t, const AnalogCalibration &)¶
void bindAnalog(StickAxis axis, uint8_t pin, const AnalogCalibration &calibration = AnalogCalibration())
Drives a whole stick axis from an analog pin of the board, e.g. a potentiometer.
The axis follows the reading of the pin: left (X) or down (Y) at AnalogCalibration::minReading, right (X) or up (Y) at AnalogCalibration::maxReading, and centered halfway. The pin is read on the update() calls that send a report to the host.
controller.bindAnalog(CtrlDS4::LeftStickX, A0, CtrlDS4::AnalogCalibration(0, 1023, 0.05));
controller.bindAnalog(CtrlDS4::LeftStickY, A1, CtrlDS4::AnalogCalibration(1023, 0, 0.05)); // Inverted
Parameters
axis: Axis to drive. Ignored if it's not a StickAxis value. Replaces the previous pins of the axis, including the ones of its halves.pin: Analog pin to read.calibration: Readings that match both ends of the axis, and deadzone around the center. The whole analogRead() range by default.
bindAnalog(StickAxis, AxisHalf, uint8_t, const AnalogCalibration &)¶
void bindAnalog(StickAxis axis, AxisHalf half, uint8_t pin, const AnalogCalibration &calibration = AnalogCalibration())
Drives a half of a stick axis from an analog pin of the board, e.g. a pressure sensor.
The axis follows the reading of the pin, from rest at AnalogCalibration::minReading to the end of the half at AnalogCalibration::maxReading. Bind the other half to drive the whole axis: the axis value is the positive half minus the negative half. The pin is read on the update() calls that send a report to the host.
controller.bindAnalog(CtrlDS4::RightStickX, CtrlDS4::Positive, A0); // Pushes right
controller.bindAnalog(CtrlDS4::RightStickX, CtrlDS4::Negative, A1); // Pushes left
Parameters
axis: Axis to drive. Ignored if it's not a StickAxis value. Replaces the analog pin of the whole axis, if any.half: Half of the axis the pin drives. Ignored if it's not an AxisHalf value. Binding it again replaces its previous pin.pin: Analog pin to read.calibration: Readings that match rest and the end of the half, and deadzone near rest. The whole analogRead() range by default.
unbind(Trigger)¶
Stops driving a trigger from its pin, and releases it.
The mode of the pin is left as is.
Parameters
unbind(StickAxis)¶
Stops driving a stick axis from its pins (whole axis and both halves), and puts the axis at rest.
The mode of the pins is left as is.
Parameters
axis: Axis to stop driving. Ignored if it's not a StickAxis value, or not bound.
setDebounceTime(uint16_t)¶
Sets how long the bound buttons ignore their pin after a press or a release.
Applies to all the buttons wired to pins, including the ones driving a trigger or a stick axis.
Mechanical buttons bounce for a few milliseconds, which would read as several presses. Presses are still reported at once: this only limits how fast a button can be pressed again.
Parameters
debounceMs: Duration in milliseconds, DEFAULT_DEBOUNCE_MS until set. Raise it if a button reports double presses, lower it for very fast repeated presses. 0 disables the filter.
setMacAddress(const MacAddress &)¶
Sets the MAC address reported to the host, instead of the one begin() chooses.
Call it before begin(), since the host reads the address when the controller connects.
Parameters
macAddress: Address to report. See MacAddress for the bits to set and clear.
getMacAddress()¶
Gets the MAC address reported to the host.
Unless set with setMacAddress(), it's chosen by begin(): derived from the factory unique ID of the board, or a fixed fallback address if the board has none.
Returns
The MAC address. Only meaningful once begin() has been called, or setMacAddress().
getMacAddressSource()¶
Tells where the MAC address comes from.
Use it to warn when the board has no usable unique ID, since the fallback address is the same on all those boards.
Returns
Where the address returned by getMacAddress() comes from.
getRumble(Motor)¶
Gets the speed of a rumble motor, as last requested by the host.
Parameters
motor: Motor to read.
Returns
Speed of the motor, from 0 (stopped) to 255 (full speed). 0 if it's not a Motor value.
getLightbarColor()¶
Gets the color of the lightbar, as last requested by the host.
Returns
Color of the lightbar. Off until the host sets it.
getLightbarBlink()¶
Gets the blinking of the lightbar, as last requested by the host.
Returns
Blinking of the lightbar. Not blinking until the host sets it.
onRumble(RumbleCallback)¶
Sets the function to call when the host changes the rumble.
The function is called from update(), so it can safely drive pins or print to Serial.
Parameters
callback: Function to call, or nullptr to stop calling one.
onLightbarColor(LightbarCallback)¶
Sets the function to call when the host changes the color of the lightbar.
The function is called from update(), so it can safely drive pins or print to Serial.
Parameters
callback: Function to call, or nullptr to stop calling one.
onLightbarBlink(LightbarBlinkCallback)¶
Sets the function to call when the host changes the blinking of the lightbar.
The function is called from update(), so it can safely drive pins or print to Serial.
Parameters
callback: Function to call, or nullptr to stop calling one.