File Coverage

blib/lib/Bit/MorseSignals/Emitter.pm
Criterion Covered Total %
statement 118 118 100.0
branch 40 40 100.0
condition 9 9 100.0
subroutine 18 18 100.0
pod 9 9 100.0
total 194 194 100.0


line stmt bran cond sub pod time code
1             package Bit::MorseSignals::Emitter;
2              
3 8     8   117594 use strict;
  8         22  
  8         304  
4 8     8   46 use warnings;
  8         15  
  8         316  
5              
6 8     8   47 use Carp qw;
  8         16  
  8         545  
7 8     8   18756 use Encode qw;
  8         105083  
  8         812  
8 8     8   11318 use Storable qw;
  8         31309  
  8         742  
9              
10 8     8   3723 use Bit::MorseSignals qw<:consts>;
  8         34  
  8         12037  
11              
12             =head1 NAME
13              
14             Bit::MorseSignals::Emitter - Base class for Bit::MorseSignals emitters.
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::Emitter;
27              
28             my $deuce = Bit::MorseSignals::Emitter->new;
29             $deuce->post("hlagh") for 1 .. 3;
30             while (defined(my $bit = $deuce->pop)) {
31             sends_by_some_mean_lets_say_signals($bit);
32             }
33              
34             =head1 DESCRIPTION
35              
36             Base class for L emitters. Please refer to this module for more general information about the protocol.
37              
38             The emitter object enqueues messages and prepares them one by one into L packets. It gives then back the bits of the packet in the order they should be sent.
39              
40             =cut
41              
42             sub _check_self {
43 6264 100 100 6264   37910 croak 'First argument isn\'t a valid ' . __PACKAGE__ . ' object'
44             unless ref $_[0] and $_[0]->isa(__PACKAGE__);
45             }
46              
47             sub _count_bits {
48 60     60   160 my ($len, $cur, $seq, $lng) = @_[1 .. 4];
49 60         175 for (my $i = 0; $i < $len; ++$i) {
50 5250         5777 my $bit = vec $_[0], $i, 1;
51 5250 100       7663 if ($cur == $bit) {
52 3167         6229 ++$seq;
53             } else {
54 2083 100       3691 $lng->[$cur] = $seq if $seq > $lng->[$cur];
55 2083         2182 $seq = 1;
56 2083         4628 $cur = $bit;
57             }
58             }
59 60 100       163 $lng->[$cur] = $seq if $seq > $lng->[$cur];
60 60         190 return $cur, $seq;
61             }
62              
63             =head1 METHODS
64              
65             =head2 C
66              
67             L object constructor. Currently does not take any optional argument.
68              
69             =cut
70              
71             sub new {
72 9     9 1 2240 my $class = shift;
73 9 100 100     78 return unless $class = ref $class || $class;
74 8 100       212 croak 'Optional arguments must be passed as key => value pairs' if @_ % 2;
75 7         63 my %opts = @_;
76 7         30 my $self = {
77             queue => [],
78             };
79 7         25 bless $self, $class;
80 7         34 $self->reset;
81 7         23 return $self;
82             }
83              
84             =head2 C<< post $msg, < type => $type > >>
85              
86             Adds C<$msg> to the message queue and, if no other message is currently processed, dequeue the oldest item and prepare it. The type is automatically chosen, but you may want to try to force it with the C option : C<$type> is then one of the C constants listed in L
87              
88             =cut
89              
90             sub post {
91 99     99 1 2563 my $self = shift;
92 99         163 my $msg = shift;
93 99         176 _check_self($self);
94 97 100       401 croak 'Optional arguments must be passed as key => value pairs' if @_ % 2;
95 96         177 my %opts = @_;
96              
97 96         149 my $type = $opts{type};
98              
99 96 100       312 if (defined $msg) {
    100          
100              
101 54     36   266 my @manglers = (sub { $_[0] }, \&encode_utf8, \&freeze);
  36         60  
102             # BM_DATA_{PLAIN, UTF8, STORABLE}
103 54 100 100     199 $type = BM_DATA_AUTO unless defined $type and exists $manglers[$type];
104 54 100       161 if (ref $msg) {
    100          
105 10 100       16 return if { map { $_ => 1 } qw }->{ref $msg};
  20         86  
106 8         18 $type = BM_DATA_STORABLE;
107             } elsif ($type == BM_DATA_AUTO) {
108 43 100       163 $type = is_utf8($msg) ? BM_DATA_UTF8 : BM_DATA_PLAIN;
109             }
110 52         129 $msg = $manglers[$type]->($msg);
111              
112 52 100       618 if ($self->{state}) { # Busy/queued, can't handle this message right now.
113 43         61 push @{$self->{queue}}, [ $msg, $type ];
  43         132  
114 43 100       316 return -1 if $self->{state} == 2; # Currently sending
115 1         2 ($msg, $type) = @{shift @{$self->{queue}}}; # Otherwise something's queued
  1         1  
  1         9  
116             }
117              
118             } elsif ($self->{state} == 1) { # No msg was given, but the queue isn't empty.
119              
120 20         90 ($msg, $type) = @{shift @{$self->{queue}}};
  20         28  
  20         139  
121              
122             } else { # Either unused or busy sending.
123              
124 22         106 return;
125              
126             }
127              
128 30         93 $self->{state} = 2;
129              
130 30         55 my $head = '';
131 30         119 vec($head, 0, 1) = ($type & 1);
132 30         116 vec($head, 1, 1) = ($type & 2) >> 1;
133 30         73 vec($head, 2, 1) = 0;
134 30         62 my $hlen = 3;
135              
136 30         79 my $len = 8 * length $msg;
137 30         71 my @lng = (0, 0, 0);
138 30         120 my ($cur, $seq) = _count_bits $head, $hlen, 2, 0, \@lng;
139 30         99 ($cur, $seq) = _count_bits $msg, $len, $cur, $seq, \@lng;
140 30 100       120 ($cur, $seq) = ($lng[0] > $lng[1]) ? (1, $lng[1])
141             : (0, $lng[0]); # Take the smallest.
142 30         50 ++$seq;
143              
144 30         93 $self->{len} = 1 + $seq + $hlen + $len + $seq + 1;
145 30         59 $self->{buf} = '';
146 30         57 my ($i, $j, $k) = (0, 0, 0);
147 30         379 vec($self->{buf}, $i++, 1) = $cur for 1 .. $seq;
148 30         97 vec($self->{buf}, $i++, 1) = 1 - $cur;
149 30         242 vec($self->{buf}, $i++, 1) = vec($head, $j++, 1) for 1 .. $hlen;
150 30         5838 vec($self->{buf}, $i++, 1) = vec($msg, $k++, 1) for 1 .. $len;
151 30         101 vec($self->{buf}, $i++, 1) = 1 - $cur;
152 30         310 vec($self->{buf}, $i++, 1) = $cur for 1 .. $seq;
153              
154 30         63 $self->{pos} = 0;
155              
156 30         125 return 1;
157             }
158              
159             =head2 C
160              
161             If a message is being processed, pops the next bit in the packet. When the message is over, the next in the queue is immediatly prepared and the first bit of the new packet is given back. If the queue is empty, C is returned. You may want to use this method with the idiom :
162              
163             while (defined(my $bit = $deuce->pop)) {
164             ...
165             }
166              
167             =cut
168              
169             sub pop {
170 5672     5672 1 57321 my ($self) = @_;
171 5672         8675 _check_self($self);
172 5670 100       12202 return if $self->{state} == 0;
173 5662 100       10792 $self->post if $self->{state} == 1;
174 5662         9701 my $bit = vec $self->{buf}, $self->{pos}++, 1;
175 5662 100       11281 $self->reset if $self->{pos} >= $self->{len};
176 5662         12794 return $bit;
177             }
178              
179             =head2 C
180              
181             The length of the currently posted message.
182              
183             =cut
184              
185             sub len {
186 68     68 1 11593 my ($self) = @_;
187 68         126 _check_self($self);
188 66         311 return $self->{len};
189             }
190              
191             =head2 C
192              
193             The number of bits that have already been sent for the current message.
194              
195             =cut
196              
197             sub pos {
198 68     68 1 1076 my ($self) = @_;
199 68         147 _check_self($self);
200 66         202 return $self->{pos};
201             }
202              
203             =head2 C
204              
205             Cancels the current transfer, but does not empty the queue.
206              
207             =cut
208              
209             sub reset {
210 39     39 1 1048 my ($self) = @_;
211 39         94 _check_self($self);
212 37         54 $self->{state} = @{$self->{queue}} > 0;
  37         154  
213 37         85 @{$self}{qw} = ();
  37         101  
214 37         82 return $self;
215             }
216              
217             =head2 C
218              
219             Flushes the queue, but does not cancel the current transfer.
220              
221             =cut
222              
223             sub flush {
224 24     24 1 1006 my ($self) = @_;
225 24         48 _check_self($self);
226 22         46 $self->{queue} = [];
227 22         56 return $self;
228             }
229              
230             =head2 C
231              
232             True when the emitter is busy, i.e. when a packet is being chunked.
233              
234             =cut
235              
236             sub busy {
237 259     259 1 8430 my ($self) = @_;
238 259         470 _check_self($self);
239 257         1203 return $self->{state} >= 2;
240             }
241              
242             =head2 C
243              
244             Returns the number of queued items.
245              
246             =cut
247              
248             sub queued {
249 35     35 1 1031 my ($self) = @_;
250 35         65 _check_self($self);
251 33         40 return @{$self->{queue}};
  33         162  
252             }
253              
254             =head1 EXPORT
255              
256             An object module shouldn't export any function, and so does this one.
257              
258             =head1 DEPENDENCIES
259              
260             L (standard since perl 5), L (since perl 5.007003), L (idem).
261              
262             =head1 SEE ALSO
263              
264             L, L.
265              
266             =head1 AUTHOR
267              
268             Vincent Pit, C<< >>, L.
269              
270             You can contact me by mail or on C (vincent).
271              
272             =head1 BUGS
273              
274             Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
275              
276             =head1 SUPPORT
277              
278             You can find documentation for this module with the perldoc command.
279              
280             perldoc Bit::MorseSignals::Emitter
281              
282             Tests code coverage report is available at L.
283              
284             =head1 COPYRIGHT & LICENSE
285              
286             Copyright 2008 Vincent Pit, all rights reserved.
287              
288             This program is free software; you can redistribute it and/or modify it
289             under the same terms as Perl itself.
290              
291             =cut
292              
293             1; # End of Bit::MorseSignals::Emitter