File Coverage

lib/Net/EGTS/SubRecord/Teledata/PosData.pm
Criterion Covered Total %
statement 21 21 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 28 28 100.0


line stmt bran cond sub pod time code
1 4     4   53708 use utf8;
  4         12  
  4         19  
2              
3             package Net::EGTS::SubRecord::Teledata::PosData;
4 4     4   1408 use Mouse;
  4         21087  
  4         1101  
5             extends qw(Net::EGTS::SubRecord);
6              
7 4     4   1136 use Carp;
  4         5  
  4         226  
8              
9 4     4   345 use Net::EGTS::Util qw(usize time2new str2time lat2mod lon2mod dumper_bitstring);
  4         6  
  4         191  
10 4     4   298 use Net::EGTS::Codes;
  4         110  
  4         2880  
11              
12             =head1 NAME
13              
14             Net::EGTS::SubRecord::Teledata::PosData - subrecord containing telemetry data.
15              
16             =head1 SEE ALSO
17              
18             L
19              
20             =cut
21              
22             # Navigation Time
23             has NTM => is => 'rw', isa => 'UINT', default => sub{ time2new };
24             # Latitude
25             has LAT => is => 'rw', isa => 'UINT';
26             # Longitude
27             has LONG => is => 'rw', isa => 'UINT';
28              
29             # Flags:
30             # altitude exists
31             has ALTE => is => 'rw', isa => 'BIT1', default => 0;
32             # east/west
33             has LOHS => is => 'rw', isa => 'BIT1';
34             # south/nord
35             has LAHS => is => 'rw', isa => 'BIT1';
36             # move
37             has MV =>
38             is => 'rw',
39             isa => 'BIT1',
40             lazy => 1,
41             builder => sub { $_[0]->SPD_LO || $_[0]->SPD_HI ? 0x1 : 0x0 },
42             ;
43             # from storage
44             has BB => is => 'rw', isa => 'BIT1', default => 0;
45             # coordinate system
46             has CS => is => 'rw', isa => 'BIT1', default => 0;
47             # 2d/3d
48             has FIX => is => 'rw', isa => 'BIT1', default => 1;
49             # valid
50             has VLD => is => 'rw', isa => 'BIT1', default => 1;
51              
52             # Speed (lower bits)
53             has SPD_LO => is => 'rw', isa => 'BYTE', default => 0;
54             # Direction the Highest bit
55             has DIRH => is => 'rw', isa => 'BIT1', default => 0;
56             # Altitude Sign
57             has ALTS => is => 'rw', isa => 'BIT1', default => 0;
58             # Speed (highest bits)
59             has SPD_HI => is => 'rw', isa => 'BIT6', default => 0;
60              
61             # Direction
62             has DIR => is => 'rw', isa => 'BYTE', default => 0;
63             # Odometer
64             has ODM => is => 'rw', isa => 'BINARY3', default => 0x000;
65             # Digital Inputs
66             has DIN => is => 'rw', isa => 'BIT8', default => 0b00000000;
67             # Source
68             has SRC => is => 'rw', isa => 'BYTE', default => EGTS_SRCD_TIMER;
69              
70             # Optional:
71             # Altitude
72             has ALT => is => 'rw', isa => 'Maybe[BINARY3]';
73             # Source Data
74             has SRCD => is => 'rw', isa => 'Maybe[SHORT]';
75              
76             after 'decode' => sub {
77             my ($self) = @_;
78             die 'SubRecord not EGTS_SR_POS_DATA type'
79             unless $self->SRT == EGTS_SR_POS_DATA;
80              
81             my $bin = $self->SRD;
82             $self->NTM( $self->nip(\$bin => 'L') );
83             $self->LAT( $self->nip(\$bin => 'L') );
84             $self->LONG($self->nip(\$bin => 'L') );
85              
86             my $flags = $self->nip(\$bin => 'C');
87             $self->ALTE( ($flags & 0b10000000) >> 7 );
88             $self->LOHS( ($flags & 0b01000000) >> 6 );
89             $self->LAHS( ($flags & 0b00100000) >> 5 );
90             $self->MV( ($flags & 0b00010000) >> 4 );
91             $self->BB( ($flags & 0b00001000) >> 3 );
92             $self->CS( ($flags & 0b00000100) >> 2 );
93             $self->FIX( ($flags & 0b00000010) >> 1 );
94             $self->VLD( ($flags & 0b00000001) );
95              
96             $self->SPD_LO( $self->nip(\$bin => 'C') );
97              
98             my $stupid = $self->nip(\$bin => 'C');
99             $self->DIRH( ($stupid & 0b10000000) >> 7 );
100             $self->ALTS( ($stupid & 0b01000000) >> 6 );
101             $self->SPD_HI($stupid & 0b00111111 );
102              
103             $self->DIR( $self->nip(\$bin => 'C') );
104             $self->ODM( $self->nip(\$bin => 'a3') );
105             $self->DIN( $self->nip(\$bin => 'C') );
106             $self->SRC( $self->nip(\$bin => 'C') );
107              
108             $self->ALT( $self->nip(\$bin => 'a3') ) if $self->ALTE;
109             $self->SRCD($self->nip(\$bin => 'S' => length($bin)) );
110             };
111              
112              
113             before 'encode' => sub {
114             my ($self) = @_;
115 4     4   25 use bytes;
  4         10  
  4         26  
116              
117             die 'SubRecord not EGTS_SR_POS_DATA type'
118             unless $self->SRT == EGTS_SR_POS_DATA;
119              
120             # Pack stupid bits economy
121             my $stupid = $self->SPD_HI;
122             $stupid = ($stupid | 0b10000000) if $self->DIRH;
123             $stupid = ($stupid | 0b01000000) if $self->ALTS;
124              
125             my $bin = '';
126             $bin .= pack 'L' => $self->NTM;
127             $bin .= pack 'L' => $self->LAT;
128             $bin .= pack 'L' => $self->LONG;
129             $bin .= pack 'B8' => sprintf(
130             '%b%b%b%b%b%b%b%b',
131             $self->ALTE, $self->LOHS, $self->LAHS, $self->MV,
132             $self->BB, $self->CS, $self->FIX, $self->VLD
133             );
134             $bin .= pack 'C' => $self->SPD_LO;
135             $bin .= pack 'C' => $stupid;
136             $bin .= pack 'C' => $self->DIR;
137             $bin .= pack 'a3' => substr(pack("L", $self->ODM), 0, 3);
138             $bin .= pack 'B8' => $self->DIN;
139             $bin .= pack 'C' => $self->SRC;
140             $bin .= pack 'a3' => substr(pack("L", $self->ALT), 0, 3)
141             if $self->ALTE;
142             $bin .= pack 'S' => $self->SRCD
143             if defined $self->SRCD;
144              
145             $self->SRD( $bin );
146             };
147              
148             around BUILDARGS => sub {
149             my $orig = shift;
150             my $class = shift;
151              
152             # simple scalar decoding support
153             my $bin = @_ % 2 ? shift : undef;
154             my %opts = @_;
155              
156             # Simple helpers for real data:
157             if( defined( my $time = delete $opts{time} ) ) {
158             $opts{NTM} = time2new str2time $time;
159             }
160              
161             if( defined( my $lat = delete $opts{latitude} ) ) {
162             $opts{LAT} = lat2mod $lat;
163             $opts{LAHS} = $lat > 0 ? 0x0 : 0x1
164             }
165              
166             if( defined( my $lon = delete $opts{longitude} ) ) {
167             $opts{LONG} = lon2mod $lon;
168             $opts{LOHS} = $lon > 0 ? 0x0 : 0x1
169             }
170              
171             if( defined( my $direction = delete $opts{direction} ) ) {
172             if( $direction > 255 ) {
173             $opts{DIRH} = 1;
174             $opts{DIR} = $direction - 256;
175             } else {
176             $opts{DIRH} = 0;
177             $opts{DIR} = $direction;
178             }
179             }
180              
181             if( defined( my $dist = delete $opts{dist} ) ) {
182             $opts{ODM} = int(($dist // 0) * 10);
183             }
184              
185             if( defined( my $avg_speed = delete $opts{avg_speed} ) ) {
186             # Speed rounded to 0.1
187             my $SPD = int(($avg_speed // 0) * 10);
188              
189             $opts{SPD_LO} = ($SPD & 0x000000ff);
190             $opts{SPD_HI} = ($SPD & 0x0000ff00) >> 8;
191             }
192              
193             if( defined( my $order = delete $opts{order} ) ) {
194             $opts{DIN} = $order ? 0b10000000 : 0b00000000;
195             }
196              
197             return $class->$orig( bin => $bin, %opts, SRT => EGTS_SR_POS_DATA ) if $bin;
198             return $class->$orig( %opts, SRT => EGTS_SR_POS_DATA );
199             };
200              
201             augment as_debug => sub {
202             my ($self) = @_;
203 4     4   1932 use bytes;
  4         4  
  4         12  
204              
205             my @bytes = ((unpack('B*', $self->SRD)) =~ m{.{8}}g);
206              
207             my @str;
208             push @str => sprintf('NTM: %s %s %s %s', splice @bytes, 0 => usize('L'));
209             push @str => sprintf('LAT: %s %s %s %s', splice @bytes, 0 => usize('L'));
210             push @str => sprintf('LONG: %s %s %s %s', splice @bytes, 0 => usize('L'));
211              
212             push @str => sprintf('FLAGS: %s', splice @bytes, 0 => usize('C'));
213              
214             push @str => sprintf('SPD_LO: %s', splice @bytes, 0 => usize('C'));
215             push @str => sprintf('SPD_HI: %s', splice @bytes, 0 => usize('C'));
216             push @str => sprintf('DIR: %s', splice @bytes, 0 => usize('C'));
217             push @str => sprintf('ODM: %s %s %s', splice @bytes, 0 => 3);
218             push @str => sprintf('DIN: %s', splice @bytes, 0 => usize('C'));
219             push @str => sprintf('SRC: %s', splice @bytes, 0 => usize('C'));
220              
221             push @str => sprintf('ALT: %s %s %s', splice @bytes, 0 => 3)
222             if $self->ALTE;
223             push @str => sprintf('SRCD: %s %s', splice @bytes, 0 => usize('S'))
224             if @bytes;
225              
226             return @str;
227             };
228              
229             __PACKAGE__->meta->make_immutable();