
# USB Dongle TEMPer1F
# The Dongle has Vendor ID 0x0C45 and Product ID 0x7401

package Device::USB::TEMPer1F;

our $VERSION = '0.01';

use 5.008008;
use strict;
use warnings;
use Device::USB;

sub new{
    my $class = shift;
    # Configuration for defaults
    my %cfg = (
        vid => 0x0C45, # Vendor ID
        pid => 0x7401, # Product ID
        tim => 500,    # Timeout
        epi => 0x82,   # Endoint in
    @_);

    my $self = bless{ 
        cfg => \%cfg,
        buffer => 0
    }, $class;
    
    # There are two devices!
    return eval{
        my $usb = Device::USB->new;
        my $dev_bulk    = undef;
        my $dev_control = undef;
        foreach my $d( $usb->list_devices ){
            next if $d->idVendor  != $cfg{vid};
            next if $d->idProduct != $cfg{pid};
            if(130 == $d->config->[0]->interfaces->[0][0]->endpoints->[0]->bEndpointAddress){
                $dev_bulk = $d;
            }
            else{
                $dev_control = $d;
            }
        }

        die "Bulk Device not found!\n"    unless $dev_bulk;
        die "Control Device not found!\n" unless $dev_control;

        $dev_bulk->open() or die "Can not open the bulk device\n";
        0 == $dev_bulk->set_configuration(1) ||
            die "Cannot set configuration for bulk device!\n";
        0 == $dev_bulk->claim_interface(1) ||
            die "Cannot claim interface 1!\n";

        $dev_control->open() or die "Can not open the control device\n";
        0 == $dev_control->set_configuration(1) ||
            die "Cannot set configuration for control device!\n";
        0 == $dev_control->claim_interface(0) ||
            die "Cannot claim interface 0!\n";

        $self->{bulk_device}    = $dev_bulk;
        $self->{control_device} = $dev_control;
        $self;
    }
}


# fetch temperature in °C
sub fetch{
    my $self = shift;
    $self->_control();
    $self->{bulk_device}->interrupt_read($self->{cfg}{epi},$self->{buffer},8,$self->{cfg}{tim});

    my $r = [unpack "C8", $self->{buffer}];
    return sprintf "%0.2f", $r->[4] + $r->[5]/256;
}

############################ private methods ##############################
# set up a control message
sub _control{
    my $self = shift;
    my $buffer = pack("C8", 0x1,0x80,0x33,0x1,0x0,0x0,0x0,0x0);
    my $check = $self->{bulk_device}->control_msg(
        0x21,
        0x09,
        0x0200,
        0x01,
        $buffer,
        8,
        $self->{cfg}{tim}
    );
    die "Cannot setup a control_message!\n" if $check != 8;
}

1;#########################################################################
#  my $temper = Device::USB::TEMPer1F->new or die $@;
#  print $temper->fetch; 
__END__

=head1 NAME

Device::USB::TEMPer1F - Perl extension for USB PCSensor TEMPer1F

=head1 SYNOPSIS

  use Device::USB::TEMPer1F;

  my $temper = Device::USB::TEMPer1F->new or die $@;
  print $temper->fetch; 
    # 23.50

=head1 DESCRIPTION



=head2 METHODS

    The API is very easy and has two methods only, as you can see below.
    
=head3 CONSTRUCTOR

  my $temper = Device::USB::TEMPer1F->new 
   or die $@;

  If the device was not found or other errors occurred, new() throws an exception and $@ contains the corresponding message.
  
=head3 FETCH

  The fetch() method returns the temperature in degrees celsius.

=head1 SEE ALSO

  Device::USB
  ppm install http://rolfrost.de/Device-USB.ppd
  ppm install http://rolfrost.de/Device-USB-PX1674.ppd

=head1 AUTHOR

Rolf Rost, E<lt>pilgrim@rolfrost.deE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2017 by Eolf Rost

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.16.3 or,
at your option, any later version of Perl 5 you may have available.


=cut
