]> git.vpit.fr Git - perl/modules/Bit-MorseSignals.git/blob - lib/Bit/MorseSignals/Receiver.pm
Importing Bit-MorseSignals-0.05.tar.gz
[perl/modules/Bit-MorseSignals.git] / lib / Bit / MorseSignals / Receiver.pm
1 package Bit::MorseSignals::Receiver;
2
3 use strict;
4 use warnings;
5
6 use Carp qw/croak/;
7 use Encode qw/decode_utf8/;
8 use Storable qw/thaw/;
9
10 use Bit::MorseSignals qw/:consts/;
11
12 =head1 NAME
13
14 Bit::MorseSignals::Receiver - Base class for Bit::MorseSignals receivers.
15
16 =head1 VERSION
17
18 Version 0.05
19
20 =cut
21
22 our $VERSION = '0.05';
23
24 =head1 SYNOPSIS
25
26     use Bit::MorseSignals::Receiver;
27
28     my $pants = new Bit::MorseSignals::Receiver done => sub { print "received $_[1]!\n" };
29     while (...) {
30      my $bit = comes_from_somewhere_lets_say_signals();
31      $pants->push($bit);
32     }
33
34 =head1 DESCRIPTION
35
36 Base class for L<Bit::MorseSignals> receivers. Please refer to this module for more general information about the protocol.
37
38 Given a sequence of bits coming from the L<Bit::MorseSignals> protocol, the receiver object detects when a packet has been completed and then reconstructs the original message depending of the datatype specified in the header.
39
40 =cut
41
42 sub _check_self {
43  croak 'First argument isn\'t a valid ' . __PACKAGE__ . ' object'
44   unless ref $_[0] and $_[0]->isa(__PACKAGE__);
45 }
46
47 =head1 METHODS
48
49 =head2 C<< new < done => $cb > >>
50
51 L<Bit::MorseSignals::Receiver> object constructor. With the C<'done'> option, you can specify a callback that will be triggered every time a message is completed, and in which C<$_[0]> will be the receiver object and C<$_[1]> the message received.
52
53 =cut
54
55 sub new {
56  my $class = shift;
57  $class = ref $class || $class || return;
58  croak 'Optional arguments must be passed as key => value pairs' if @_ % 2;
59  my %opts = @_;
60  my $self = {
61   msg    => undef,
62   done   => $opts{done},
63  };
64  bless $self, $class;
65  $self->reset;
66  return $self;
67 }
68
69 =head2 C<push $bit>
70
71 Tells the receiver that you have received the bit C<$bit>. Returns true while the message isn't completed, and C<undef> as soon as it is.
72
73 =cut
74
75 sub push {
76  my ($self, $bit) = @_;
77  _check_self($self);
78  if (!defined $bit) {
79   $bit = $_;
80   return unless defined $bit;
81  }
82  $bit = $bit ? 1 : 0;
83
84  if ($self->{state} == 3) { # data
85
86   vec($self->{buf}, $self->{len}, 1) = $bit;
87   ++$self->{len};
88   if ($self->{len} >= $self->{sig_len}) {
89    my $res = 1;
90    for (1 .. $self->{sig_len}) {
91     if (vec($self->{buf}, $self->{len} - $_, 1) != vec($self->{sig}, $_-1, 1)) {
92      $res = 0;
93      last;
94     }
95    }
96    if ($res) {
97     my $base = int $self->{sig_len} / 8 + $self->{sig_len} % 8 != 0;
98     substr $self->{buf}, -$base, $base, '';
99     my @demanglers = (sub { $_[0] }, \&decode_utf8, \&thaw  );
100     #        BM_DATA_{PLAIN,         UTF8,          STORABLE}
101     $self->{msg} = defined $demanglers[$self->{type}]
102                     ? do {
103                        my $msg = eval {
104                         local $SIG{__DIE__} = sub { warn @_ };
105                         $demanglers[$self->{type}]->($self->{buf})
106                        };
107                        $@ ? undef : $msg;
108                       }
109                     : $self->{buf};
110     $self->reset;
111     $self->{done}->($self, $self->{msg}) if $self->{done};
112     return;
113    }
114   }
115
116  } elsif ($self->{state} == 2) { # header
117
118   vec($self->{buf}, $self->{len}++, 1) = $bit;
119   if ($self->{len} >= 3) {
120    my $type = 2 * vec($self->{buf}, 0, 1)
121                 + vec($self->{buf}, 1, 1);
122    $type = BM_DATA_PLAIN if vec($self->{buf}, 2, 1);
123    @{$self}{qw/state type buf len/} = (3, $type, '', 0);
124   }
125
126  } elsif ($self->{state} == 1) { # end of signature
127
128   if ($self->{sig_bit} != $bit) {
129    $self->{state} = 2;
130   }
131   vec($self->{sig}, $self->{sig_len}++, 1) = $bit;
132
133  } else { # first bit
134
135   @{$self}{qw/state sig sig_bit sig_len buf len/}
136            = (1,    '', $bit,   1,      '', 0  );
137   vec($self->{sig}, 0, 1) = $bit;
138
139  }
140
141  return $self;
142 }
143
144 =head2 C<reset>
145
146 Resets the current receiver state, obliterating any current message being received.
147
148 =cut
149
150 sub reset {
151  my ($self) = @_;
152  _check_self($self);
153  $self->{state} = 0;
154  @{$self}{qw/sig sig_bit sig_len type buf len/} = ();
155  return $self;
156 }
157
158 =head2 C<busy>
159
160 True when the receiver is in the middle of assembling a message.
161
162 =cut
163
164 sub busy {
165  my ($self) = @_;
166  _check_self($self);
167  return $self->{state} > 0;
168 }
169
170 =head2 C<msg>
171
172 The last message completed, or C<undef> when no message has been assembled yet.
173
174 =cut
175
176 sub msg {
177  my ($self) = @_;
178  _check_self($self);
179  return $self->{msg};
180 }
181
182 =head1 EXPORT
183
184 An object module shouldn't export any function, and so does this one.
185
186 =head1 DEPENDENCIES
187
188 L<Carp> (standard since perl 5), L<Encode> (since perl 5.007003), L<Storable> (idem).
189
190 =head1 SEE ALSO
191
192 L<Bit::MorseSignals>, L<Bit::MorseSignals::Emitter>.
193
194 =head1 AUTHOR
195
196 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
197
198 You can contact me by mail or on #perl @ FreeNode (vincent or Prof_Vince).
199
200 =head1 BUGS
201
202 Please report any bugs or feature requests to C<bug-bit-morsesignals-receiver at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Bit-MorseSignals>.  I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
203
204 =head1 SUPPORT
205
206 You can find documentation for this module with the perldoc command.
207
208     perldoc Bit::MorseSignals::Receiver
209
210 =head1 COPYRIGHT & LICENSE
211
212 Copyright 2008 Vincent Pit, all rights reserved.
213
214 This program is free software; you can redistribute it and/or modify it
215 under the same terms as Perl itself.
216
217 =cut
218
219 1; # End of Bit::MorseSignals::Receiver