#############################################################
# This file was automatically generated on 2021-01-15.      #
#                                                           #
# Perl Bindings Version 2.1.29                              #
#                                                           #
# If you have a bugfix for this file and want to commit it, #
# please fix the bug in the generator. You can find a link  #
# to the generators git repository on tinkerforge.com       #
#############################################################

=pod

=encoding utf8

=head1 NAME

Tinkerforge::BrickletPerformanceDC - Drives one brushed DC motor with up to 36V and 10A

=cut

package Tinkerforge::BrickletPerformanceDC;

use strict;
use warnings;
use Carp;
use threads;
use threads::shared;
use parent 'Tinkerforge::Device';
use Tinkerforge::IPConnection;
use Tinkerforge::Error;

=head1 CONSTANTS

=over

=item DEVICE_IDENTIFIER

This constant is used to identify a Performance DC Bricklet.

The get_identity() subroutine and the CALLBACK_ENUMERATE callback of the
IP Connection have a device_identifier parameter to specify the Brick's or
Bricklet's type.

=cut

use constant DEVICE_IDENTIFIER => 2156;

=item DEVICE_DISPLAY_NAME

This constant represents the display name of a Performance DC Bricklet.

=cut

use constant DEVICE_DISPLAY_NAME => 'Performance DC Bricklet';

=item CALLBACK_EMERGENCY_SHUTDOWN

This constant is used with the register_callback() subroutine to specify
the CALLBACK_EMERGENCY_SHUTDOWN callback.

=cut

use constant CALLBACK_EMERGENCY_SHUTDOWN => 35;

=item CALLBACK_VELOCITY_REACHED

This constant is used with the register_callback() subroutine to specify
the CALLBACK_VELOCITY_REACHED callback.

=cut

use constant CALLBACK_VELOCITY_REACHED => 36;

=item CALLBACK_CURRENT_VELOCITY

This constant is used with the register_callback() subroutine to specify
the CALLBACK_CURRENT_VELOCITY callback.

=cut

use constant CALLBACK_CURRENT_VELOCITY => 37;

=item FUNCTION_SET_ENABLED

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_ENABLED => 1;

=item FUNCTION_GET_ENABLED

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_ENABLED => 2;

=item FUNCTION_SET_VELOCITY

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_VELOCITY => 3;

=item FUNCTION_GET_VELOCITY

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_VELOCITY => 4;

=item FUNCTION_GET_CURRENT_VELOCITY

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_CURRENT_VELOCITY => 5;

=item FUNCTION_SET_MOTION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_MOTION => 6;

=item FUNCTION_GET_MOTION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_MOTION => 7;

=item FUNCTION_FULL_BRAKE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_FULL_BRAKE => 8;

=item FUNCTION_SET_DRIVE_MODE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_DRIVE_MODE => 9;

=item FUNCTION_GET_DRIVE_MODE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_DRIVE_MODE => 10;

=item FUNCTION_SET_PWM_FREQUENCY

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_PWM_FREQUENCY => 11;

=item FUNCTION_GET_PWM_FREQUENCY

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_PWM_FREQUENCY => 12;

=item FUNCTION_GET_POWER_STATISTICS

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_POWER_STATISTICS => 13;

=item FUNCTION_SET_THERMAL_SHUTDOWN

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_THERMAL_SHUTDOWN => 14;

=item FUNCTION_GET_THERMAL_SHUTDOWN

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_THERMAL_SHUTDOWN => 15;

=item FUNCTION_SET_GPIO_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_GPIO_CONFIGURATION => 16;

=item FUNCTION_GET_GPIO_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_GPIO_CONFIGURATION => 17;

=item FUNCTION_SET_GPIO_ACTION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_GPIO_ACTION => 18;

=item FUNCTION_GET_GPIO_ACTION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_GPIO_ACTION => 19;

=item FUNCTION_GET_GPIO_STATE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_GPIO_STATE => 20;

=item FUNCTION_SET_ERROR_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_ERROR_LED_CONFIG => 21;

=item FUNCTION_GET_ERROR_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_ERROR_LED_CONFIG => 22;

