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