
#############################################################
# This file was automatically generated on 2014-02-24.      #
#                                                           #
# Bindings Version 2.0.1                                    #
#                                                           #
# 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 generator git on tinkerforge.com                   #
#############################################################

package Tinkerforge::BrickIMU;
=comment
        Device for sensing acceleration, magnetic field and angular velocity
=cut

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

use constant DEVICE_IDENTIFIER => 16;
use constant CALLBACK_ACCELERATION => 31;
use constant CALLBACK_MAGNETIC_FIELD => 32;
use constant CALLBACK_ANGULAR_VELOCITY => 33;
use constant CALLBACK_ALL_DATA => 34;
use constant CALLBACK_ORIENTATION => 35;
use constant CALLBACK_QUATERNION => 36;

use constant FUNCTION_GET_ACCELERATION => 1;
use constant FUNCTION_GET_MAGNETIC_FIELD => 2;
use constant FUNCTION_GET_ANGULAR_VELOCITY => 3;
use constant FUNCTION_GET_ALL_DATA => 4;
use constant FUNCTION_GET_ORIENTATION => 5;
use constant FUNCTION_GET_QUATERNION => 6;
use constant FUNCTION_GET_IMU_TEMPERATURE => 7;
use constant FUNCTION_LEDS_ON => 8;
use constant FUNCTION_LEDS_OFF => 9;
use constant FUNCTION_ARE_LEDS_ON => 10;
use constant FUNCTION_SET_ACCELERATION_RANGE => 11;
use constant FUNCTION_GET_ACCELERATION_RANGE => 12;
use constant FUNCTION_SET_MAGNETOMETER_RANGE => 13;
use constant FUNCTION_GET_MAGNETOMETER_RANGE => 14;
use constant FUNCTION_SET_CONVERGENCE_SPEED => 15;
use constant FUNCTION_GET_CONVERGENCE_SPEED => 16;
use constant FUNCTION_SET_CALIBRATION => 17;
use constant FUNCTION_GET_CALIBRATION => 18;
use constant FUNCTION_SET_ACCELERATION_PERIOD => 19;
use constant FUNCTION_GET_ACCELERATION_PERIOD => 20;
use constant FUNCTION_SET_MAGNETIC_FIELD_PERIOD => 21;
use constant FUNCTION_GET_MAGNETIC_FIELD_PERIOD => 22;
use constant FUNCTION_SET_ANGULAR_VELOCITY_PERIOD => 23;
use constant FUNCTION_GET_ANGULAR_VELOCITY_PERIOD => 24;
use constant FUNCTION_SET_ALL_DATA_PERIOD => 25;
use constant FUNCTION_GET_ALL_DATA_PERIOD => 26;
use constant FUNCTION_SET_ORIENTATION_PERIOD => 27;
use constant FUNCTION_GET_ORIENTATION_PERIOD => 28;
use constant FUNCTION_SET_QUATERNION_PERIOD => 29;
use constant FUNCTION_GET_QUATERNION_PERIOD => 30;
use constant FUNCTION_ORIENTATION_CALCULATION_ON => 37;
use constant FUNCTION_ORIENTATION_CALCULATION_OFF => 38;
use constant FUNCTION_IS_ORIENTATION_CALCULATION_ON => 39;
use constant FUNCTION_GET_PROTOCOL1_BRICKLET_NAME => 241;
use constant FUNCTION_GET_CHIP_TEMPERATURE => 242;
use constant FUNCTION_RESET => 243;
use constant FUNCTION_GET_IDENTITY => 255;

use constant CALIBRATION_TYPE_ACCELEROMETER_GAIN => 0;
use constant CALIBRATION_TYPE_ACCELEROMETER_BIAS => 1;
use constant CALIBRATION_TYPE_MAGNETOMETER_GAIN => 2;
use constant CALIBRATION_TYPE_MAGNETOMETER_BIAS => 3;
use constant CALIBRATION_TYPE_GYROSCOPE_GAIN => 4;
use constant CALIBRATION_TYPE_GYROSCOPE_BIAS => 5;