=item FUNCTION_SET_CW_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_CW_LED_CONFIG => 23;

=item FUNCTION_GET_CW_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_CW_LED_CONFIG => 24;

=item FUNCTION_SET_CCW_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_CCW_LED_CONFIG => 25;

=item FUNCTION_GET_CCW_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_CCW_LED_CONFIG => 26;

=item FUNCTION_SET_GPIO_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_GPIO_LED_CONFIG => 27;

=item FUNCTION_GET_GPIO_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_GPIO_LED_CONFIG => 28;

=item FUNCTION_SET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION => 29;

=item FUNCTION_GET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION => 30;

=item FUNCTION_SET_VELOCITY_REACHED_CALLBACK_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_VELOCITY_REACHED_CALLBACK_CONFIGURATION => 31;

=item FUNCTION_GET_VELOCITY_REACHED_CALLBACK_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_VELOCITY_REACHED_CALLBACK_CONFIGURATION => 32;

=item FUNCTION_SET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION => 33;

=item FUNCTION_GET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION => 34;

=item FUNCTION_GET_SPITFP_ERROR_COUNT

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_SPITFP_ERROR_COUNT => 234;

=item FUNCTION_SET_BOOTLOADER_MODE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_BOOTLOADER_MODE => 235;

=item FUNCTION_GET_BOOTLOADER_MODE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_BOOTLOADER_MODE => 236;

=item FUNCTION_SET_WRITE_FIRMWARE_POINTER

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_WRITE_FIRMWARE_POINTER => 237;

=item FUNCTION_WRITE_FIRMWARE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_WRITE_FIRMWARE => 238;

=item FUNCTION_SET_STATUS_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_SET_STATUS_LED_CONFIG => 239;

=item FUNCTION_GET_STATUS_LED_CONFIG

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_STATUS_LED_CONFIG => 240;

=item FUNCTION_GET_CHIP_TEMPERATURE

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_CHIP_TEMPERATURE => 242;

=item FUNCTION_RESET

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_RESET => 243;

=item FUNCTION_WRITE_UID

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_WRITE_UID => 248;

=item FUNCTION_READ_UID

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_READ_UID => 249;

=item FUNCTION_GET_IDENTITY

This constant is used with the get_response_expected(), set_response_expected()
and set_response_expected_all() subroutines.

=cut

