Geo-FIT

 view release on metacpan or  search on metacpan

lib/Geo/FIT.pm  view on Meta::CPAN

sub FIT_UINT8Z() {10;}
sub FIT_UINT16Z() {11;}
sub FIT_UINT32Z() {12;}
sub FIT_BYTE() {13;}
sub FIT_SINT64() {14;}
sub FIT_UINT64() {15;}
sub FIT_UINT64Z() {16;}
sub FIT_BASE_TYPE_MAX() {FIT_UINT64Z;}

my ($rechd_offset_compressed_timestamp_header, $rechd_mask_compressed_timestamp_header,
    $rechd_offset_cth_local_message_type, $rechd_length_cth_local_message_type,
    $rechd_mask_cth_local_message_type, $rechd_length_cth_timestamp, $rechd_mask_cth_timestamp,
    $rechd_offset_definition_message, $rechd_mask_definition_message, $rechd_offset_devdata_message,
    $rechd_mask_devdata_message, $rechd_length_local_message_type, $rechd_mask_local_message_type,
    $cthd_offset_local_message_type, $cthd_length_local_message_type, $cthd_mask_local_message_type,
    $cthd_length_time_offset, $cthd_mask_time_offset
    );

$rechd_offset_compressed_timestamp_header =  7;
$rechd_mask_compressed_timestamp_header   =  1 << $rechd_offset_compressed_timestamp_header;
$rechd_offset_cth_local_message_type      =  5;
$rechd_length_cth_local_message_type      =  2;
$rechd_mask_cth_local_message_type        =  ((1 << $rechd_length_cth_local_message_type) - 1) << $rechd_offset_cth_local_message_type;
$rechd_length_cth_timestamp               =  $rechd_offset_cth_local_message_type;
$rechd_mask_cth_timestamp                 =  (1 << $rechd_length_cth_timestamp) - 1;
$rechd_offset_definition_message          =  6;
$rechd_mask_definition_message            =  1 << $rechd_offset_definition_message;
$rechd_offset_devdata_message             =  5;
$rechd_mask_devdata_message               =  1 << $rechd_offset_devdata_message;
$rechd_length_local_message_type          =  4;
$rechd_mask_local_message_type            =  (1 << $rechd_length_local_message_type) - 1;
$cthd_offset_local_message_type           =  5;
$cthd_length_local_message_type           =  2;
$cthd_mask_local_message_type             =  (1 << $cthd_length_local_message_type) - 1;
$cthd_length_time_offset                  =  5;
$cthd_mask_time_offset                    =  (1 << $cthd_length_time_offset) - 1;

my ($defmsg_min_template, $defmsg_min_length);
$defmsg_min_template  =  'C C C S C';
$defmsg_min_length    =  length(pack($defmsg_min_template));

my ($deffld_template, $deffld_length, $deffld_mask_endian_p, $deffld_mask_type);
$deffld_template       =  'C C C';
$deffld_length         =  length(pack($deffld_template));
$deffld_mask_endian_p  =  1 << 7;
$deffld_mask_type      =  (1 << 5) - 1;

my ($devdata_min_template, $devdata_min_length, $devdata_deffld_template, $devdata_deffld_length);
$devdata_min_template    = 'C';
$devdata_min_length      = length(pack($devdata_min_template));
$devdata_deffld_template = 'C C C';
$devdata_deffld_length   = length(pack($deffld_template));

my @invalid = (0xFF) x ($deffld_mask_type + 1);
$invalid[FIT_SINT8] = 0x7F;
$invalid[FIT_SINT16] = 0x7FFF;
$invalid[FIT_UINT16] = 0xFFFF;
$invalid[FIT_SINT32] = 0x7FFFFFFF;
$invalid[FIT_UINT32] = 0xFFFFFFFF;
$invalid[FIT_STRING] = $invalid[FIT_UINT8Z] = $invalid[FIT_UINT16Z] = $invalid[FIT_UINT32Z] = $invalid[FIT_UINT64Z] = 0;
#$invalid[FIT_FLOAT32] = NaN;
#$invalid[FIT_FLOAT64] = NaN;
$invalid[FIT_FLOAT32] = unpack('f', pack('V', 0xFFFFFFFF));
$invalid[FIT_FLOAT64] = unpack('d', pack('V V', 0xFFFFFFFF, 0xFFFFFFFF));

my ($big_int_base32, $sint64_2c_mask, $sint64_2c_base, $sint64_2c_sign);

if (defined $uint64_invalid) {
    $invalid[FIT_UINT64] = $uint64_invalid;
    $invalid[FIT_SINT64] = eval '0x7FFFFFFFFFFFFFFF';
} else {
    $invalid[FIT_UINT64] = Math::BigInt->new('0xFFFFFFFFFFFFFFFF');
    $invalid[FIT_SINT64] = Math::BigInt->new('0x7FFFFFFFFFFFFFFF');
    $big_int_base32 = Math::BigInt->new('0x100000000');
    $sint64_2c_mask = Math::BigInt->new('0xFFFFFFFFFFFFFFFF');
    $sint64_2c_base = Math::BigInt->new('0x10000000000000000');
    $sint64_2c_sign = Math::BigInt->new('0x1000000000000000');
}

sub packfilter_uint64_big_endian {
    my @res = $_[0]->bdiv($big_int_base32);
    @res;
}

sub packfilter_uint64_little_endian {
    my @res = $_[0]->bdiv($big_int_base32);
    @res[1, 0];
}

my $my_endian = unpack('L', pack('N', 1)) == 1 ? 1 : 0;