sub new
{
=comment
        Creates an object with the unique device ID *uid* and adds it to
        the IP Connection *ipcon*.
=cut
    my ($class, $uid, $ipcon) = @_;

    my $self :shared = shared_clone({super => shared_clone(Tinkerforge::Device->new($uid, $ipcon)),
                                     api_version => [2, 0, 1],
                                     response_expected => shared_clone({&FUNCTION_GET_ACCELERATION => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_MAGNETIC_FIELD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_ANGULAR_VELOCITY => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_ALL_DATA => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_ORIENTATION => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_QUATERNION => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_IMU_TEMPERATURE => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_LEDS_ON => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_LEDS_OFF => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_ARE_LEDS_ON => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_ACCELERATION_RANGE => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_GET_ACCELERATION_RANGE => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_MAGNETOMETER_RANGE => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_GET_MAGNETOMETER_RANGE => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_CONVERGENCE_SPEED => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_GET_CONVERGENCE_SPEED => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_CALIBRATION => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_GET_CALIBRATION => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_ACCELERATION_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_TRUE,
                                                                        &FUNCTION_GET_ACCELERATION_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_MAGNETIC_FIELD_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_TRUE,
                                                                        &FUNCTION_GET_MAGNETIC_FIELD_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_ANGULAR_VELOCITY_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_TRUE,
                                                                        &FUNCTION_GET_ANGULAR_VELOCITY_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_ALL_DATA_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_TRUE,
                                                                        &FUNCTION_GET_ALL_DATA_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_ORIENTATION_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_TRUE,
                                                                        &FUNCTION_GET_ORIENTATION_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_SET_QUATERNION_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_TRUE,
                                                                        &FUNCTION_GET_QUATERNION_PERIOD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &CALLBACK_ACCELERATION => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_FALSE,
                                                                        &CALLBACK_MAGNETIC_FIELD => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_FALSE,
                                                                        &CALLBACK_ANGULAR_VELOCITY => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_FALSE,
                                                                        &CALLBACK_ALL_DATA => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_FALSE,
                                                                        &CALLBACK_ORIENTATION => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_FALSE,
                                                                        &CALLBACK_QUATERNION => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_FALSE,
                                                                        &FUNCTION_ORIENTATION_CALCULATION_ON => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_ORIENTATION_CALCULATION_OFF => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_IS_ORIENTATION_CALCULATION_ON => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_PROTOCOL1_BRICKLET_NAME => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_GET_CHIP_TEMPERATURE => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE,
                                                                        &FUNCTION_RESET => Tinkerforge::Device->RESPONSE_EXPECTED_FALSE,
                                                                        &FUNCTION_GET_IDENTITY => Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE}),
                                    callback_formats => shared_clone({&CALLBACK_ACCELERATION => 's s s',
                                                                      &CALLBACK_MAGNETIC_FIELD => 's s s',
                                                                      &CALLBACK_ANGULAR_VELOCITY => 's s s',
                                                                      &CALLBACK_ALL_DATA => 's s s s s s s s s s',
                                                                      &CALLBACK_ORIENTATION => 's s s',
                                                                      &CALLBACK_QUATERNION => 'f f f f'})});

    $self->{super}->{ipcon}->{devices}->{$self->{super}->{uid}} = $self;

    $self->{super}->{api_version} = $self->{api_version};

    bless($self, $class);

    return $self;
}

sub get_acceleration
{
=comment
        Returns the calibrated acceleration from the accelerometer for the 
        x, y and z axis in mG (G/1000, 1G = 9.80605m/s²).
        
        If you want to get the acceleration periodically, it is recommended 
        to use the callback :func:`Acceleration` and set the period with 
        :func:`SetAccelerationPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ACCELERATION, [], '', 's s s');
 }

sub get_magnetic_field
{
=comment
        Returns the calibrated magnetic field from the magnetometer for the 
        x, y and z axis in mG (Milligauss or Nanotesla).
        
        If you want to get the magnetic field periodically, it is recommended 
        to use the callback :func:`MagneticField` and set the period with 
        :func:`SetMagneticFieldPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_MAGNETIC_FIELD, [], '', 's s s');
 }

