File Coverage

blib/lib/LEGO/NXT.pm
Criterion Covered Total %
statement 15 263 5.7
branch 0 102 0.0
condition n/a
subroutine 5 71 7.0
pod 57 57 100.0
total 77 493 15.6


line stmt bran cond sub pod time code
1             # vim: sts=2 sw=2
2              
3             # LEGO NXT Direct Commands API
4             # Author: Michael Collins michaelcollins@ivorycity.com
5             # Contributions: Aran Deltac aran@arandeltac.com
6             #
7             # Copyright 2006 Michael Collins
8             #
9             # This program is free software; you can redistribute it and/or modify
10             # it under the terms of the GNU General Public License as published by
11             # the Free Software Foundation; either version 2 of the License
12             #
13             # This program is distributed in the hope that it will be useful,
14             # but WITHOUT ANY WARRANTY; without even the implied warranty of
15             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16             # GNU General Public License for more details.
17             #
18             # You should have received a copy of the GNU General Public License
19             # along with this program; if not, write to the Free Software Foundation,
20             # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21             #
22             # You may also distribute under the terms of Perl Artistic License,
23             # as specified in the Perl README file.
24             #
25              
26             package LEGO::NXT;
27 1     1   1017 use strict qw(vars);
  1         2  
  1         40  
28 1     1   6 use warnings;
  1         2  
  1         31  
29              
30 1     1   718 use LEGO::NXT::Constants;
  1         3  
  1         7178  