use constant FUNCTION_GET_IDENTITY => 255;
use constant DRIVE_MODE_DRIVE_BRAKE => 0;
use constant DRIVE_MODE_DRIVE_COAST => 1;
use constant GPIO_ACTION_NONE => 0;
use constant GPIO_ACTION_NORMAL_STOP_RISING_EDGE => 1;
use constant GPIO_ACTION_NORMAL_STOP_FALLING_EDGE => 2;
use constant GPIO_ACTION_FULL_BRAKE_RISING_EDGE => 4;
use constant GPIO_ACTION_FULL_BRAKE_FALLING_EDGE => 8;
use constant GPIO_ACTION_CALLBACK_RISING_EDGE => 16;
use constant GPIO_ACTION_CALLBACK_FALLING_EDGE => 32;
use constant ERROR_LED_CONFIG_OFF => 0;
use constant ERROR_LED_CONFIG_ON => 1;
use constant ERROR_LED_CONFIG_SHOW_HEARTBEAT => 2;
use constant ERROR_LED_CONFIG_SHOW_ERROR => 3;
use constant CW_LED_CONFIG_OFF => 0;
use constant CW_LED_CONFIG_ON => 1;
use constant CW_LED_CONFIG_SHOW_HEARTBEAT => 2;
use constant CW_LED_CONFIG_SHOW_CW_AS_FORWARD => 3;
use constant CW_LED_CONFIG_SHOW_CW_AS_BACKWARD => 4;
use constant CCW_LED_CONFIG_OFF => 0;
use constant CCW_LED_CONFIG_ON => 1;
use constant CCW_LED_CONFIG_SHOW_HEARTBEAT => 2;
use constant CCW_LED_CONFIG_SHOW_CCW_AS_FORWARD => 3;
use constant CCW_LED_CONFIG_SHOW_CCW_AS_BACKWARD => 4;
use constant GPIO_LED_CONFIG_OFF => 0;
use constant GPIO_LED_CONFIG_ON => 1;
use constant GPIO_LED_CONFIG_SHOW_HEARTBEAT => 2;
use constant GPIO_LED_CONFIG_SHOW_GPIO_ACTIVE_HIGH => 3;
use constant GPIO_LED_CONFIG_SHOW_GPIO_ACTIVE_LOW => 4;
use constant BOOTLOADER_MODE_BOOTLOADER => 0;
use constant BOOTLOADER_MODE_FIRMWARE => 1;
use constant BOOTLOADER_MODE_BOOTLOADER_WAIT_FOR_REBOOT => 2;
use constant BOOTLOADER_MODE_FIRMWARE_WAIT_FOR_REBOOT => 3;
use constant BOOTLOADER_MODE_FIRMWARE_WAIT_FOR_ERASE_AND_REBOOT => 4;
use constant BOOTLOADER_STATUS_OK => 0;
use constant BOOTLOADER_STATUS_INVALID_MODE => 1;
use constant BOOTLOADER_STATUS_NO_CHANGE => 2;
use constant BOOTLOADER_STATUS_ENTRY_FUNCTION_NOT_PRESENT => 3;
use constant BOOTLOADER_STATUS_DEVICE_IDENTIFIER_INCORRECT => 4;
use constant BOOTLOADER_STATUS_CRC_MISMATCH => 5;
use constant STATUS_LED_CONFIG_OFF => 0;
use constant STATUS_LED_CONFIG_ON => 1;
use constant STATUS_LED_CONFIG_SHOW_HEARTBEAT => 2;
use constant STATUS_LED_CONFIG_SHOW_STATUS => 3;


=back

=head1 FUNCTIONS

=over

=item new()

Creates an object with the unique device ID *uid* and adds it to
the IP Connection *ipcon*.

=cut

sub new
{
	my ($class, $uid, $ipcon) = @_;

	my $self = Tinkerforge::Device->_new($uid, $ipcon, [2, 0, 0], &DEVICE_IDENTIFIER, &DEVICE_DISPLAY_NAME);

	$self->{response_expected}->{&FUNCTION_SET_ENABLED} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_ENABLED} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_VELOCITY} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_VELOCITY} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_CURRENT_VELOCITY} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_MOTION} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_MOTION} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_FULL_BRAKE} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_SET_DRIVE_MODE} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_DRIVE_MODE} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_PWM_FREQUENCY} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_PWM_FREQUENCY} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_POWER_STATISTICS} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_THERMAL_SHUTDOWN} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_THERMAL_SHUTDOWN} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_GPIO_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_GPIO_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_GPIO_ACTION} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_GPIO_ACTION} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_GPIO_STATE} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_ERROR_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_ERROR_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_CW_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_CW_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_CCW_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_CCW_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_GPIO_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_GPIO_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_VELOCITY_REACHED_CALLBACK_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_VELOCITY_REACHED_CALLBACK_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_SPITFP_ERROR_COUNT} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_BOOTLOADER_MODE} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_BOOTLOADER_MODE} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_WRITE_FIRMWARE_POINTER} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_WRITE_FIRMWARE} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_SET_STATUS_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_GET_STATUS_LED_CONFIG} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_CHIP_TEMPERATURE} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_RESET} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_WRITE_UID} = Tinkerforge::Device->_RESPONSE_EXPECTED_FALSE;
	$self->{response_expected}->{&FUNCTION_READ_UID} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;
	$self->{response_expected}->{&FUNCTION_GET_IDENTITY} = Tinkerforge::Device->_RESPONSE_EXPECTED_ALWAYS_TRUE;

	$self->{callback_formats}->{&CALLBACK_EMERGENCY_SHUTDOWN} = shared_clone([8, '']);
	$self->{callback_formats}->{&CALLBACK_VELOCITY_REACHED} = shared_clone([10, 's']);
	$self->{callback_formats}->{&CALLBACK_CURRENT_VELOCITY} = shared_clone([10, 's']);



	bless($self, $class);

	$ipcon->_add_device($self);

	return $self;
}