sub get_angular_velocity
{
=comment
        Returns the calibrated angular velocity from the gyroscope for the 
        x, y and z axis in °/14.375s (you have to divide by 14.375 to
        get the value in °/s).
        
        If you want to get the angular velocity periodically, it is recommended 
        to use the callback :func:`AngularVelocity` and set the period with 
        :func:`SetAngularVelocityPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ANGULAR_VELOCITY, [], '', 's s s');
 }

sub get_all_data
{
=comment
        Returns the data from :func:`GetAcceleration`, :func:`GetMagneticField` 
        and :func:`GetAngularVelocity` as well as the temperature of the IMU Brick.
        
        The temperature is given in °C/100.
        
        If you want to get the data periodically, it is recommended 
        to use the callback :func:`AllData` and set the period with 
        :func:`SetAllDataPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ALL_DATA, [], '', 's s s s s s s s s s');
 }

sub get_orientation
{
=comment
        Returns the current orientation (roll, pitch, yaw) of the IMU Brick as Euler
        angles in one-hundredth degree. Note that Euler angles always experience a
        `gimbal lock <http://en.wikipedia.org/wiki/Gimbal_lock>`__.
        
        We recommend that you use quaternions instead.
        
        The order to sequence in which the orientation values should be applied is 
        roll, yaw, pitch. 
        
        If you want to get the orientation periodically, it is recommended 
        to use the callback :func:`Orientation` and set the period with 
        :func:`SetOrientationPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ORIENTATION, [], '', 's s s');
 }

sub get_quaternion
{
=comment
        Returns the current orientation (x, y, z, w) of the IMU as 
        `quaternions <http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation>`__.
        
        You can go from quaternions to Euler angles with the following formula::
        
         roll  = atan2(2*y*w - 2*x*z, 1 - 2*y*y - 2*z*z)
         pitch = atan2(2*x*w - 2*y*z, 1 - 2*x*x - 2*z*z)
         yaw   =  asin(2*x*y + 2*z*w)
        
        This process is not reversible, because of the 
        `gimbal lock <http://en.wikipedia.org/wiki/Gimbal_lock>`__.
        
        Converting the quaternions to an OpenGL transformation matrix is
        possible with the following formula::
        
         matrix = [[1 - 2*(y*y + z*z),     2*(x*y - w*z),     2*(x*z + w*y), 0],
                   [    2*(x*y + w*z), 1 - 2*(x*x + z*z),     2*(y*z - w*x), 0],
                   [    2*(x*z - w*y),     2*(y*z + w*x), 1 - 2*(x*x + y*y), 0],
                   [                0,                 0,                 0, 1]]
        
        If you want to get the quaternions periodically, it is recommended 
        to use the callback :func:`Quaternion` and set the period with 
        :func:`SetQuaternionPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_QUATERNION, [], '', 'f f f f');
 }

sub get_imu_temperature
{
=comment
        Returns the temperature of the IMU Brick. The temperature is given in 
        °C/100.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_IMU_TEMPERATURE, [], '', 's');
}

sub leds_on
{
=comment
        Turns the orientation and direction LEDs of the IMU Brick on.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    $self->{super}->send_request($self, &FUNCTION_LEDS_ON, [], '', '');
}

sub leds_off
{
=comment
        Turns the orientation and direction LEDs of the IMU Brick off.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    $self->{super}->send_request($self, &FUNCTION_LEDS_OFF, [], '', '');
}

sub are_leds_on
{
=comment
        Returns *true* if the orientation and direction LEDs of the IMU Brick
        are on, *false* otherwise.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_ARE_LEDS_ON, [], '', 'C');
}

sub set_acceleration_range
{
=comment
        Not implemented yet.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $range) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_ACCELERATION_RANGE, [$range], 'C', '');
}

sub get_acceleration_range
{
=comment
        Not implemented yet.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ACCELERATION_RANGE, [], '', 'C');
}

sub set_magnetometer_range
{
=comment
        Not implemented yet.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $range) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_MAGNETOMETER_RANGE, [$range], 'C', '');
}

sub get_magnetometer_range
{
=comment
        Not implemented yet.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_MAGNETOMETER_RANGE, [], '', 'C');
}

sub set_convergence_speed
{
=comment
        Sets the convergence speed of the IMU Brick in °/s. The convergence speed 
        determines how the different sensor measurements are fused.
        
        If the orientation of the IMU Brick is off by 10° and the convergence speed is 
        set to 20°/s, it will take 0.5s until the orientation is corrected. However,
        if the correct orientation is reached and the convergence speed is too high,
        the orientation will fluctuate with the fluctuations of the accelerometer and
        the magnetometer.
        
        If you set the convergence speed to 0, practically only the gyroscope is used
        to calculate the orientation. This gives very smooth movements, but errors of the
        gyroscope will not be corrected. If you set the convergence speed to something
        above 500, practically only the magnetometer and the accelerometer are used to
        calculate the orientation. In this case the movements are abrupt and the values
        will fluctuate, but there won't be any errors that accumulate over time.
        
        In an application with high angular velocities, we recommend a high convergence
        speed, so the errors of the gyroscope can be corrected fast. In applications with
        only slow movements we recommend a low convergence speed. You can change the
        convergence speed on the fly. So it is possible (and recommended) to increase 
        the convergence speed before an abrupt movement and decrease it afterwards 
        again.
        
        You might want to play around with the convergence speed in the Brick Viewer to
        get a feeling for a good value for your application.
        
        The default value is 30.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $speed) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_CONVERGENCE_SPEED, [$speed], 'S', '');
}

sub get_convergence_speed
{
=comment
        Returns the convergence speed as set by :func:`SetConvergenceSpeed`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_CONVERGENCE_SPEED, [], '', 'S');
}

sub set_calibration
{
=comment
        There are several different types that can be calibrated:
        
        .. csv-table::
         :header: "Type", "Description", "Values"
         :widths: 10, 30, 110
        
         "0",    "Accelerometer Gain", "``[mul x, mul y, mul z, div x, div y, div z, 0, 0, 0, 0]``"
         "1",    "Accelerometer Bias", "``[bias x, bias y, bias z, 0, 0, 0, 0, 0, 0, 0]``"
         "2",    "Magnetometer Gain",  "``[mul x, mul y, mul z, div x, div y, div z, 0, 0, 0, 0]``"
         "3",    "Magnetometer Bias",  "``[bias x, bias y, bias z, 0, 0, 0, 0, 0, 0, 0]``"
         "4",    "Gyroscope Gain",     "``[mul x, mul y, mul z, div x, div y, div z, 0, 0, 0, 0]``"
         "5",    "Gyroscope Bias",     "``[bias xl, bias yl, bias zl, temp l, bias xh, bias yh, bias zh, temp h, 0, 0]``"
        
        The calibration via gain and bias is done with the following formula::
        
         new_value = (bias + orig_value) * gain_mul / gain_div
        
        If you really want to write your own calibration software, please keep
        in mind that you first have to undo the old calibration (set bias to 0 and
        gain to 1/1) and that you have to average over several thousand values
        to obtain a usable result in the end.
        
        The gyroscope bias is highly dependent on the temperature, so you have to
        calibrate the bias two times with different temperatures. The values ``xl``,
        ``yl``, ``zl`` and ``temp l`` are the bias for ``x``, ``y``, ``z`` and the
        corresponding temperature for a low temperature. The values ``xh``, ``yh``,
        ``zh`` and ``temp h`` are the same for a high temperatures. The temperature
        difference should be at least 5°C. If you have a temperature where the
        IMU Brick is mostly used, you should use this temperature for one of the
        sampling points.
        
        .. note::
         We highly recommend that you use the Brick Viewer to calibrate your
         IMU Brick.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $typ, $data) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_CALIBRATION, [$typ, $data], 'C s10', '');
}

sub get_calibration
{
=comment
        Returns the calibration for a given type as set by :func:`SetCalibration`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $typ) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_CALIBRATION, [$typ], 'C', 's10');
}

sub set_acceleration_period
{
=comment
        Sets the period in ms with which the :func:`Acceleration` callback is triggered
        periodically. A value of 0 turns the callback off.
        
        The default value is 0.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $period) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_ACCELERATION_PERIOD, [$period], 'L', '');
}

sub get_acceleration_period
{
=comment
        Returns the period as set by :func:`SetAccelerationPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ACCELERATION_PERIOD, [], '', 'L');
}