31              
32             our $VERSION = '2.00';
33             our @ISA;
34              
35             =head1 NAME
36              
37             LEGO::NXT - LEGO NXT Direct Commands API.
38              
39             =head1 SYNOPSIS
40              
41             use LEGO::NXT;
42            
43             # Create a new Bluetooth/NXT object by connecting to
44             # a specific bluetooth address and channel.
45             my $nxt = LEGO::NXT->new( 'xx:xx:xx:xx:xx:xx', 1 );
46            
47             $nxt->play_sound_file($NXT_NORET, 0,'! Attention.rso');
48            
49             $res = $nxt->get_battery_level($NXT_RET);
50            
51             # Turn on Motor 1 to full power.
52             $res = $nxt->set_output_state(
53             $NXT_RET,
54             $NXT_SENSOR1,
55             100,
56             $NXT_MOTORON|$NXT_REGULATED,
57             $NXT_REGULATION_MODE_MOTOR_SPEED, 0,
58             $NXT_MOTOR_RUN_STATE_RUNNING, 0,
59             );
60              
61             =head1 DESCRIPTION
62              
63             This module provides low-level control of a LEGO NXT brick over bluetooth
64             using the Direct Commands API. This API will not enable you to run programs
65             on the NXT, rather, it will connect to the NXT and issue real-time commands
66             that turn on/off motors, retrieve sensor values, play sound, and more.
67              
68             Users will leverage this API to control the NXT directly from an external box.
69              
70             This is known to work on Linux. Other platforms are currently untested,
71             though it should work on any system that has the Net::Bluetooth module.
72              
73             =head1 MANUAL
74              
75             There is a manual for this module with an introduction, tutorials, plugins,
76             FAQ, etc. See L.
77              
78             =head1 SUPPORT
79              
80             If you would like to get some help join the #lego-nxt IRC chat room
81             on the MagNET IRC network (the official perl IRC network). More
82             information at:
83              
84             L
85              
86             =head1 PLUGINS
87              
88             LEGO::NXT supports the ability to load plugins.
89              
90             use LEGO::NXT qw( Scorpion );
91              
92             Plugins provide higher level and more sophisticated means of handling
93             your NXT. Likely you will want to use a plugin if you want to control
94             your NXT as the methods in LEGO::NXT itself are very low level and
95             tedious to use by themselves.
96              
97             Please see L for more details about how to
98             use plugins (and write your own!) as well as what plugins are available
99             to you.
100              
101             =cut
102              
103             my %error_codes = (
104             #Direct Command errors
105             0x20 => "Pending communication transaction in progress",
106             0x40 => "Specified mailbox queue is empty",
107             0xBD => "Request failed (i.e. specified file not found)",
108             0xBE => "Unknown command opcode",
109             0xBF => "Insane packet",
110             0xC0 => "Data contains out-of-range values",
111             0xDD => "Communication bus error",
112             0xDE => "No free memory in communication buffer",
113             0xDF => "Specified channel/connection is not valid",
114             0xE0 => "Specified channel/connection not configured or busy",
115             0xEC => "No active program",
116             0xED => "Illegal size specified",
117             0xEE => "Illegal mailbox queue ID specified",
118             0xEF => "Attempted to access invalid field of a structure",
119             0xF0 => "Bad input or output specified",
120             0xFB => "Insufficient memory available",
121             0xFF => "Bad arguments",
122              
123             #System errors
124             0x81 => "No more handles",
125             0x82 => "No space",
126             0x83 => "No more files",
127             0x84 => "End of file expected",
128             0x85 => "End of file",
129             0x86 => "Not a linear file",
130             0x87 => "File not found",
131             0x88 => "Handle all ready closed",
132             0x89 => "No linear space",
133             0x8A => "Undefined error",
134             0x8B => "File is busy",
135             0x8C => "No write buffers",
136             0x8D => "Append not possible",
137             0x8E => "File is full",
138             0x8F => "File exists",
139             0x90 => "Module not found",
140             0x91 => "Out of boundary",
141             0x92 => "Illegal file name",
142             0x93 => "Illegal handle"
143             );
144              
145             =head1 METHODS
146              
147             =head2 new
148              
149             $nxt = LEGO::NXT->new( new LEGO::NXT:BlueComm('xx:xx:xx:xx',0) );
150             $nxt = LEGO::NXT->new( new LEGO::NXT:USBComm() );
151              
152             Creates a new NXT object, however a connection is not established until
153             the first direct command is issued. Argument 1 should be the bluetooth
154             address of your NXT (from "hcitool scan" for instance). Argument 2 is
155             the channel you wish to connect on -- 1 or 2 seems to work.
156              
157             =cut
158              
159             sub new
160             {
161 1     1 1 819 my ($pkgnm,$comm) = @_;
162              
163 1         7 my $this = {
164             'comm' => $comm,
165             'error' => undef,
166             'errstr' => undef,
167             'status' => undef,
168             'result' => undef
169             };
170            
171 1         3 bless $this, $pkgnm;
172 1         4 return $this;
173             }
174              
175             =head2 initialize_ultrasound_port
176              
177             $nxt->initialize_ultrasound_port($NXT_SENSOR_4);
178              
179             Sets the port of your choosing to use the ultrasound digital sensor.
180              
181             =cut
182              
183             sub initialize_ultrasound_port
184             {
185 0     0 1 0 my ($this,$port) = @_;
186 0         0 $this->set_input_mode($NXT_RET,$port,$NXT_LOW_SPEED_9V,$NXT_RAW_MODE);
187             }
188              
189             =head2 get_ultrasound_measurement_units
190              
191             $nxt->get_ultrasound_measurement_units($NXT_SENSOR_4);
192              
193             Returns the units of measurement the US sensor is using (cm? in?)
194              
195             =cut
196              
197             sub get_ultrasound_measurement_units
198             {
199 0     0 1 0 my ($this,$port) = @_;
200 0         0 return $this->ls_request_response($port,2,7,pack("CC",0x02,0x14));
201             }
202              
203             =head2 get_ultrasound_measurement_byte
204              
205             $nxt->get_ultrasound_measurement_byte($NXT_SENSOR_4,$byte);
206              
207             Returns the distance reading from the NXT from register $byte.
208             $byte should be a value 0-7 indicating the measurement register
209             in the ultrasound sensor. In continuous measurement mode,
210             measurements are stored in register 0 only, however in one-shot mode,
211             each time one-shot is called a value will be stored in a new register.
212              
213             =cut
214              
215             sub get_ultrasound_measurement_byte
216             {
217 0     0 1 0 my ($this,$port,$byte) = @_;
218 0         0 return $this->ls_request_response($port,2,1,pack("CC",0x02,0x42+$byte));
219             }
220              
221             =head2 get_ultrasound_continuous_measurement_interval
222              
223             $nxt->get_ultrasound_measurement_interval($NXT_SENSOR_4);
224              
225             Returns the time period between ultrasound measurements.
226              
227             =cut
228              
229             sub get_ultrasound_continuous_measurement_interval
230             {
231 0     0 1 0 my ($this,$port)=@_;
232 0         0 return $this->ls_request_response($port,2,1,pack("CC",0x02,0x40));
233             }
234              
235             =head2 get_ultrasound_read_command_state
236              
237             $nxt->get_ultrasound_read_command_state($NXT_SENSOR_4);
238              
239             Returns whether the sensor is in one-off mode or continuous measurement
240             mode (the default).
241              
242             =cut
243              
244             sub get_ultrasound_read_command_state
245             {
246 0     0 1 0 my ($this,$port) = @_;
247 0         0 return $this->ls_request_response($port,2,1,pack("CC",0x02,0x41));
248             }
249              
250             =head2 get_ultrasound_actual_zero
251              
252             $nxt->get_ultrasound_actual_zero($NXT_SENSOR_4);
253              
254             Returns the calibrated zero-distance value for the sensor
255              
256             =cut
257              
258             sub get_ultrasound_actual_zero
259             {
260 0     0 1 0 my ($this,$port) = @_;
261 0         0 return $this->ls_request_response($port,2,1,pack("CC",0x02,0x50));
262             }
263              
264             =head2 get_ultrasound_actual_scale_factor
265              
266             $nxt->get_ultrasound_actual_scale_factor($NXT_SENSOR_4);
267              
268             Returns the scale factor used to compute distances
269              
270             =cut
271              
272             sub get_ultrasound_actual_scale_factor
273             {
274 0     0 1 0 my ($this,$port) = @_;
275 0         0 return $this->ls_request_response($port,2,1,pack("CC",0x02,0x51));
276             }
277              
278             =head2 get_ultrasound_actual_scale_divisor
279              
280             $nxt->get_ultrasound_actual_scale_divisor($NXT_SENSOR_4);
281              
282             Returns the scale divisor used to compute distances
283              
284             =cut
285              
286             sub get_ultrasound_actual_scale_divisor
287             {
288 0     0 1 0 my ($this,$port) = @_;
289 0         0 return $this->ls_request_response($port,2,1,pack("CC",0x02,0x52));
290             }
291              
292             =head2 set_ultrasound_off
293              
294             $nxt->set_ultrasound_off($NXT_SENSOR_4);
295              
296             Turns the ultrasound sensor off
297              
298             =cut
299              
300             sub set_ultrasound_off
301             {
302 0     0 1 0 my ($this,$port) = @_;
303 0         0 return $this->ls_write($NXT_RET,$port,3,0,pack("CCC",0x02,0x41,0x00));
304             }
305              
306             =head2 set_ultrasound_single_shot
307              
308             $nxt->set_ultrasound_single_shot($NXT_SENSOR_4);
309              
310             Puts the sensor in single shot mode - it will only store a value in a register once each time this function is called
311              
312             =cut
313              
314             sub set_ultrasound_single_shot
315             {
316 0     0 1 0 my ($this,$port) = @_;
317 0         0 return $this->ls_write($NXT_RET,$port,3,0,pack("CCC",0x02,0x41,0x01));
318             }
319              
320             =head2 set_ultrasound_continuous_measurement
321              
322             $nxt->set_ultrasound_continuous_measurement($NXT_SENSOR_4);
323              
324             Puts the sensor in continuous measurement mode.
325              
326             =cut
327              
328             sub set_ultrasound_continuous_measurement
329             {
330 0     0 1 0 my ($this,$port) = @_;
331 0         0 return $this->ls_write($NXT_RET,$port,3,0,pack("CCC",0x02,0x41,0x02));
332             }
333              
334             =head2 set_ultrasound_event_capture_mode
335              
336             $nxt->set_ultrasound_event_capture_mode($NXT_SENSOR_4);
337              
338             In this mode the US sensor will detect only other ultrasound sensors in the vicinity.
339              
340             =cut
341              
342             sub set_ultrasound_event_capture_mode
343             {
344 0     0 1 0 my ($this,$port) = @_;
345 0         0 return $this->ls_write($NXT_RET,$port,3,0,pack("CCC",0x02,0x41,0x03));
346             }
347              
348             =head2 ultrasound_request_warm_reset
349              
350             $nxt->ultrasound_request_warm_reset($NXT_SENSOR_4);
351              
352             I won't lie - I don't know what a "warm reset" is, but it sounds like a nice
353             new beginning to me. =)
354              
355             =cut
356              
357             sub ultrasound_request_warm_reset
358             {
359 0     0 1 0 my ($this,$port) = @_;
360 0         0 return $this->ls_write($NXT_RET,$port,3,0,pack("CCC",0x02,0x41,0x04));
361             }
362              
363             =head2 set_ultrasound_continuous_measurement_interval
364              
365             $nxt->set_ultrasound_continuous_measurement_interval($NXT_SENSOR_4);
366              
367             Sets the sampling interval for the range sensor.
368              
369             TODO: Document valid values...
370              
371             =cut
372              
373             sub set_ultrasound_continuous_measurement_interval
374             {
375 0     0 1 0 my ($this,$port,$interval) = @_;
376 0         0 return $this->ls_write($NXT_RET,3,0,pack("CCC",0x02,0x40,$interval));
377             }
378              
379             =head2 set_ultrasound_actual_zero
380              
381             $nxt->set_ultrasound_actual_zero($NXT_SENSOR_4);
382              
383             Sets the calibrated zero value for the sensor.
384              
385             =cut
386              
387             sub set_ultrasound_actual_zero
388             {
389 0     0 1 0 my ($this,$port,$value) = @_;
390 0         0 return $this->ls_write($port,3,0,pack("CCC",0x02,0x50,$value));
391             }
392              
393             =head2 set_ultrasound_actual_scale_factor
394              
395             $nxt->set_ultrasound_actual_scale_factor($NXT_SENSOR_4);
396              
397             Sets the scale factor used in computing range.
398              
399             =cut
400              
401             sub set_ultrasound_actual_scale_factor
402             {
403 0     0 1 0 my ($this,$port,$value) = @_;
404 0         0 return $this->ls_write($port,3,0,pack("CCC",0x02,0x51,$value));
405             }
406              
407             =head2 set_ultrasound_actual_scale_divisor
408              
409             $nxt->set_ultrasound_actual_scale_divisor($NXT_SENSOR_4);
410              
411             Sets the scale divisor used in computing range.
412              
413             =cut
414              
415             sub set_ultrasound_actual_scale_divisor
416             {
417 0     0 1 0 my ($this,$port,$value) = @_;
418 0         0 return $this->ls_write($port,3,0,pack("CCC",0x02,0x52,$value));
419             }
420              
421             =head2 start_program
422              
423             $nxt->start_program($NXT_NORET,$filename)
424              
425             Start a program on the NXT called $filename
426              
427             =cut
428              
429             sub start_program
430             {
431 0     0 1 0 my ($this,$needsret,$file) = @_;
432 0         0 my $strlen = 1+length($file);
433 0         0 my $ret = $this->_do_cmd(
434             pack("CCZ[$strlen]",$needsret,$NXT_START_PROGRAM,$file),
435             $needsret
436             );
437              
438 0 0       0 return if $needsret==$NXT_NORET;
439              
440 0         0 $this->_parse_generic_ret($ret);
441             }
442              
443             =head2 stop_program
444              
445             $nxt->stop_program($NXT_NORET)
446              
447             Stop the currently executing program on the NXT
448              
449             =cut
450              
451             sub stop_program
452             {
453 0     0 1 0 my ($this,$needsret) = @_;
454              
455 0         0 my $ret = $this->_do_cmd(
456             pack("CC",$needsret,$NXT_STOP_PROGRAM),
457             $needsret
458             );
459              
460 0 0       0 return if $needsret==$NXT_NORET;
461 0         0 $this->_parse_generic_ret($ret);
462             }
463              
464             =head2 play_tone
465              
466             $nxt->play_tone($NXT_NORET,$pitch,$duration)
467              
468             Play a Tone in $pitch HZ for $duration miliseconds
469              
470             =cut
471              
472             sub play_tone
473             {
474 0     0 1 0 my ($this,$needsret,$pitch,$duration) = @_;
475              
476 0         0 my $ret = $this->_do_cmd(
477             pack("CCvv",$needsret,$NXT_PLAY_TONE,$pitch,$duration),
478             $needsret
479             );
480              
481 0 0       0 return if $needsret==$NXT_NORET;
482              
483 0         0 $this->_parse_generic_ret($ret);
484             }
485              
486             =head2 play_sound_file
487              
488             $nxt->play_sound_file($NXT_NORET,$repeat,$file)
489              
490             Play a NXT sound file called $file. Specify $repeat=1 for infinite repeat, 0 to play only once.
491              
492             =cut
493              
494             sub play_sound_file
495             {
496 0     0 1 0 my ($this,$needsret,$repeat,$file) = @_;
497 0         0 my $strlen = 1+length($file);
498 0         0 my $ret = $this->_do_cmd(
499             pack("CCCZ[$strlen]",$needsret,$NXT_PLAY_SOUND_FILE,$repeat,$file),
500             $needsret
501             );
502            
503 0 0       0 return if $needsret==$NXT_NORET;
504            
505 0         0 $this->_parse_generic_ret($ret);
506             }
507              
508             =head2 set_output_state
509              
510             $nxt->set_output_state($NXT_NORET,$port,$power,$mode,$regulation,$turnratio,$runstate,$tacholimit)
511              
512             Set the output state for one of the motor ports.
513              
514             $port One of the motor port constants.
515             $power -100 to 100 power level.
516             $mode An bitwise or of output mode constants.
517             $regulation One of the motor regulation mode constants.
518             $runstate One of the motor runstate constants.
519             $tacholimit Number of rotation ticks the motor should turn before it stops.
520              
521             =cut
522              
523             sub set_output_state
524             {
525 0     0 1 0 my ($this,$needsret,$port,$power,$mode,$regulation,$turnratio,$runstate,$tacholimit) = @_;
526 0         0 my $ret = $this->_do_cmd(
527             pack("CCCcCCcCV",$needsret,$NXT_SET_OUTPUT_STATE,$port,$power,$mode,$regulation,$turnratio,$runstate,$tacholimit),
528             $needsret
529             );
530              
531 0 0       0 return if $needsret==$NXT_NORET;
532            
533 0         0 $this->_parse_generic_ret($ret);
534             }
535              
536             =head2 set_input_mode
537              
538             $nxt->set_input_mode($NXT_NORET,$port,$sensor_type,$sensor_mode)
539              
540             Configure the input mode of a sensor port.
541              
542             $port A sensor port constant.
543             $sensor_type A sensor type constant.
544             $sensor_mode A sensor mode constant.
545              
546             =cut
547              
548             sub set_input_mode
549             {
550 0     0 1 0 my ($this,$needsret,$port,$sensor_type,$sensor_mode) = @_;
551              
552 0         0 my $ret = $this->_do_cmd(
553             pack("CCCCC",$needsret,$NXT_SET_INPUT_MODE,$port,$sensor_type,$sensor_mode),
554             $needsret
555             );
556              
557 0 0       0 return if $needsret==$NXT_NORET;
558            
559 0         0 $this->_parse_generic_ret($ret);
560             }
561              
562             =head2 get_output_state
563              
564             $ret = $nxt->get_output_state($NXT_RET,$port)
565              
566             Retrieve the current ouput state of $port.
567              
568             $ret A hashref containing the port attributes.
569              
570             =cut
571              
572             sub get_output_state
573             {
574 0     0 1 0 my ($this,$needsret,$port) = @_;
575 0         0 my $ret = $this->_do_cmd(
576             pack("CCC",$needsret,$NXT_GET_OUTPUT_STATE,$port),
577             $needsret
578             );
579              
580 0 0       0 return if $needsret==$NXT_NORET;
581            
582 0         0 $this->_parse_get_output_state($ret);
583             }
584              
585             =head2 get_input_values
586              
587             $ret = $nxt->get_input_values($NXT_RET,$port)
588              
589             Retrieve the current sensor input values of $port.
590              
591             $ret A hashref containing the sensor value attributes.
592              
593             =cut
594              
595             sub get_input_values
596             {
597 0     0 1 0 my ($this,$needsret,$port) = @_;
598 0         0 my $ret = $this->_do_cmd(
599             pack("CCC",$needsret,$NXT_GET_INPUT_VALUES,$port),
600             $needsret
601             );
602              
603 0 0       0 return if $needsret==$NXT_NORET;
604 0         0 $this->_parse_get_input_values($ret);
605             }
606              
607             =head2 reset_input_scaled_value
608              
609             $nxt->reset_input_scaled_value($NXT_NORET,$port)
610              
611             If your sensor port is using scaled values, reset them.
612              
613             =cut
614              
615             sub reset_input_scaled_value
616             {
617 0     0 1 0 my ($this,$needsret,$port) = @_;
618 0         0 my $ret = $this->_do_cmd(
619             pack("CCC",$needsret,$NXT_RESET_SCALED_INPUT_VALUE,$port),
620             $needsret
621             );
622              
623 0 0       0 return if $needsret==$NXT_NORET;
624 0         0 $this->_parse_generic_ret($ret);
625             }
626              
627             =head2 message_write
628              
629             $nxt->message_write($NXT_NORET,$mailbox,$message)
630              
631             Write a $message to local mailbox# $mailbox.
632              
633             =cut
634              
635             sub message_write
636             {
637 0     0 1 0 my ($this,$needsret,$mailbox,$message) = @_;
638 0         0 my $mlen = 1+length($message);
639              
640 0         0 my $ret = $this->_do_cmd(
641             pack("CCCCZ[$mlen]",$needsret,$NXT_MESSAGE_WRITE,$mailbox,$mlen,$message),
642             $needsret
643             );
644              
645 0 0       0 return if $needsret==$NXT_NORET;
646 0         0 $this->_parse_generic_ret($ret);
647             }
648              
649             =head2 reset_motor_position
650              
651             $nxt->reset_motor_position($NXT_NORET,$port,$relative)
652              
653             TODO: Specifics
654              
655             =cut
656              
657             sub reset_motor_position
658             {
659 0     0 1 0 my ($this,$needsret,$port,$relative) = @_;
660              
661 0         0 my $ret = $this->_do_cmd(
662             pack("CCCC",$needsret,$NXT_RESET_MOTOR_POSITION,$port,$relative),
663             $needsret
664             );
665              
666 0 0       0 return if $needsret==$NXT_NORET;
667 0         0 $this->_parse_generic_ret($ret);
668             }
669              
670             =head2 get_battery_level
671              
672             $ret = $nxt->get_battery_level($NXT_RET)
673              
674             $ret A hash containing battery attributes - voltage in MV
675              
676             =cut
677              
678             sub get_battery_level
679             {
680 0     0 1 0 my ($this,$needsret) = @_;
681              
682 0         0 my $ret = $this->_do_cmd(
683             pack("CC",$needsret,$NXT_GET_BATTERY_LEVEL),
684             $needsret
685             );
686              
687 0 0       0 return if $needsret==$NXT_NORET;
688 0         0 $this->_parse_get_battery_level($ret);
689             }
690              
691             =head2 set_stop_sound_playback
692              
693             $nxt->set_stop_sound_playback($NXT_NORET)
694              
695             Stops the currently playing sound file
696              
697             =cut
698              
699             sub set_stop_sound_playback
700             {
701 0     0 1 0 my ($this,$needsret) = @_;
702              
703 0         0 my $ret = $this->_do_cmd(
704             pack("CC",$needsret,$NXT_STOP_SOUND_PLAYBACK),
705             $needsret
706             );
707              
708 0 0       0 return if $needsret==$NXT_NORET;
709 0         0 $this->_parse_generic_ret($ret);
710             }
711              
712             =head2 keep_alive
713              
714             $nxt->keep_alive($NXT_NORET)
715              
716             Prevents the NXT from entering sleep mode
717              
718             =cut
719              
720             sub keep_alive
721             {
722 0     0 1 0 my ($this,$needsret) = @_;
723            
724 0         0 my $ret = $this->_do_cmd(
725             pack("CC",$needsret,$NXT_KEEP_ALIVE),
726             $needsret
727             );
728              
729 0 0       0 return if $needsret==$NXT_NORET;
730 0         0 $this->_parse_generic_ret($ret);
731             }
732              
733             =head2 ls_get_status
734              
735             $nxt->ls_get_status($NXT_RET,$port)
736              
737             Determine whether there is data ready to read from an I2C digital sensor.
738             NOTE: The Ultrasonic Range sensor is such a sensor and must be interfaced via the ls* commands
739              
740             =cut
741              
742             sub ls_get_status
743             {
744 0     0 1 0 my ($this,$needsret,$port) = @_;
745              
746 0         0 my $ret = $this->_do_cmd(
747             pack("CCC",$needsret,$NXT_LSGET_STATUS,$port),
748             $needsret
749             );
750              
751 0 0       0 return if $needsret==$NXT_NORET;
752 0         0 $this->_parse_ls_get_status($ret);
753             }
754              
755             =head2 ls_write
756              
757             $nxt->ls_write($NXT_RET,$port,$txlen,$rxlen,$txdata)
758              
759             Send an I2C command to a digital I2C sensor.
760              
761             $port The sensor port of the I2C sensor
762             $txlen The length of $txdata
763             $rxlen The length of the expected response (sensor/command specific)
764             $txdata The I2C command you wish to send in packed byte format.
765             NOTE: The NXT will suffix the command with a status byte R+0x03,
766             but you dont need to worry about this. Do not send it as part of
767             $txdata though - it will result in a bus error.
768              
769             NOTE: The Ultrasonic Range sensor is such a sensor and must be interfaced via the ls* commands
770              
771             =cut
772              
773             sub ls_write
774             {
775 0     0 1 0 my ($this,$needsret,$port,$txlen,$rxlen,$txdata) = @_;
776              
777 0         0 my $ret = $this->_do_cmd(
778             pack("CCCCC",$needsret,$NXT_LSWRITE,$port,$txlen,$rxlen).
779             $txdata,
780             $needsret
781             );
782              
783 0 0       0 return if $needsret==$NXT_NORET;
784 0         0 $this->_parse_generic_ret($ret);
785             }
786              
787             =head2 ls_read
788              
789             $nxt->ls_read($NXT_RET,$port)
790              
791             Read a pending I2C message from a digital I2C device.
792              
793             =cut
794              
795             sub ls_read
796             {
797 0     0 1 0 my ($this,$needsret,$port) = @_;
798              
799 0         0 my $ret = $this->_do_cmd(
800             pack("CCC",$needsret,$NXT_LSREAD,$port),
801             $needsret
802             );
803              
804 0 0       0 return if $needsret==$NXT_NORET;
805 0         0 $this->_parse_ls_read($ret);
806             }
807              
808             =head2 ls_request_response
809              
810             $nxt->ls_request_response($port,$txlen,$rxlen,$txdata)
811              
812             Higher level I2C request-response routine. Loops to ensure data is ready
813             to read from the sensor and returns the result.
814              
815             =cut
816              
817             sub ls_request_response
818             {
819 0     0 1 0 my ($this,$port,$txlen,$rxlen,$data) = @_;
820              
821 0         0 $this->ls_write($NXT_RET,$port,$txlen,$rxlen,$data);
822              
823 0         0 my $lsstat;
824              
825 0         0 do{ $lsstat=$this->ls_get_status($NXT_RET,$port); } while ( $lsstat->{bytesready} < $rxlen );
  0         0  
826              
827 0         0 $this->ls_read($NXT_RET,$port);
828             }
829              
830             =head2 get_current_program_name
831              
832             $ret = $nxt->get_current_program_name($NXT_RET)
833              
834             $ret is a hash containing info on the current;y running program.
835              
836             =cut
837              
838             sub get_current_program_name
839             {
840 0     0 1 0 my ($this,$needsret) = @_;
841              
842 0         0 my $ret = $this->_do_cmd(
843             pack("CC",$needsret,$NXT_GET_CURRENT_PROGRAM_NAME),
844             $needsret
845             );
846              
847 0 0       0 return if $needsret==$NXT_NORET;
848 0         0 $this->_parse_get_current_progran_name($ret);
849             }
850              
851             =head2 message_read
852              
853             $ret = $nxt->message_read($NXT_RET,$remotebox,$localbox,$remove)
854              
855             Read a message.
856              
857             =cut
858              
859             sub message_read
860             {
861 0     0 1 0 my ($this,$needsret,$remotebox,$localbox,$remove) = @_;
862            
863 0         0 my $ret = $this->_do_cmd(
864             pack("CCCCC",$needsret,$NXT_MESSAGE_READ,$remotebox,$localbox,$remove),
865             $needsret
866             );
867              
868 0 0       0 return if $needsret==$NXT_NORET;
869 0         0 $this->_parse_message_read($ret);
870             }
871              
872             =head1 NXT SYSTEM COMMANDS
873              
874             Caution. Use these only if you know what you're doing.
875              
876             If you know what you're doing, these methods can be very useful. If you don't know
877             what you're doing, you will probably end up with a dead robot. Beware. Seriously.
878              
879             NOTE: Every system command requires a return value, so there's no need to pass NXT_RET.
880              
881             =head2 sys_open_read
882              
883             $ret = $nxt->sys_open_read($filename);
884              
885             Opens a system file for reading, returns a file descriptor.
886              
887             =cut
888              
889             sub sys_open_read
890             {
891 0     0 1 0 my ($this,$file) = @_;
892              
893 0         0 my $strlen = 1+length($file);
894 0         0 my $ret = $this->_do_cmd(
895             pack("CCZ[$strlen]",$NXT_SYSOP,$NXT_SYS_OPEN_READ,$file),
896             $NXT_RET
897             );
898              
899 0         0 my ($len,$rval,$status,$fd,$file_size) = unpack( "vvCCV", $ret );
900              
901             return
902             {
903 0 0       0 'status' => $status,
904             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
905             'fd' => $fd,
906             'file_size' => $file_size
907             };
908             }
909              
910             =head2 sys_open_write
911              
912             $ret = $nxt->sys_open_write($filename,$size);
913              
914             Opens (creates?) a system file for writing, returns a file descriptor. You must specify
915             the size of the file you wish to write to.
916              
917             =cut
918              
919             sub sys_open_write
920             {
921 0     0 1 0 my ($this,$file,$size) = @_;
922              
923 0         0 my $strlen = 1+length($file);
924 0         0 my $ret = $this->_do_cmd(
925             pack("CCZ[$strlen]V",$NXT_SYSOP,$NXT_SYS_OPEN_WRITE,$file,$size),
926             $NXT_RET
927             );
928              
929 0         0 my ($len,$rval,$status,$fd) = unpack( "vvCC", $ret );
930              
931             return
932             {
933 0 0       0 'status' => $status,
934             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
935             'fd' => $fd
936             };
937             }
938              
939             =head2 sys_read
940              
941             $ret = $nxt->sys_read($fd,$nbytes);
942              
943             Reads $nbytes from open file descriptor $fd. I believe $nbytes should be < 60 when using USB.
944              
945             =cut
946              
947             sub sys_read
948             {
949 0     0 1 0 my ($this,$fd,$nbytes) = @_;
950              
951 0         0 my $ret = $this->_do_cmd(
952             pack("CCCv",$NXT_SYSOP,$NXT_SYS_READ,$fd,$nbytes),
953             $NXT_RET
954             );
955              
956 0         0 my ($len,$rval,$status,$nread,$data) = unpack( "vvCvC*", $ret );
957              
958             return
959             {
960 0 0       0 'status' => $status,
961             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
962             'nread' => $nread,
963             'data' => $data
964             };
965             }
966              
967             =head2 sys_write
968              
969             $ret = $nxt->sys_write($fd,$data);
970              
971             Writes $data to open file descriptor $fd.
972              
973             =cut
974              
975             sub sys_write
976             {
977 0     0 1 0 my ($this,$fd,$data) = @_;
978              
979 0         0 my $dlen = 1+length($data);
980 0         0 my $ret = $this->_do_cmd(
981             pack("CCCC[$dlen]",$NXT_SYSOP,$NXT_SYS_WRITE,$fd,$data),
982             $NXT_RET
983             );
984              
985 0         0 my ($len,$rval,$status,$nfd,$nwritten) = unpack( "vvCCv", $ret );
986              
987             return
988             {
989 0 0       0 'status' => $status,
990             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
991             'nwritten' => $nwritten,
992             'fd' => $nfd
993             };
994             }
995              
996             =head2 sys_close
997              
998             $ret = $nxt->sys_close($fd);
999              
1000             Closes the file descriptor $fd.
1001              
1002             =cut
1003              
1004             sub sys_close
1005             {
1006 0     0 1 0 my ($this,$fd) = @_;
1007              
1008 0         0 my $ret = $this->_do_cmd(
1009             pack("CCC",$NXT_SYSOP,$NXT_SYS_CLOSE,$fd),
1010             $NXT_RET
1011             );
1012              
1013 0         0 my ($len,$rval,$status,$nfd) = unpack( "vvCC", $ret );
1014              
1015             return
1016             {
1017 0 0       0 'status' => $status,
1018             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1019             'fd' => $nfd
1020             };
1021             }
1022              
1023             =head2 sys_delete
1024              
1025             $ret = $nxt->sys_delete($filename);
1026              
1027             Deletes a file on the NXT with name $filename.
1028              
1029             =cut
1030              
1031             sub sys_delete
1032             {
1033 0     0 1 0 my ($this,$file) = @_;
1034              
1035 0         0 my $strlen = 1+length($file);
1036 0         0 my $ret = $this->_do_cmd(
1037             pack("CCZ[$strlen]",$NXT_SYSOP,$NXT_SYS_DELETE,$file),
1038             $NXT_RET
1039             );
1040              
1041 0         0 my ($len,$rval,$status,$nfile) = unpack( "vvCZ[$strlen]", $ret );
1042              
1043             return
1044             {
1045 0 0       0 'status' => $status,
1046             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1047             'file' => $nfile
1048             };
1049             }
1050              
1051              
1052             =head2 sys_find_first
1053              
1054             $ret = $nxt->sys_find_first($search);
1055              
1056             Finds a file on the system with filename $search. Searches may use wildcards: *.*, *.txt, etc.
1057             This command will return statstr=>"File not found" on failure. The filehandle MUST be closed
1058             when finished with the query.
1059              
1060             =cut
1061              
1062             sub sys_find_first
1063             {
1064 0     0 1 0 my ($this,$file) = @_;
1065              
1066 0         0 my $strlen = 1+length($file);
1067 0         0 my $ret = $this->_do_cmd(
1068             pack("CCZ[$strlen]",$NXT_SYSOP,$NXT_SYS_FIND_FIRST,$file),
1069             $NXT_RET
1070             );
1071              
1072 0         0 my ($len,$rval,$status,$fd,$fname,$fsize) = unpack( "vvCCZ[20]V", $ret );
1073              
1074             return
1075             {
1076 0 0       0 'status' => $status,
1077             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1078             'fd' => $fd,
1079             'file' => $fname,
1080             'file_size' => $fsize
1081             };
1082             }
1083              
1084             =head2 sys_find_next
1085              
1086             $ret = $nxt->sys_find_next($fd);
1087              
1088             Finds the next matching file on the system from sys_find_first.
1089             $fd is the descriptor returned from sys_find_first
1090              
1091             =cut
1092              
1093             sub sys_find_next
1094             {
1095 0     0 1 0 my ($this,$fd) = @_;
1096              
1097 0         0 my $ret = $this->_do_cmd(
1098             pack("CCC",$NXT_SYSOP,$NXT_SYS_FIND_NEXT,$fd),
1099             $NXT_RET
1100             );
1101              
1102 0         0 my ($len,$rval,$status,$nfd,$fname,$fsize) = unpack( "vvCCZ[19]V", $ret );
1103              
1104             return
1105             {
1106 0 0       0 'status' => $status,
1107             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1108             'fd' => $nfd,
1109             'file' => $fname,
1110             'file_size' => $fsize
1111             };
1112             }
1113              
1114             =head2 sys_get_firmware_version
1115              
1116             $ret = $nxt->sys_get_firmware_version();
1117              
1118             Does what it says.
1119              
1120             =cut
1121              
1122             sub sys_get_firmware_version
1123             {
1124 0     0 1 0 my ($this) = @_;
1125              
1126 0         0 my $ret = $this->_do_cmd(
1127             pack("CC",$NXT_SYSOP,$NXT_SYS_GET_FIRMWARE_VERSION),
1128             $NXT_RET
1129             );
1130              
1131 0         0 my ($len,$rval,$status,$pminor,$pmajor,$fminor,$fmajor) = unpack( "vvCCCC", $ret );
1132              
1133             return
1134             {
1135 0 0       0 'status' => $status,
1136             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1137             'protocol_version' => "$pmajor.$pminor",
1138             'firmware_version' => "$fmajor.$fminor"
1139             };
1140             }
1141              
1142             =head2 sys_open_write_linear
1143              
1144             $ret = $nxt->sys_open_write_linear($filename,$size);
1145              
1146             Opens a system file for writing (raw data mode? update me... ), returns a file descriptor. You must specify
1147             the size of the file you wish to write to.
1148              
1149             =cut
1150              
1151             sub sys_open_write_linear
1152             {
1153 0     0 1 0 my ($this,$file,$size) = @_;
1154              
1155 0         0 my $strlen = 1+length($file);
1156 0         0 my $ret = $this->_do_cmd(
1157             pack("CCZ[$strlen]V",$NXT_SYSOP,$NXT_SYS_OPEN_WRITE_LINEAR,$file,$size),
1158             $NXT_RET
1159             );
1160              
1161 0         0 my ($len,$rval,$status,$fd) = unpack( "vvCC", $ret );
1162              
1163             return
1164             {
1165 0 0       0 'status' => $status,
1166             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1167             'fd' => $fd
1168             };
1169             }
1170              
1171             =head2 sys_open_read_linear
1172              
1173             $ret = $nxt->sys_open_read_linear($filename);
1174              
1175             Opens a system file for reading, returns the memory address of the file (NOT FD).
1176              
1177             =cut
1178              
1179             sub sys_open_read_linear
1180             {
1181 0     0 1 0 my ($this,$file) = @_;
1182              
1183 0         0 my $strlen = 1+length($file);
1184 0         0 my $ret = $this->_do_cmd(
1185             pack("CCZ[$strlen]",$NXT_SYSOP,$NXT_SYS_OPEN_READ_LINEAR,$file),
1186             $NXT_RET
1187             );
1188              
1189 0         0 my ($len,$rval,$status,$ptr) = unpack( "vvCV", $ret );
1190              
1191             return
1192             {
1193 0 0       0 'status' => $status,
1194             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1195             'address' => $ptr
1196             };
1197             }
1198              
1199              
1200             =head2 sys_open_write_data
1201              
1202             $ret = $nxt->sys_open_write_data($filename,$size);
1203              
1204             Opens a system file for writing (data mode? update me... ), returns a file descriptor. You must specify
1205             the size of the file you wish to write to.
1206              
1207             =cut
1208              
1209             sub sys_open_write_data
1210             {
1211 0     0 1 0 my ($this,$file,$size) = @_;
1212              
1213 0         0 my $strlen = 1+length($file);
1214 0         0 my $ret = $this->_do_cmd(
1215             pack("CCZ[$strlen]V",$NXT_SYSOP,$NXT_SYS_OPEN_WRITE_DATA,$file,$size),
1216             $NXT_RET
1217             );
1218              
1219 0         0 my ($len,$rval,$status,$fd) = unpack( "vvCC", $ret );
1220              
1221             return
1222             {
1223 0 0       0 'status' => $status,
1224             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1225             'fd' => $fd
1226             };
1227             }
1228              
1229             =head2 sys_open_append_data
1230              
1231             $ret = $nxt->sys_open_append_data($filename);
1232              
1233             Opens a system file for appendinf (data mode?), returns the fd and available size.
1234              
1235             =cut
1236              
1237             sub sys_open_append_data
1238             {
1239 0     0 1 0 my ($this,$file) = @_;
1240              
1241 0         0 my $strlen = 1+length($file);
1242 0         0 my $ret = $this->_do_cmd(
1243             pack("CCZ[$strlen]",$NXT_SYSOP,$NXT_SYS_OPEN_APPEND_DATA,$file),
1244             $NXT_RET
1245             );
1246              
1247 0         0 my ($len,$rval,$status,$fd,$size) = unpack( "vvCCV", $ret );
1248              
1249             return
1250             {
1251 0 0       0 'status' => $status,
1252             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1253             'fd' => $fd,
1254             'size' => $size
1255             };
1256             }
1257              
1258              
1259              
1260             =head2 sys_boot
1261              
1262             $ret = $nxt->sys_boot()
1263              
1264             Boot the NXT. DO NOT USE UNLESS YOU **REALLY** KNOW WHAT YOU'RE DOING!!! YOU CAN BREAK YOUR NXT!!! YOU HAVE BEEN WARNED.
1265            
1266             NOTE: USB Interface ONLY!
1267              
1268             =cut
1269              
1270             sub sys_boot
1271             {
1272 0     0 1 0 my ($this) = @_;
1273            
1274 0         0 my $file = "Let's dance: SAMBA";
1275 0         0 my $strlen = 1+length($file);
1276 0         0 my $ret = $this->_do_cmd(
1277             pack("CCZ[$strlen]",$NXT_SYSOP,$NXT_SYS_BOOT,$file),
1278             $NXT_RET
1279             );
1280              
1281 0         0 my ($len,$rval,$status,$msg) = unpack( "vvCA[3]", $ret );
1282              
1283             return
1284             {
1285 0 0       0 'status' => $status,
1286             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1287             'message' => $msg
1288             };
1289            
1290             }
1291              
1292              
1293             =head2 sys_set_brick_name
1294              
1295             $ret = $nxt->sys_set_brick_name($filename);
1296              
1297             Does what it says. I believe this defaults to NXT and is used in Bluetooth identification.
1298              
1299             =cut
1300              
1301             sub sys_set_brick_name
1302             {
1303 0     0 1 0 my ($this,$name) = @_;
1304              
1305 0         0 my $strlen = 1+length($name);
1306 0         0 my $ret = $this->_do_cmd(
1307             pack("CCZ[$strlen]",$NXT_SYSOP,$NXT_SYS_SET_BRICK_NAME,$name),
1308             $NXT_RET
1309             );
1310              
1311 0         0 $this->_parse_generic_ret($ret);
1312             }
1313              
1314             =head2 sys_get_device_info
1315              
1316             $ret = $nxt->sys_get_device_info();
1317              
1318             Returns various informations about the NXT including Bluetooth info and available flash.
1319              
1320             =cut
1321              
1322             sub sys_get_device_info
1323             {
1324 0     0 1 0 my ($this) = @_;
1325              
1326 0         0 my $ret = $this->_do_cmd(
1327             pack("CC",$NXT_SYSOP,$NXT_SYS_GET_DEVICE_INFO),
1328             $NXT_RET
1329             );
1330              
1331 0         0 my ($len,$rval,$status,$name,$b1,$b2,$b3,$b4,$b5,$b6,$btstrength,$flash) = unpack( "vvCZ[15]"."CCCCCC"."VV", $ret );
1332              
1333             return
1334             {
1335 0         0 'status' => $status,
1336             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1337             'name' => $name,
1338 0 0       0 'btaddr' => join ':', map{ sprintf("%x",$_) } ($b1,$b2,$b3,$b4,$b5,$b6),
1339             'btstrength' => $btstrength,
1340             'flash_free' => $flash
1341             };
1342             }
1343              
1344             =head2 sys_poll_command_length
1345              
1346             $ret = $nxt->sys_poll_command_length($buffer_number);
1347              
1348             Polls for the number of bytes ready in the command buffer.
1349             $buffer_number = 0x00 for poll buffer
1350             $buffer_number = 0xA1 for the high speed buffer
1351             * I have no idea what this does as of this writing.
1352              
1353             =cut
1354              
1355             sub sys_poll_command_length
1356             {
1357 0     0 1 0 my ($this,$bn) = @_;
1358              
1359 0         0 my $ret = $this->_do_cmd(
1360             pack("CCC",$NXT_SYSOP,$NXT_SYS_POLL_COMMAND_LENGTH,$bn),
1361             $NXT_RET
1362             );
1363              
1364 0         0 my ($len,$rval,$nbn,$status,$bytes) = unpack( "vvCCC", $ret );
1365              
1366             return
1367             {
1368 0 0       0 'status' => $status,
1369             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1370             'buffer_number' => $nbn,
1371             'bytes_ready' => $bytes
1372             };
1373             }
1374              
1375             =head2 sys_poll_command
1376              
1377             $ret = $nxt->sys_poll_command($buffer_number,$command_length);
1378              
1379             Polls the command buffer.
1380             $buffer_number = 0x00 for poll buffer
1381             $buffer_number = 0xA1 for the high speed buffer
1382             * I have no idea what this does as of this writing.
1383              
1384             =cut
1385              
1386             sub sys_poll_command
1387             {
1388 0     0 1 0 my ($this,$bn,$length) = @_;
1389              
1390 0         0 my $ret = $this->_do_cmd(
1391             pack("CCCC",$NXT_SYSOP,$NXT_SYS_POLL_COMMAND_LENGTH,$bn,$length),
1392             $NXT_RET
1393             );
1394              
1395 0         0 my ($len,$rval,$nbn,$status,$bytes,@command) = unpack( "vvCCCC*", $ret );
1396              
1397             return
1398             {
1399 0 0       0 'status' => $status,
1400             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1401             'buffer_number' => $nbn,
1402             'length' => $bytes,
1403             'command' => join '', @command
1404             };
1405             }
1406              
1407             =head2 sys_bluetooth_factory_reset
1408              
1409             $ret = $nxt->sys_bluetooth_factory_reset($filename);
1410              
1411             Resets the on-board bluetooth chip to factory defaults.
1412              
1413             =cut
1414              
1415             sub sys_bluetooth_factory_reset
1416             {
1417 0     0 1 0 my ($this) = @_;
1418              
1419 0         0 my $ret = $this->_do_cmd(
1420             pack("CC",$NXT_SYSOP,$NXT_SYS_BLUETOOTH_FACTORY_RESET),
1421             $NXT_RET
1422             );
1423              
1424 0         0 $this->_parse_generic_ret($ret);
1425             }
1426              
1427              
1428              
1429             =head1 PRIVATE METHODS
1430              
1431             =head2 _do_cmd
1432              
1433             =cut
1434              
1435             sub _do_cmd
1436             {
1437 0     0   0 my ($this,$msg,$needsret) = @_;
1438              
1439 0         0 my $comm = $this->{comm};
1440 0         0 my $res;
1441              
1442 0 0       0 if ($comm->type eq 'usb')
1443             {
1444 0         0 $res = $comm->do_cmd( $msg, $needsret );
1445              
1446             #parsing functions expect prepended length bytes ala bluetooth
1447 0 0       0 if (defined $res )
1448             {
1449 0         0 $res = pack('v',length($res)).$res;
1450             }
1451             }
1452              
1453 0 0       0 if ($comm->type eq 'blue')
1454             {
1455             #bluetooth comm requires prepended length bytes
1456 0         0 $res = $comm->do_cmd( pack( "v", length($msg) ) . $msg, $needsret );
1457             }
1458              
1459 0         0 $res;
1460             }
1461              
1462              
1463             =head2 _parse_get_output_state
1464              
1465             =cut
1466              
1467             sub _parse_get_output_state
1468             {
1469 0     0   0 my ($this,$ret) = @_;
1470             my
1471             (
1472 0         0 $len,
1473             $rval,
1474             $status,
1475             $port,
1476             $power,
1477             $mode,
1478             $regulation,
1479             $turn_ratio,
1480             $runstate,
1481             $tacho_limit,
1482             $tacho_count,
1483             $block_tacho_count,
1484             $rotation_count
1485             )
1486             = unpack( "vvCCcCCcCVlll", $ret );
1487            
1488             return
1489             {
1490 0 0       0 'status' => $status,
1491             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1492             'port' => $port,
1493             'power' => $power,
1494             'mode' => $mode,
1495             'regulation' => $regulation,
1496             'turn_ratio' => $turn_ratio,
1497             'runstate' => $runstate,
1498             'tacho_limit' => $tacho_limit,
1499             'tacho_count' => $tacho_limit,
1500             'block_tacho_count' => $block_tacho_count,
1501             'rotation_count' => $rotation_count
1502             };
1503             }
1504              
1505             =head2 _parse_get_input_values
1506              
1507             =cut
1508              
1509             sub _parse_get_input_values
1510             {
1511 0     0   0 my ($this,$ret) = @_;
1512             my
1513             (
1514 0         0 $len,
1515             $rval,
1516             $status,
1517             $port,
1518             $valid,
1519             $calibrated,
1520             $sensor_type,
1521             $sensor_mode,
1522             $raw_value,
1523             $normal_value,
1524             $scaled_value,
1525             $calibrated_value
1526             )
1527             = unpack( "vvCCCCCvvss", $ret );
1528              
1529             return
1530             {
1531 0 0       0 'status' => $status,
1532             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1533             'port' => $port,
1534             'valid' => $valid,
1535             'calibrated' => $calibrated,
1536             'sensor_type' => $sensor_type,
1537             'sensor_mode' => $sensor_mode,
1538             'raw_value' => $raw_value,
1539             'normal_value' => $normal_value,
1540             'scaled_value' => $scaled_value,
1541             'calibrated_value' => $calibrated_value # **currently unused**
1542             };
1543             }
1544              
1545             =head2 _parse_get_battery_level
1546              
1547             =cut
1548              
1549             sub _parse_get_battery_level
1550             {
1551 0     0   0 my ($this,$ret)=@_;
1552 0         0 my ($len,$rval,$status,$battery) = unpack( "vvCv", $ret );
1553              
1554             return
1555             {
1556 0 0       0 'status' => $status,
1557             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1558             'battery_mv' => $battery
1559             };
1560             }
1561              
1562             =head2 _parse_ls_get_status
1563              
1564             =cut
1565              
1566             sub _parse_ls_get_status
1567             {
1568 0     0   0 my ($this,$ret)=@_;
1569 0         0 my ($len,$rval,$status,$bytesready) = unpack( "vvCC", $ret );
1570              
1571             return
1572             {
1573 0 0       0 'status' => $status,
1574             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1575             'bytesready' => $bytesready
1576             };
1577             }
1578              
1579             =head2 _parse_ls_read
1580              
1581             =cut
1582              
1583             sub _parse_ls_read
1584             {
1585 0     0   0 my ($this,$ret)=@_;
1586 0         0 my ($len,$rval,$status,$nread,$rxdata) = unpack( "vvCCC[16]", $ret );
1587              
1588             return
1589             {
1590 0 0       0 'status' => $status,
1591             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1592             'length' => $nread,
1593             'data' => $rxdata
1594             };
1595             }
1596              
1597             =head2 _parse_get_current_program_name
1598              
1599             =cut
1600              
1601             sub _parse_get_current_program_name
1602             {
1603 0     0   0 my ($this,$ret)=@_;
1604 0         0 my ($len,$rval,$status,$name) = unpack( "vvC[19]", $ret );
1605              
1606             return
1607             {
1608 0 0       0 'status' => $status,
1609             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1610             'filename' => $name
1611             };
1612             }
1613              
1614             =head2 _parse_message_read
1615              
1616             =cut
1617              
1618             sub _parse_message_read
1619             {
1620 0     0   0 my ($this,$ret) = @_;
1621            
1622 0         0 my ($len,$rval,$status,$localbox,$length,$message) = unpack( "vvCCC[58]", $ret );
1623              
1624             return
1625             {
1626 0 0       0 'status' => $status,
1627             'statstr' => $status>0 ? $error_codes{$status} : 'ok',
1628             'localbox' => $localbox,
1629             'length' => $length,
1630             'message' => $message
1631             };
1632             }
1633              
1634             =head2 _parse_generic_ret
1635              
1636             =cut
1637              
1638             sub _parse_generic_ret
1639             {
1640 0     0   0 my ($this,$ret)=@_;
1641 0         0 my ($len,$rval,$status) = unpack( "vvC", $ret );
1642              
1643             return
1644             {
1645 0 0       0 'status' => $status,
1646             'statstr' => $status ? $error_codes{$status} : 'ok'
1647             };
1648             }
1649              
1650             sub _status_str
1651             {
1652 0     0   0 my $status = shift;
1653 0 0       0 $status>0 ? $error_codes{$status} : 'ok';
1654             }
1655              
1656             =head2 import
1657              
1658             This is a custom import method for supporting
1659             plugins. See L.
1660              
1661             =cut
1662              
1663             sub import {
1664 1     1   12 my $class = shift;
1665 1         14 foreach my $plugin (@_) {
1666 0           $plugin = $class . '::' . $plugin;
1667              
1668             # Skip out if this module is already in @ISA.
1669 0 0         next if (grep { ($_ eq $plugin) ? 1 : () } @ISA);
  0 0          
1670              
1671 0           eval("require $plugin");
1672 0 0         die("Problem loading $plugin: $@") if($@);
1673              
1674 0           push @ISA, $plugin;
1675             }
1676             }
1677              
1678             1;
1679             __END__