=item set_enabled()

Enables/Disables the driver chip. The driver parameters can be configured
(velocity, acceleration, etc) before it is enabled.

=cut

sub set_enabled
{
	my ($self, $enabled) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_ENABLED, [$enabled], '?', 0, '');
}

=item get_enabled()

Returns *true* if the driver chip is enabled, *false* otherwise.

=cut

sub get_enabled
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_ENABLED, [], '', 9, '?');
}

=item set_velocity()

Sets the velocity of the motor. Whereas -32767 is full speed backward,
0 is stop and 32767 is full speed forward. Depending on the
acceleration (see :func:`Set Motion`), the motor is not immediately
brought to the velocity but smoothly accelerated.

The velocity describes the duty cycle of the PWM with which the motor is
controlled, e.g. a velocity of 3277 sets a PWM with a 10% duty cycle.
You can not only control the duty cycle of the PWM but also the frequency,
see :func:`Set PWM Frequency`.

=cut

sub set_velocity
{
	my ($self, $velocity) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_VELOCITY, [$velocity], 's', 0, '');
}

=item get_velocity()

Returns the velocity as set by :func:`Set Velocity`.

=cut

sub get_velocity
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_VELOCITY, [], '', 10, 's');
}

=item get_current_velocity()

Returns the *current* velocity of the motor. This value is different
from :func:`Get Velocity` whenever the motor is currently accelerating
to a goal set by :func:`Set Velocity`.

=cut

sub get_current_velocity
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_CURRENT_VELOCITY, [], '', 10, 's');
}

=item set_motion()

Sets the acceleration and deceleration of the motor. It is given in *velocity/s*.
An acceleration of 10000 means, that every second the velocity is increased
by 10000 (or about 30% duty cycle).

For example: If the current velocity is 0 and you want to accelerate to a
velocity of 16000 (about 50% duty cycle) in 10 seconds, you should set
an acceleration of 1600.

If acceleration and deceleration is set to 0, there is no speed ramping, i.e. a
new velocity is immediately given to the motor.

=cut

sub set_motion
{
	my ($self, $acceleration, $deceleration) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_MOTION, [$acceleration, $deceleration], 'S S', 0, '');
}

=item get_motion()

Returns the acceleration/deceleration as set by :func:`Set Motion`.

=cut

sub get_motion
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_MOTION, [], '', 12, 'S S');
}

=item full_brake()

Executes an active full brake.

.. warning::
 This function is for emergency purposes,
 where an immediate brake is necessary. Depending on the current velocity and
 the strength of the motor, a full brake can be quite violent.

Call :func:`Set Velocity` with 0 if you just want to stop the motor.

=cut

sub full_brake
{
	my ($self) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_FULL_BRAKE, [], '', 0, '');
}

=item set_drive_mode()

Sets the drive mode. Possible modes are:

* 0 = Drive/Brake
* 1 = Drive/Coast

These modes are different kinds of motor controls.

In Drive/Brake mode, the motor is always either driving or braking. There
is no freewheeling. Advantages are: A more linear correlation between
PWM and velocity, more exact accelerations and the possibility to drive
with slower velocities.

In Drive/Coast mode, the motor is always either driving or freewheeling.
Advantages are: Less current consumption and less demands on the motor and
driver chip.

=cut

sub set_drive_mode
{
	my ($self, $mode) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_DRIVE_MODE, [$mode], 'C', 0, '');
}

=item get_drive_mode()

Returns the drive mode, as set by :func:`Set Drive Mode`.

=cut

sub get_drive_mode
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_DRIVE_MODE, [], '', 9, 'C');
}

=item set_pwm_frequency()

Sets the frequency of the PWM with which the motor is driven.
Often a high frequency
is less noisy and the motor runs smoother. However, with a low frequency
there are less switches and therefore fewer switching losses. Also with
most motors lower frequencies enable higher torque.

