File Coverage

blib/lib/Device/MegaSquirt/MS2ExtraRel303s.pm
Criterion Covered Total %
statement 15 186 8.0
branch 0 40 0.0
condition n/a
subroutine 5 20 25.0
pod 8 13 61.5
total 28 259 10.8


line stmt bran cond sub pod time code
1             package Device::MegaSquirt::MS2ExtraRel303s;
2 1     1   5 use strict;
  1         2  
  1         37  
3 1     1   7 use warnings;
  1         1  
  1         31  
4              
5 1     1   6 use Carp;
  1         2  
  1         66  
6              
7 1     1   988 use Text::LookUpTable;
  1         24475  
  1         43  
8              
9 1     1   12 use vars qw(@ISA);
  1         3  
  1         2577  
10             @ISA = ('Device::MegaSquirt');
11              
12             =head1 NAME
13              
14             Device::MegaSquirt::MS2ExtraRel303s - operations for version 'MS2Extra Rel 3.0.3s'
15              
16             =head1 SYNOPSIS
17              
18             $ms = Device::MegaSquirt->new($device);
19              
20             $tbl = $ms->read_advanceTable1();
21             $res = $ms->write_advanceTable1($tbl);
22              
23             $tbl = $ms->read_veTable1();
24             $res = $ms->write_veTable1($tbl);
25              
26             $val = $ms->read_crankingRPM();
27             $res = $ms->write_crankingRPM($val);
28              
29             $data = $ms->read_BurstMode();
30              
31             =head1 DESCRIPTION
32              
33             This modules implements the version specific operations of Device::MegaSquirt
34             for version 'MS2Extra Rel 3.0.3s'.
35              
36             =head1 OPERATONS
37              
38             =cut
39              
40             # {{{ new()
41              
42             =head2 Device::MegaSquirt::MS2ExtraRel303s->new($mss)
43              
44             Returns object TRUE on success, FALSE on error
45              
46             Given a Device::MegaSquirt::Serial object ($mss) it creates a
47             new object.
48              
49             $ms = Device::MegaSquirt::MS2ExtraRel303s->new($mss);
50              
51             Normally this is called from MegaSquirt->new() and is not
52             called directly.
53              
54             $ms = Device::MegaSquirt->new($dev);
55              
56             =cut
57              
58             sub new {
59 0     0 1   my ($class, $mss) = @_;
60             # mss - mega squirt serial device
61              
62 0           bless {
63             version => 'MS2Extra Rel 3.0.3s',
64             mss => $mss,
65             }, $class;
66             }
67              
68             # }}}
69              
70             # {{{ read_BurstMode()
71              
72             =head2 $ms->read_BurstMode()
73              
74             Returns: TRUE on success, FALSE on error
75              
76             Retrives one chunk of burst mode data.
77              
78             $data = $ms->read_BurstMode();
79             print $data->{'pulseWidth1'} . "\n";
80              
81             =cut
82              
83              
84             sub read_BurstMode {
85 0     0 1   my $self = shift;
86 0           my $mss = $self->{mss};
87              
88 0           my $num_bytes = 145;
89              
90 0           my $data = $mss->read_A($num_bytes);
91              
92 0           _parse_bin($data);
93             }
94              
95             # {{{ _parse_bin()
96              
97             # Parse the read data (binary) in to a Perl object.
98              
99             # "A"
100             # (65) - MS2 sends the real time variables as an array of 152 bytes
101             # (will continues to change). [2]
102             #
103             # The variable names and properties for each byte are described in the
104             # msn-extra.ini file shipped with each version of MS2/Extra. [2]
105             #
106             # Open megaquirt-ii.ini (found along with the firmware) and search for
107             # afr1 after the line [BurstMode] [2]
108             #
109              
110             # {{{ %dat_def
111             # Definition of the data in a BurstMode packet.
112             my %dat_def = (
113             seconds => {
114             packt => 'n', # perl 'pack' type
115             offset => 0, # offset in bytes
116             mtype => 'U16', # Megasuirt type in .ini
117             units => 's', # units
118             #conv_fn => sub { $_[0] * 0.000666 }, # function to convert value from raw data
119             mult => 1.0, # value to multiply by, default 1
120             scale => 0, # value to add to
121             },
122             pulseWidth1 => {
123             packt => 'n',
124             offset => 2,
125             mtype => 'U16',
126             units => 's',
127             mult => 0.000666,
128             },
129             pulseWidth2 => {
130             packt => 'n',
131             offset => 4,
132             mtype => 'U16',
133             units => 's',
134             mult => 0.000666,
135             },
136             rpm => {
137             packt => 'n',
138             offset => 6,
139             mtype => 'U16',
140             units => 'RPM',
141             },
142             advance => {
143             packt => 'n',
144             offset => 8,
145             mtype => 'S16',
146             units => 'deg',
147             mult => 0.100,
148             },
149             squirt => {
150             packt => 'B8', # 8 bit byte
151             offset => 10,
152             mtype => 'U08',
153             units => 'bit',
154             },
155             engine => {
156             packt => 'B8',
157             offset => 11,
158             mtype => 'U08',
159             units => 'bit',
160             },
161             afrtgt1 => {
162             packt => 'C',
163             offset => 12,
164             mtype => 'U08',
165             units => 'AFR',
166             mult => 10.00,
167             },
168             afrtgt2 => {
169             packt => 'C',
170             offset => 13,
171             mtype => 'U08',
172             units => 'AFR',
173             mult => 10.00,
174             },
175             wb02_en1 => {
176             packt => 'C',
177             offset => 14,
178             mtype => 'U08',
179             units => '',
180             },
181             wb02_en2 => {
182             packt => 'C',
183             offset => 15,
184             mtype => 'U08',
185             units => '',
186             },
187             barometer => {
188             packt => 'n',
189             offset => 16,
190             mtype => 'S16',
191             units => 'kPa',
192             mult => '0.100',
193             },
194             map => {
195             packt => 'n',
196             offset => 18,
197             mtype => 'S16',
198             units => 'kPa',
199             mult => '0.100',
200             },
201             mat => {
202             packt => 'n',
203             offset => 20,
204             mtype => 'S16',
205             units => '°F',
206             mult => '0.100',
207             },
208             coolant => {
209             packt => 'n',
210             offset => 22,
211             mtype => 'S16',
212             units => '°F',
213             mult => '0.100',
214             },
215             tps => {
216             packt => 'n',
217             offset => 24,
218             mtype => 'S16',
219             units => '%',
220             mult => '0.100',
221             },
222             batteryVoltage => {
223             packt => 'n',
224             offset => 26,
225             mtype => 'S16',
226             units => 'v',
227             mult => '0.100',
228             },
229             afr1 => {
230             packt => 'n',
231             offset => 28,
232             mtype => 'S16',
233             units => 'AFR',
234             mult => 0.100,
235             },
236             afr2 => {
237             packt => 'n',
238             offset => 30,
239             mtype => 'S16',
240             units => 'AFR',
241             mult => 0.100,
242             },
243             egoCorrection1 => {
244             packt => 'n',
245             offset => 36,
246             mtype => 'S16',
247             units => '%',
248             mult => 0.1000,
249             },
250             airCorrection => {
251             packt => 'n',
252             offset => 38,
253             mtype => 'S16',
254             units => '%',
255             },
256             warmupEnrich => {
257             packt => 'n',
258             offset => 40,
259             mtype => 'S16',
260             units => '%',
261             },
262              
263             # TODO more tedious work adding entries from megasquirt-ii.ini.ms2extra
264             );
265             # }}}
266              
267             sub _parse_bin {
268 0     0     my $bin = shift;
269              
270 0           my %data = ();
271              
272 0           foreach my $name (keys %dat_def) {
273 0           my $def = $dat_def{$name};
274              
275 0           my $packt = $def->{packt};
276 0           my $offset = $def->{offset};
277              
278 0           my ($val) = unpack('@' . $offset . $packt, $bin);
279              
280             # Convert the raw value in to something more meaningful.
281 0 0         if (exists $def->{'conv_fn'}) {
282 0           my $fn = $def->{'conf_fn'};
283 0           $val = $fn->($val);
284             } else {
285 0 0         if (exists $def->{'scale'}) {
286 0           $val += $def->{'scale'};
287             }
288 0 0         if (exists $def->{'mult'}) {
289 0           $val *= $def->{'mult'};
290             }
291             }
292              
293 0           $data{$name} = $val;
294             }
295              
296 0           return \%data;
297             # my ($seconds, $pulseWidth1, $pulseWidth2, $rpm, $advance, $squirt, $engine,
298             # $afrtgt1, $afrtgt2, $wbo2_en1, $wbo2_en2, $barometer, $map,
299             # $mat, $coolant, $tps) =
300             # unpack("nnnnnB8B8CCCCnnnnn", $data);
301             #
302             #{
303             # seconds => $seconds,
304             # pulseWidth1 => $pulseWidth1,
305             #};
306             }
307              
308             # }}}
309              
310             # }}}
311              
312             # {{{ read_advanceTable1() :-)
313              
314             =head2 $ms->read_advanceTable1()
315              
316             Returns: Text::LookUpTable object (TRUE) on success, FALSE on error
317              
318             $tbl = $ms->read_advanceTable1();
319              
320             =cut
321              
322             sub read_advanceTable1 {
323 0     0 1   my $ms = shift;
324              
325 0           my $mss = $ms->get_mss();
326              
327             #
328             # doc/ini/megasquirt-ii.ms2extra.alpha_3.0.3u_20100522.ini
329             # page = 3
330             # advanceTable1 = array , S16, 000, [12x12], "deg", 0.10000, 0.0
331             #
332             # page = 3 -> table_idx 7
333             #
334             # read_r(
335 0           my $packed_bytes = $mss->read_r(_page_to_table(3), 0, 288);
336              
337 0           my @vals = unpack("n*", $packed_bytes); # S16
338              
339 0           my $num_rcvd = @vals;
340 0 0         if ($num_rcvd != 144) {
341 0           carp "ERROR: received $num_rcvd bytes but was expecting 144.";
342 0           return;
343             }
344              
345             # convert values
346 0           @vals = map { $_ * 0.100; } @vals;
  0            
347              
348             # Start with a blank table of the correct dimensions
349             # and then set the values accordingly.
350              
351 0           my $tbl = Text::LookUpTable->load_blank(12, 12, "rpm", "load");
352              
353 0           my @xs = $ms->read_srpm_table1();
354 0           my @ys = $ms->read_smap_table1();
355              
356 0           $tbl->set_x_coords(@xs);
357 0           $tbl->set_y_coords(@ys);
358              
359 0           my $n = 0;
360 0           for (my $i = 0; $i < 12; $i++) {
361 0           for (my $j = 0; $j < 12; $j++) {
362 0           $tbl->set($j, $i, $vals[$n]);
363 0           $n++;
364             }
365             }
366              
367 0           return $tbl;
368             }
369              
370             # {{{ read_srpm_table1() :-)
371              
372             #
373             # Returns: @list on success, FALSE on error
374             #
375             # Reads the values of the rpm coordinates for advanceTable1.
376             #
377              
378             sub read_srpm_table1 {
379 0     0 0   my $ms = shift;
380              
381 0           my $mss = $ms->get_mss();
382              
383             #
384             # doc/ini/megasquirt-ii.ms2extra.alpha_3.0.3u_20100522.ini
385             # page = 3, tble_idx = 7
386             #
387             # srpm_table1 = array , U16, 576, [ 12], "RPM", 1.00000, 0.00000, 0.00,15000.00,
388             #
389             #
390 0           my $read = $mss->read_r(_page_to_table(3), 576, 24);
391 0           my @bytes = unpack("n*", $read); # U16
392             #my @bytes = unpack("v*", $read); # U16
393             #my @bytes = unpack("s*", $read); # U16
394             #my @bytes = unpack("S*", $read); # U16
395 0           my $num_rcvd = @bytes;
396 0 0         if ($num_rcvd != 12) {
397 0           carp "ERROR: received $num_rcvd value but was expecting 12.";
398 0           return;
399             }
400              
401             # no processing, pass on data as is
402              
403 0           return @bytes;
404             }
405              
406             # }}}
407              
408             # {{{ read_smap_table1() :-)
409              
410             #
411             # Returns: @list on success, FALSE on error
412             #
413             # Reads the values of the map coordinates for advanceTable1.
414             #
415              
416             sub read_smap_table1 {
417 0     0 0   my $ms = shift;
418              
419 0           my $mss = $ms->get_mss();
420              
421             #
422             # doc/ini/megasquirt-ii.ms2extra.alpha_3.0.3u_20100522.ini
423             #
424             # page = 3
425             # smap_table1 = array , S16, 624, [ 12], "%", 0.10000, 0.00000, 0.00, 400.00, 1 ; * ( 24 bytes)
426             #
427 0           my $read = $mss->read_r(_page_to_table(3), 624, 24);
428 0           my @bytes = unpack("n*", $read); # U16
429 0           my $num_rcvd = @bytes;
430 0 0         if ($num_rcvd != 12) {
431 0           carp "ERROR: received $num_rcvd value but was expecting 12.";
432 0           return;
433             }
434              
435 0           @bytes = map { ($_ * 0.100); } @bytes;
  0            
436              
437             # the bytes are backwards, not sure why, fix them
438 0           @bytes = reverse @bytes;
439              
440 0           return @bytes;
441             }
442              
443             # }}}
444              
445             # }}}
446              
447             # {{{ write_advanceTable1() :-)
448              
449             =head2 $ms->write_advanceTable1()
450              
451             Returns: TRUE on success, FALSE on error
452              
453             $ms->write_advanceTable1($tbl);
454              
455             =cut
456              
457             # TODO - write srpm, smap
458              
459             sub write_advanceTable1 {
460 0     0 1   my $ms = shift;
461 0           my $tbl = shift;
462              
463 0           my $mss = $ms->get_mss();
464              
465 0           my @vals = $tbl->flatten();
466              
467             # un-convert values
468 0           @vals = map { $_ / 0.100; } @vals;
  0            
469              
470 0           my $pack = pack("n*", @vals);
471 0           my @bytes = unpack("C*", $pack);
472              
473 0 0         unless (288 == @bytes) {
474 0           carp "wrong number of bytes";
475 0           return;
476             }
477              
478 0           $mss->write_w(_page_to_table(3), 0, @bytes);
479             }
480              
481             # }}}
482              
483             # {{{ read_veTable1() :-)
484              
485             =head2 $ms->read_veTable1()
486              
487             Returns: Text::LookUpTable object (TRUE) on success, FALSE on error
488              
489             $tbl = $ms->read_veTable1();
490              
491             =cut
492              
493             sub read_veTable1 {
494 0     0 1   my $ms = shift;
495              
496 0           my $mss = $ms->get_mss();
497              
498             #
499             # doc/ini/megasquirt-ii.ms2extra.alpha_3.0.3u_20100522.ini
500             # page = 5
501             # veTable1 = array , U08, 0, [16x16], "%", 1.00000, 0.00000, 0.00, 255.00, 0 ; * (144 bytes)
502             #
503 0           my $read = $mss->read_r(_page_to_table(5), 0, 256);
504 0           my @bytes = unpack("C*", $read);
505 0           my $num_rcvd = @bytes;
506 0 0         if ($num_rcvd != 256) {
507 0           carp "ERROR: received $num_rcvd bytes but was expecting 256.";
508 0           return;
509             }
510              
511 0           my $tbl = Text::LookUpTable->load_blank(16, 16, "rpm", "load");
512              
513 0           my @xs = $ms->read_frpm_table1();
514 0           my @ys = $ms->read_fmap_table1();
515              
516 0           $tbl->set_x_coords(@xs);
517 0           $tbl->set_y_coords(@ys);
518              
519 0           my $n = 0;
520              
521 0           for (my $i = 0; $i < 16; $i++) {
522 0           for (my $j = 0; $j < 16; $j++) {
523 0           $tbl->set($j, $i, $bytes[$n]);
524 0           $n++;
525             }
526             }
527              
528 0           return $tbl;
529             }
530              
531             # {{{ read_frpm_table1() :-)
532              
533             #
534             # Returns list of values on SUCCESS, FALSE on error
535             #
536             # Reads the rpm coordinate values for veTable1.
537             #
538              
539             sub read_frpm_table1 {
540 0     0 0   my $ms = shift;
541              
542 0           my $mss = $ms->get_mss();
543              
544             #
545             # doc/ini/megasquirt-ii.ms2extra.alpha_3.0.3u_20100522.ini
546             # page = 5
547             #
548             # frpm_table1 = array , U16, 768, [ 16], "RPM", 1.00000, 0.00000, 0.00,15000.00, 0 ; * ( 24 bytes)
549             #
550 0           my $read = $mss->read_r(_page_to_table(5), 768, 32);
551 0           my @bytes = unpack("n*", $read); # U16
552 0           my $num_rcvd = @bytes;
553 0 0         if ($num_rcvd != 16) {
554 0           carp "ERROR: received $num_rcvd bytes but was expecting 16.";
555 0           return;
556             }
557              
558             # no process, pass on data as is
559              
560 0           return @bytes;
561             }
562              
563             # }}}
564              
565             # {{{ read_fmap_table1() :-)
566              
567             #
568             # Returns list of values on SUCCESS, FALSE on error
569             #
570             # Reads the map coordinate values for veTable1.
571             #
572              
573             sub read_fmap_table1 {
574 0     0 0   my $ms = shift;
575              
576 0           my $mss = $ms->get_mss();
577              
578             #
579             # doc/ini/megasquirt-ii.ms2extra.alpha_3.0.3u_20100522.ini
580             # page = 5
581             #
582             # fmap_table1 = array , S16, 864, [ 16], "%", 0.10000, 0.00000, 0.00, 400.00, 1 ; * ( 24 bytes)
583             #
584             # page 5 -> table_idx = 9
585             #
586 0           my $read = $mss->read_r(_page_to_table(5), 864, 32);
587 0           my @bytes = unpack("n*", $read); # U16
588 0           my $num_rcvd = @bytes;
589 0 0         if ($num_rcvd != 16) {
590 0           carp "ERROR: received $num_rcvd bytes but was expecting 16.";
591 0           return;
592             }
593              
594 0           @bytes = map { ($_ * 0.100); } @bytes;
  0            
595              
596             # the bytes are backwards, not sure why, fix them
597 0           @bytes = reverse @bytes;
598              
599 0           return @bytes;
600             }
601              
602             # }}}
603              
604             # }}}
605              
606             # {{{ write_veTable1() :-)
607              
608             =head2 $ms->write_veTable1()
609              
610             Returns TRUE on success, FALSE on error
611              
612             $ms->write_veTable1($tbl);
613              
614             =cut
615              
616             # TODO - write frpm, fmap
617              
618             sub write_veTable1 {
619 0     0 1   my $ms = shift;
620 0           my $tbl = shift;
621              
622 0           my $mss = $ms->get_mss();
623              
624 0           my @bytes = $tbl->flatten();
625              
626 0           $mss->write_w(_page_to_table(5), 0, @bytes);
627             }
628              
629             # }}}
630              
631             # {{{ read_arpm_table1() :-)
632              
633             sub read_arpm_table1 {
634 0     0 0   my $ms = shift;
635              
636 0           my $mss = $ms->get_mss();
637              
638             #
639             # doc/ini/megasquirt-ii.ms2extra.alpha_3.0.3u_20100522.ini
640             #
641             # page = 1
642             # arpm_table1 = array , U16, 374, [ 12], "RPM", 1.00000, 0.00000, 0.00,15000.00, 0 ; * ( 24 bytes)
643             #
644             #
645              
646 0           my $read = $mss->read_r(_page_to_table(1), 374, 24);
647 0 0         unless ($read) {
648 0           carp "read_arpm_table1() read_r error\n";
649 0           return;
650             }
651              
652 0           my @bytes = unpack("n*", $read); # U16
653              
654 0           my $num_rcvd = @bytes;
655              
656 0 0         if ($num_rcvd != 12) {
657 0           carp "ERROR: received $num_rcvd value but was expecting 12.";
658 0           return;
659             }
660              
661             # no need to process, pass on data as is
662              
663 0           return @bytes;
664             }
665              
666             # }}}
667              
668             # {{{ read_crankingRPM() :-)
669              
670             =head2 $ms->read_crankingRPM()
671              
672             Returns $val on success, FALSE on error
673              
674             $val = $ms->read_crankingRPM();
675              
676             =cut
677              
678             sub read_crankingRPM {
679 0     0 1   my $ms = shift;
680              
681 0           my $mss = $ms->get_mss();
682              
683 0           my $read = $mss->read_r(_page_to_table(1), 20, 2);
684 0 0         unless ($read) {
685 0           carp "read_crankingRPM() read_r error\n";
686 0           return;
687             }
688              
689 0           my @bytes = unpack("n", $read); # S16
690              
691 0           my $num_rcvd = @bytes;
692              
693 0 0         if ($num_rcvd != 1) {
694 0           carp "ERROR: received $num_rcvd value but was expecting 1.";
695 0           return;
696             }
697              
698             # no need to process, pass on data as is
699              
700 0           return $bytes[0];
701             }
702              
703             # }}}
704              
705             # {{{ write_crankingRPM() :-)
706              
707             =head2 $ms->write_crankingRPM($val)
708              
709             Returns TRUE on success, FALSE on error
710              
711             $res = $ms->write_crankingRPM($val);
712              
713             =cut
714              
715             sub write_crankingRPM {
716 0     0 1   my $ms = shift;
717 0           my $val = shift;
718              
719 0 0         unless (defined $val) {
720 0           carp "a value must be given to write_crankingRPM";
721 0           return;
722             }
723              
724 0           my $mss = $ms->get_mss();
725              
726             # write_w expects values in bytes but crankRPM is
727             # a two byte integer. re-pack it accordingly
728 0           my $pack = pack("n", $val);
729 0           my @bytes = unpack("CC", $pack);
730              
731 0 0         unless (2 == @bytes) {
732 0           my $n = @bytes;
733 0           carp "wrong number of bytes: $n ";
734             }
735              
736 0           my $write = $mss->write_w(_page_to_table(1), 20, @bytes);
737 0 0         unless ($write) {
738 0           carp "write_crankingRPM() write_w error\n";
739 0           return;
740             }
741              
742 0           return 1; # success
743             }
744              
745             # }}}
746              
747             # {{{ _page_to_table() :-)
748              
749             #
750             # Some commands require "table_idx" but in the .ini
751             # it is specified as "page.
752             # _page_to_table provides this conversion.
753             #
754             # The conversions described in [2] are apparantley out of date
755             # because some of them do not work.
756             #
757             # These conversions were found through trial and error.
758             #
759              
760             sub _page_to_table {
761 0     0     my $page = shift;
762              
763 0           my $table;
764 0 0         if (1 == $page) {
    0          
    0          
765 0           $table = 4;
766             } elsif (3 == $page) {
767 0           $table = 10;
768             } elsif (5 == $page) {
769 0           $table = 9;
770             } else {
771 0           carp "ERROR: undefined page '$page' for _page_to_table()";
772 0           return;
773             }
774              
775 0           return $table;
776             }
777              
778             # }}}
779              
780             =head1 REFERENCES
781              
782             [1] MegaSquirt Engine Management System
783             http://www.msextra.com/
784              
785             [2] http://home.comcast.net/~whaussmann/RS232_MS2E/RS232_MS2_tables.htm#adv_tbl
786              
787             =head1 AUTHOR
788              
789             Jeremiah Mahler
790             CPAN ID: JERI
791             http://www.google.com/profiles/jmmahler#about
792              
793             =head1 COPYRIGHT
794              
795             Copyright (c) 2010, Jeremiah Mahler. All Rights Reserved.
796             This module is free software. It may be used, redistributed
797             and/or modified under the same terms as Perl itself.
798              
799             =head1 SEE ALSO
800              
801             Text::LookUpTable, Device::MegaSquirt
802              
803             =cut
804              
805             # vim:foldmethod=marker
806              
807             1;