sub set_magnetic_field_period
{
=comment
        Sets the period in ms with which the :func:`MagneticField` callback is triggered
        periodically. A value of 0 turns the callback off.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $period) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_MAGNETIC_FIELD_PERIOD, [$period], 'L', '');
}

sub get_magnetic_field_period
{
=comment
        Returns the period as set by :func:`SetMagneticFieldPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_MAGNETIC_FIELD_PERIOD, [], '', 'L');
}

sub set_angular_velocity_period
{
=comment
        Sets the period in ms with which the :func:`AngularVelocity` callback is triggered
        periodically. A value of 0 turns the callback off.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $period) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_ANGULAR_VELOCITY_PERIOD, [$period], 'L', '');
}

sub get_angular_velocity_period
{
=comment
        Returns the period as set by :func:`SetAngularVelocityPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ANGULAR_VELOCITY_PERIOD, [], '', 'L');
}

sub set_all_data_period
{
=comment
        Sets the period in ms with which the :func:`AllData` callback is triggered
        periodically. A value of 0 turns the callback off.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $period) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_ALL_DATA_PERIOD, [$period], 'L', '');
}

sub get_all_data_period
{
=comment
        Returns the period as set by :func:`SetAllDataPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ALL_DATA_PERIOD, [], '', 'L');
}

sub set_orientation_period
{
=comment
        Sets the period in ms with which the :func:`Orientation` callback is triggered
        periodically. A value of 0 turns the callback off.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $period) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_ORIENTATION_PERIOD, [$period], 'L', '');
}

sub get_orientation_period
{
=comment
        Returns the period as set by :func:`SetOrientationPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_ORIENTATION_PERIOD, [], '', 'L');
}