If you have no idea what all this means, just ignore this function and use
the default frequency, it will very likely work fine.

=cut

sub set_pwm_frequency
{
	my ($self, $frequency) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_PWM_FREQUENCY, [$frequency], 'S', 0, '');
}

=item get_pwm_frequency()

Returns the PWM frequency as set by :func:`Set PWM Frequency`.

=cut

sub get_pwm_frequency
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_PWM_FREQUENCY, [], '', 10, 'S');
}

=item get_power_statistics()

Returns input voltage, current usage and temperature of the driver.

=cut

sub get_power_statistics
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_POWER_STATISTICS, [], '', 14, 'S S s');
}

=item set_thermal_shutdown()

Sets a temperature threshold that is used for thermal shutdown.

Additionally to this user defined threshold the driver chip will shut down at a
temperature of 150°C.

If a thermal shutdown is triggered the driver is disabled and has to be
explicitly re-enabled with :func:`Set Enabled`.

=cut

sub set_thermal_shutdown
{
	my ($self, $temperature) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_THERMAL_SHUTDOWN, [$temperature], 'C', 0, '');
}

=item get_thermal_shutdown()

Returns the thermal shutdown temperature as set by :func:`Set Thermal Shutdown`.

=cut

sub get_thermal_shutdown
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_THERMAL_SHUTDOWN, [], '', 9, 'C');
}

=item set_gpio_configuration()

Sets the GPIO configuration for the given channel.
You can configure a debounce and the deceleration that is used if the action is
configured as ``normal stop``. See :func:`Set GPIO Action`.

=cut

sub set_gpio_configuration
{
	my ($self, $channel, $debounce, $stop_deceleration) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_GPIO_CONFIGURATION, [$channel, $debounce, $stop_deceleration], 'C S S', 0, '');
}

=item get_gpio_configuration()

Returns the GPIO configuration for a channel as set by :func:`Set GPIO Configuration`.

=cut

sub get_gpio_configuration
{
	my ($self, $channel) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_GPIO_CONFIGURATION, [$channel], 'C', 12, 'S S');
}

=item set_gpio_action()

Sets the GPIO action for the given channel.

The action can be a normal stop, a full brake or a callback. Each for a rising
edge or falling edge. The actions are a bitmask they can be used at the same time.
You can for example trigger a full brake and a callback at the same time or for
rising and falling edge.

The deceleration speed for the normal stop can be configured with
:func:`Set GPIO Configuration`.

=cut

sub set_gpio_action
{
	my ($self, $channel, $action) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_GPIO_ACTION, [$channel, $action], 'C L', 0, '');
}

=item get_gpio_action()

Returns the GPIO action for a channel as set by :func:`Set GPIO Action`.

=cut

sub get_gpio_action
{
	my ($self, $channel) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_GPIO_ACTION, [$channel], 'C', 12, 'L');
}

=item get_gpio_state()

Returns the GPIO state for both channels. True if the state is ``high`` and
false if the state is ``low``.

=cut

sub get_gpio_state
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_GPIO_STATE, [], '', 9, '?2');
}

=item set_error_led_config()

Configures the error LED to be either turned off, turned on, blink in
heartbeat mode or show an error.

If the LED is configured to show errors it has three different states:

* Off: No error present.
* 1s interval blinking: Input voltage too low (below 6V).
* 250ms interval blinking: Overtemperature or overcurrent.

=cut

sub set_error_led_config
{
	my ($self, $config) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_ERROR_LED_CONFIG, [$config], 'C', 0, '');
}

=item get_error_led_config()

Returns the LED configuration as set by :func:`Set Error LED Config`

=cut

sub get_error_led_config
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_ERROR_LED_CONFIG, [], '', 9, 'C');
}

=item set_cw_led_config()

Configures the CW LED to be either turned off, turned on, blink in
heartbeat mode or if the motor turn clockwise.

=cut

sub set_cw_led_config
{
	my ($self, $config) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_CW_LED_CONFIG, [$config], 'C', 0, '');
}