*packfilter_uint64 = $my_endian ? \&packfilter_uint64_big_endian : \&packfilter_uint64_little_endian;

sub unpackfilter_uint64_big_endian {
    my ($hi, $lo) = @_;
    Math::BigInt->new($hi)->blsft(32)->badd($lo);
}

sub unpackfilter_uint64_little_endian {
    &unpackfilter_uint64_big_endian(@_[1, 0]);
}

*unpackfilter_uint64 = $my_endian ? \&unpackfilter_uint64_big_endian : \&unpackfilter_uint64_little_endian;

sub packfilter_sint64_big_endian {
    if ($_[0]->bcmp(0) < 0) {
        &packfilter_uint64_big_endian($sint64_2c_mask->band($sint64_2c_base->badd($_[0])));
    } else {
        &packfilter_uint64_big_endian($_[0]);
    }
}

sub packfilter_sint64_little_endian {
    if ($_[0]->bcmp(0) < 0) {
        &packfilter_uint64_little_endian($sint64_2c_mask->band($sint64_2c_base->badd($_[0])));
    } else {
        &packfilter_uint64_little_endian($_[0]);
    }
}

*packfilter_sint64 = $my_endian ? \&packfilter_sint64_big_endian : \&packfilter_sint64_little_endian;

lib/Geo/FIT.pm  view on Meta::CPAN


            if ($packfactor[$type] > 1) {
                push @pi, $type, $i_array_t, $c, $i_array;
                $c *= $packfactor[$type];
            }

            $desc{template} .= $c if $c > 1;
            $i_array_t += $c;
        }

        $desc{devdata_nfields} = $nfields;
        $self->error(join(' / ', @emsg)) if (@emsg);
    }

    $desc{endian_converter} = \@cvt if @cvt;
    $desc{packfilter_index} = \@pi if @pi;
    $desc{message_length} = $i_string;
    $desc{array_length} = $i_array;
    $self->offset($e);
    return 1
}

sub endian_convert {
    my ($self, $cvt, $buffer, $i) = @_;
    my $j;

    for ($j = 4 ; $j < @$cvt ; $j += 5) {
        my ($b, $size, $c) = @$cvt[$j - 2, $j - 1, $j];

        for ($b += $i ; $c > 0 ; $b += $size, --$c) {
            my @v = unpack($cvt->[$j - 3], substr($$buffer, $b, $size));
            my ($k, $l);

            for ($k = 0, $l = $#v ; $k < $l ; ++$k, --$l) {
                @v[$k, $l] = @v[$l, $k];
            }
            substr($$buffer, $b, $size) = pack($cvt->[$j - 4], @v);
        }
    }
}

sub last_timestamp {
    my $self = shift;
    if (@_) {
        $self->{last_timestamp} = $_[0];
    } else {
        $self->{last_timestamp};
    }
}

sub fetch_data_message {
    my ($self, $desc) = @_;
    my $buffer = $self->buffer;

    if ( $self->_buffer_needs_updating( $desc->{message_length} ) ) {
        $self->fill_buffer or return undef
    }
    $self->endian_convert($desc->{endian_converter}, $self->buffer, $self->offset) if ref $desc->{endian_converter} eq 'ARRAY';

    my $i = $self->offset;
    # unpack('f'/'d', ...) unpacks to NaN
    my @v = unpack($desc->{template}, substr($$buffer, $i, $desc->{message_length}));

    if (ref $desc->{packfilter_index} eq 'ARRAY') {
        my $piv = $desc->{packfilter_index};
        my ($i, $j);
        my @v_t = @v;

        @v = ($v_t[0]);

        for ($i = 1, $j = 3 ; $j < @$piv ; $j += 4) {
            my ($type, $i_array_t, $c, $i_array) = @$piv[($j - 3) .. $j];
            my $delta = $packfactor[$type];

            $i < $i_array_t and push @v, @v_t[$i .. ($i_array_t - 1)];
            $i = $i_array_t + $c * $delta;

            for (; $i_array_t < $i ; $i_array_t += $delta) {
                push @v, $unpackfilter[$type]->(@v_t[$i_array_t .. ($i_array_t + $delta - 1)]);
            }
        }
    }

    $self->offset($i + $desc->{message_length});

    my $cb = $desc->{callback};

    my $ret_val;
    if (ref $cb eq 'ARRAY') {
        $v[0] & $rechd_mask_compressed_timestamp_header and push @v, $self->last_timestamp + ($v[0] & $rechd_mask_cth_timestamp);
        $ret_val = $cb->[0]->($self, $desc, \@v, @$cb[1 .. $#$cb]);
    } else {
        $ret_val = 1;
    }
    return $ret_val
}

sub pack_data_message {
    my ($self, $desc, $v) = @_;
    my $drop_devdata = $self->drop_developer_data;

    if ($drop_devdata && ($desc->{message_name} eq 'developer_data_id' || $desc->{message_name} eq 'field_description')) {
        '';
    } else {
        my $rv = $v;

        if (ref $desc->{packfilter_index} eq 'ARRAY') {
            my @v = ($v->[0]);
            my $piv = $desc->{packfilter_index};
            my ($i, $j);

            for ($i = 1, $j = 3 ; $j < @$piv ; $j += 4) {
                my ($type, $i_array_t, $c, $i_array) = @$piv[($j - 3) .. $j];

                $i < $i_array and push @v, @$v[$i .. ($i_array - 1)];
                $i = $i_array + $c;

                for (; $i_array < $i ; ++$i_array) {
                    push @v, $packfilter[$type]->($v->[$i_array]);
                }
            }



( run in 2.607 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )