File: HiPi.pm

package info (click to toggle)
libhipi-perl 0.93-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 20,048 kB
  • sloc: perl: 471,917; ansic: 22; makefile: 10
file content (221 lines) | stat: -rw-r--r-- 5,951 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
###############################################################################
# Distribution : HiPi Modules for Raspberry Pi
# File         : lib/HiPi.pm
# Description  : Pepi module for Raspberry Pi
# Copyright    : Copyright (c) 2013-2025 Mark Dootson
# License      : This is free software; you can redistribute it and/or modify it under
#                the same terms as the Perl 5 programming language system itself.
#########################################################################################

package HiPi;

###############################################################################
use strict;
use warnings;
use parent qw( Exporter );
use HiPi::Constant qw( :hipi );
use HiPi::RaspberryPi;
use constant hipi_export_constants();
use Scalar::Util qw( weaken isweak refaddr );
use Carp;

our $VERSION ='0.93';

our @EXPORT_OK = hipi_export_ok();
our %EXPORT_TAGS = hipi_export_tags();

my $registered_exits = {};
my $signal_handlers_installed = 0;

our $interrupt_verbose = 0;

sub is_raspberry_pi { return HiPi::RaspberryPi::is_raspberry() ; }

sub alt_func_version { return HiPi::RaspberryPi::alt_func_version() ; }

sub _install_signal_handlers {
    $SIG{INT}  = \&_call_registered_and_exit;
    $SIG{TERM} = \&_call_registered_and_exit;
    $SIG{HUP}  = \&_call_registered_and_exit;
    $signal_handlers_installed = 1;
}

sub catch_sigpipe {
    $SIG{PIPE} = \&_call_registered_and_exit;
}

sub twos_compliment {
    my( $class, $value, $numbytes) = @_;
    my $onescomp = (~$value) & ( 2**(8 * $numbytes) -1 );
    return $onescomp + 1;
}

sub bytes_to_integer {
    my($class, $bytes, $is_signed, $l_endian) = @_;
    my $packformat = $class->get_integer_pack_format( scalar @$bytes, $is_signed, $l_endian );
    my $int = unpack($packformat, pack('C*', @$bytes) );
    return $int;
}

sub integer_to_bytes {
    my($class, $length, $value, $is_signed, $l_endian) = @_;
    my $packformat = $class->get_integer_pack_format( $length, $is_signed, $l_endian );
    my @bytes = unpack('C*', pack( $packformat, $value ) );
    return ( wantarray ) ? @bytes : \@bytes;
}

sub integer_to_bytes_calc_length {
    my($class, $value, $is_signed, $l_endian) = @_;
    my $length = $class->get_integer_value_byte_length($value, $is_signed);
    my $packformat = $class->get_integer_pack_format( $length, $is_signed, $l_endian );
    my @bytes = unpack('C*', pack( $packformat, $value ) );
    return ( wantarray ) ? @bytes : \@bytes;
}

sub get_integer_pack_format {
    my($class, $length, $is_signed, $l_endian) = @_;
    my $packformat;
    
    if ( $length == 1 ) {
        $packformat = 'C';
    } elsif( $length == 2 ) {
        $packformat = ( $l_endian ) ? 'S<' : 'S>';
    } elsif( $length == 4 ) {
        $packformat = ( $l_endian ) ? 'L<' : 'L>';
    } else {
        $packformat = 'Q>';
        $packformat = ( $l_endian ) ? 'Q<' : 'Q>';
    }
    
    $packformat = lc($packformat) if $is_signed;
    
    return $packformat;
}

sub get_integer_value_byte_length {
    my( $class, $value, $signed ) = @_;
    
    my $absvalue = abs($value);
    
    my $limit = ( $signed ) ? 0x7fffffff : 0xffffffff;
    
    # negative integers can have an absolute
    # value 1 greater than positive integers
    # within a given byte length
    if ( $signed && $value < 0 ) {
        $absvalue --;
    }    
    
    if( $absvalue      > $limit ) {
        # anything requiring 5 bytes or more
        # treat as 64 bit 8 byte thing and
        # assume architecture at both ends
        # supports it
        return 8;
    } elsif( $absvalue > ( $limit >> 16 ) ) {
        return 4;
    } elsif( $absvalue > ( $limit >> 24 ) ) {
        return 2;
    } else {
        return 1;
    }
}

sub register_exit_method {
    my($class, $obj, $method) = @_;
    
    my $tid = 0;
    if( $HiPi::Threads::threads ) {
        $tid = threads->tid();
    }
    
    if( !$tid && !$signal_handlers_installed ) {
        _install_signal_handlers();
    }
    
    my $key = refaddr( $obj );
    $registered_exits->{$key} = [ $obj, $method ];
    weaken( $registered_exits->{$key}->[0] );
}

sub unregister_exit_method {
    my($class, $obj) = @_;
    my $key = refaddr( $obj );
    delete($registered_exits->{$key}) if exists($registered_exits->{$key});
}

sub _call_registered_and_exit {
    my $interrupt = shift;
    my $tid = 0;
    if( $HiPi::Threads::threads ) {
        $tid = threads->tid();
        HiPi::Threads->signal_handler( $interrupt ) unless( $tid ); # only call in main thread
    }
    
    for my $key ( keys %$registered_exits ) {
        my $method = $registered_exits->{$key}->[1];
        if( isweak( $registered_exits->{$key}->[0] ) && $registered_exits->{$key}->[0]->can($method) ) {
            $registered_exits->{$key}->[0]->$method();
        }
    }
    unless( $tid ) {
        # only in main thread
        if($interrupt_verbose) {
            Carp::confess(qq(\nInterrupt SIG$interrupt));
        } else {
            die qq(\nInterrupt SIG$interrupt);
        }
    }
}

sub call_registered_exit_method {
    my($class, $instance) = @_;
    my $key = refaddr( $instance );
    if(exists($registered_exits->{$key})) {
        my $method = $registered_exits->{$key}->[1];
        if( isweak( $registered_exits->{$key}->[0] ) && $registered_exits->{$key}->[0]->can($method) ) {
            $registered_exits->{$key}->[0]->$method();
        }
    }
}

1;

=pod

=encoding UTF-8

=head1 NAME

HiPi - Modules for Raspberry Pi GPIO

=head1 SYNOPSIS

    use HiPi;
    ....
    use HiPi qw( :rpi :i2c :spi :mcp3adc :mcp4dac :mpl3115a2 );
    ....
    use HiPi qw( :mcp23x17 :lcd :hrf69 :openthings :energenie );

=head1 DESCRIPTION

HiPi provides modules for use with the Raspberry Pi GPIO and
peripherals.

Documentation and details are available at

L<https://www.hipiperl.com>

=head1 AUTHOR

Mark Dootson, C<< mdootson@cpan.org >>.

=head1 COPYRIGHT

Copyright (c) 2013 - 2024 Mark Dootson

=cut

__END__