=item get_cw_led_config()

Returns the LED configuration as set by :func:`Set CW LED Config`

=cut

sub get_cw_led_config
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_CW_LED_CONFIG, [], '', 9, 'C');
}

=item set_ccw_led_config()

Configures the CCW LED to be either turned off, turned on, blink in
heartbeat mode or if the motor turn counter-clockwise.

=cut

sub set_ccw_led_config
{
	my ($self, $config) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_CCW_LED_CONFIG, [$config], 'C', 0, '');
}

=item get_ccw_led_config()

Returns the LED configuration as set by :func:`Set CCW LED Config`

=cut

sub get_ccw_led_config
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_CCW_LED_CONFIG, [], '', 9, 'C');
}

=item set_gpio_led_config()

Configures the GPIO LED to be either turned off, turned on, blink in
heartbeat mode or the GPIO state.

The GPIO LED can be configured for both channels.

=cut

sub set_gpio_led_config
{
	my ($self, $channel, $config) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_GPIO_LED_CONFIG, [$channel, $config], 'C C', 0, '');
}

=item get_gpio_led_config()

Returns the LED configuration as set by :func:`Set GPIO LED Config`

=cut

sub get_gpio_led_config
{
	my ($self, $channel) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_GPIO_LED_CONFIG, [$channel], 'C', 9, 'C');
}

=item set_emergency_shutdown_callback_configuration()

Enable/Disable :cb:`Emergency Shutdown` callback.

=cut

sub set_emergency_shutdown_callback_configuration
{
	my ($self, $enabled) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION, [$enabled], '?', 0, '');
}

=item get_emergency_shutdown_callback_configuration()

Returns the callback configuration as set by
:func:`Set Emergency Shutdown Callback Configuration`.

=cut

sub get_emergency_shutdown_callback_configuration
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_EMERGENCY_SHUTDOWN_CALLBACK_CONFIGURATION, [], '', 9, '?');
}

=item set_velocity_reached_callback_configuration()

Enable/Disable :cb:`Velocity Reached` callback.

=cut

sub set_velocity_reached_callback_configuration
{
	my ($self, $enabled) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_VELOCITY_REACHED_CALLBACK_CONFIGURATION, [$enabled], '?', 0, '');
}

=item get_velocity_reached_callback_configuration()

Returns the callback configuration as set by
:func:`Set Velocity Reached Callback Configuration`.

=cut

sub get_velocity_reached_callback_configuration
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_VELOCITY_REACHED_CALLBACK_CONFIGURATION, [], '', 9, '?');
}

=item set_current_velocity_callback_configuration()

The period is the period with which the :cb:`Current Velocity`
callback is triggered periodically. A value of 0 turns the callback off.

If the `value has to change`-parameter is set to true, the callback is only
triggered after the value has changed. If the value didn't change within the
period, the callback is triggered immediately on change.

If it is set to false, the callback is continuously triggered with the period,
independent of the value.

=cut

sub set_current_velocity_callback_configuration
{
	my ($self, $period, $value_has_to_change) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION, [$period, $value_has_to_change], 'L ?', 0, '');
}

=item get_current_velocity_callback_configuration()

Returns the callback configuration as set by
:func:`Set Current Velocity Callback Configuration`.

=cut

sub get_current_velocity_callback_configuration
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_CURRENT_VELOCITY_CALLBACK_CONFIGURATION, [], '', 13, 'L ?');
}

=item get_spitfp_error_count()

Returns the error count for the communication between Brick and Bricklet.

The errors are divided into

* ACK checksum errors,
* message checksum errors,
* framing errors and
* overflow errors.

The errors counts are for errors that occur on the Bricklet side. All
Bricks have a similar function that returns the errors on the Brick side.

=cut

sub get_spitfp_error_count
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_SPITFP_ERROR_COUNT, [], '', 24, 'L L L L');
}

=item set_bootloader_mode()

Sets the bootloader mode and returns the status after the requested
mode change was instigated.