sub set_quaternion_period
{
=comment
        Sets the period in ms with which the :func:`Quaternion` callback is triggered
        periodically. A value of 0 turns the callback off.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $period) = @_;

    $self->{super}->send_request($self, &FUNCTION_SET_QUATERNION_PERIOD, [$period], 'L', '');
}

sub get_quaternion_period
{
=comment
        Returns the period as set by :func:`SetQuaternionPeriod`.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_QUATERNION_PERIOD, [], '', 'L');
}

sub orientation_calculation_on
{
=comment
        Turns the orientation calculation of the IMU Brick on.
        
        As default the calculation is on.
        
        .. versionadded:: 2.0.2~(Firmware)
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    $self->{super}->send_request($self, &FUNCTION_ORIENTATION_CALCULATION_ON, [], '', '');
}

sub orientation_calculation_off
{
=comment
        Turns the orientation calculation of the IMU Brick off.
        
        If the calculation is off, :func:`GetOrientation` will return
        the last calculated value until the calculation is turned on again.
        
        The trigonometric functions that are needed to calculate the orientation 
        are very expensive. We recommend to turn the orientation calculation
        off if the orientation is not needed, to free calculation time for the
        sensor fusion algorithm.
        
        As default the calculation is on.
        
        .. versionadded:: 2.0.2~(Firmware)
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    $self->{super}->send_request($self, &FUNCTION_ORIENTATION_CALCULATION_OFF, [], '', '');
}

sub is_orientation_calculation_on
{
=comment
        Returns *true* if the orientation calculation of the IMU Brick
        is on, *false* otherwise.
        
        .. versionadded:: 2.0.2~(Firmware)
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_IS_ORIENTATION_CALCULATION_ON, [], '', 'C');
}

sub get_protocol1_bricklet_name
{
=comment
        Returns the firmware and protocol version and the name of the Bricklet for a
        given port.
        
        This functions sole purpose is to allow automatic flashing of v1.x.y Bricklet
        plugins.
        
        .. versionadded:: 2.0.0~(Firmware)
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $port) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_PROTOCOL1_BRICKLET_NAME, [$port], 'a', 'C C3 Z40');
 }

sub get_chip_temperature
{
=comment
        Returns the temperature in °C/10 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 an
        accuracy of +-15%. Practically it is only useful as an indicator for
        temperature changes.
        
        .. versionadded:: 1.0.7~(Firmware)
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_CHIP_TEMPERATURE, [], '', 's');
}