You can change from bootloader mode to firmware mode and vice versa. A change
from bootloader mode to firmware mode will only take place if the entry function,
device identifier and CRC are present and correct.

This function is used by Brick Viewer during flashing. It should not be
necessary to call it in a normal user program.

=cut

sub set_bootloader_mode
{
	my ($self, $mode) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_SET_BOOTLOADER_MODE, [$mode], 'C', 9, 'C');
}

=item get_bootloader_mode()

Returns the current bootloader mode, see :func:`Set Bootloader Mode`.

=cut

sub get_bootloader_mode
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_BOOTLOADER_MODE, [], '', 9, 'C');
}

=item set_write_firmware_pointer()

Sets the firmware pointer for :func:`Write Firmware`. The pointer has
to be increased by chunks of size 64. The data is written to flash
every 4 chunks (which equals to one page of size 256).

This function is used by Brick Viewer during flashing. It should not be
necessary to call it in a normal user program.

=cut

sub set_write_firmware_pointer
{
	my ($self, $pointer) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_WRITE_FIRMWARE_POINTER, [$pointer], 'L', 0, '');
}

=item write_firmware()

Writes 64 Bytes of firmware at the position as written by
:func:`Set Write Firmware Pointer` before. The firmware is written
to flash every 4 chunks.

You can only write firmware in bootloader mode.

This function is used by Brick Viewer during flashing. It should not be
necessary to call it in a normal user program.

=cut

sub write_firmware
{
	my ($self, $data) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_WRITE_FIRMWARE, [$data], 'C64', 9, 'C');
}

=item set_status_led_config()

Sets the status LED configuration. By default the LED shows
communication traffic between Brick and Bricklet, it flickers once
for every 10 received data packets.

You can also turn the LED permanently on/off or show a heartbeat.

If the Bricklet is in bootloader mode, the LED is will show heartbeat by default.

=cut

sub set_status_led_config
{
	my ($self, $config) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_SET_STATUS_LED_CONFIG, [$config], 'C', 0, '');
}

=item get_status_led_config()

Returns the configuration as set by :func:`Set Status LED Config`

=cut

sub get_status_led_config
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_STATUS_LED_CONFIG, [], '', 9, 'C');
}

=item get_chip_temperature()

Returns the temperature as measured inside the microcontroller. The
value returned is not the ambient temperature!

The temperature is only proportional to the real temperature and it has bad
accuracy. Practically it is only useful as an indicator for
temperature changes.

=cut

sub get_chip_temperature
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_GET_CHIP_TEMPERATURE, [], '', 10, 's');
}

=item reset()

Calling this function will reset the Bricklet. All configurations
will be lost.

After a reset you have to create new device objects,
calling functions on the existing ones will result in
undefined behavior!

=cut

sub reset
{
	my ($self) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_RESET, [], '', 0, '');
}

=item write_uid()

Writes a new UID into flash. If you want to set a new UID
you have to decode the Base58 encoded UID string into an
integer first.

We recommend that you use Brick Viewer to change the UID.

=cut

sub write_uid
{
	my ($self, $uid) = @_;

	$self->_check_validity();

	$self->_send_request(&FUNCTION_WRITE_UID, [$uid], 'L', 0, '');
}

=item read_uid()

Returns the current UID as an integer. Encode as
Base58 to get the usual string version.

=cut

sub read_uid
{
	my ($self) = @_;

	$self->_check_validity();

	return $self->_send_request(&FUNCTION_READ_UID, [], '', 12, 'L');
}

=item get_identity()

Returns the UID, the UID where the Bricklet is connected to,
the position, the hardware and firmware version as well as the
device identifier.

The position can be 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h' (Bricklet Port).
A Bricklet connected to an :ref:`Isolator Bricklet <isolator_bricklet>` is always at
position 'z'.

The device identifier numbers can be found :ref:`here <device_identifier>`.
|device_identifier_constant|

=cut

sub get_identity
{
	my ($self) = @_;

	return $self->_send_request(&FUNCTION_GET_IDENTITY, [], '', 33, 'Z8 Z8 a C3 C3 S');
}

=back
=cut

1;