sub reset
{
=comment
        Calling this function will reset the Brick. Calling this function
        on a Brick inside of a stack will reset the whole stack.
        
        After a reset you have to create new device objects,
        calling functions on the existing ones will result in
        undefined behavior!
        
        .. versionadded:: 1.0.7~(Firmware)
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    $self->{super}->send_request($self, &FUNCTION_RESET, [], '', '');
}

sub get_identity
{
=comment
        Returns the UID, the UID where the Brick is connected to, 
        the position, the hardware and firmware version as well as the
        device identifier.
        
        The position can be '0'-'8' (stack position).
        
        The device identifier numbers can be found :ref:`here <device_identifier>`.
        |device_identifier_constant|
        
        .. versionadded:: 2.0.0~(Firmware)
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self) = @_;

    return $self->{super}->send_request($self, &FUNCTION_GET_IDENTITY, [], '', 'Z8 Z8 a C3 C3 S');
 }


sub register_callback
{
=comment
        Registers a callback with ID *id* to the function *callback*.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $id, $callback) = @_;

    $self->{super}->{registered_callbacks}->{$id} = '&'.caller.'::'.$callback;
}

sub get_api_version
{
=comment
        Returns the API version (major, minor, revision) of the bindings for
        this device.
=cut
    my ($self) = @_;

    return $self->{super}->{api_version};
}

sub get_response_expected
{
=comment
        Returns the response expected flag for the function specified by the
        *function_id* parameter. It is *true* if the function is expected to
        send a response, *false* otherwise.

        For getter functions this is enabled by default and cannot be disabled,
        because those functions will always send a response. For callback
        configuration functions it is enabled by default too, but can be
        disabled via the set_response_expected function. For setter functions
        it is disabled by default and can be enabled.

        Enabling the response expected flag for a setter function allows to
        detect timeouts and other error conditions calls of this setter as
        well. The device will then send a response for this purpose. If this
        flag is disabled for a setter function then no response is send and
        errors are silently ignored, because they cannot be detected.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $function_id) = @_;

    if(defined($self->{response_expected}->{$function_id}))
    {
        if($self->{response_expected}->{$function_id} == Tinkerforge::Device->RESPONSE_EXPECTED_ALWAYS_TRUE ||
           $self->{response_expected}->{$function_id} == Tinkerforge::Device->RESPONSE_EXPECTED_TRUE)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        croak(Tinkerforge::Error->new(Tinkerforge::IPConnection->ERROR_INVALID_FUNCTION_ID, "Function ID $function_id is unknown"));
    }
}

sub set_response_expected
{
=comment
        Changes the response expected flag of the function specified by the
        *function_id* parameter. This flag can only be changed for setter
        (default value: *false*) and callback configuration functions
        (default value: *true*). For getter functions it is always enabled
        and callbacks it is always disabled.

        Enabling the response expected flag for a setter function allows to
        detect timeouts and other error conditions calls of this setter as
        well. The device will then send a response for this purpose. If this
        flag is disabled for a setter function then no response is send and
        errors are silently ignored, because they cannot be detected.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $function_id, $response_expected) = @_;

    if(defined($self->{response_expected}->{$function_id}))
    {
        if($response_expected)
        {
            $self->{response_expected}->{$function_id} = Tinkerforge::Device->RESPONSE_EXPECTED_TRUE;
        }
        else
        {  
            $self->{response_expected}->{$function_id} = Tinkerforge::Device->RESPONSE_EXPECTED_FALSE;
        }
    }
    else
    {
        croak(Tinkerforge::Error->new(Tinkerforge::IPConnection->ERROR_INVALID_FUNCTION_ID, "Function ID $function_id is unknown"));
    }
}

sub set_response_expected_all
{
=comment
        Changes the response expected flag for all setter and callback
        configuration functions of this device at once.
=cut
    lock($Tinkerforge::Device::DEVICE_LOCK);

    my ($self, $response_expected) = @_;

    foreach my $key (sort keys $self->{response_expected})
    {
        if($response_expected)
        {
            $self->{response_expected}->{$key} = Tinkerforge::Device->RESPONSE_EXPECTED_TRUE;
        }
        else
        {
            $self->{response_expected}->{$key} = Tinkerforge::Device->RESPONSE_EXPECTED_FALSE;
        }
    }
}

1;
