File Coverage

blib/lib/HiPi/Interface/Si470N.pm
Criterion Covered Total %
statement 24 279 8.6
branch 0 58 0.0
condition 0 29 0.0
subroutine 8 44 18.1
pod 0 35 0.0
total 32 445 7.1


line stmt bran cond sub pod time code
1             #########################################################################################
2             # Package HiPi::Interface::Si470N
3             # Description : Control Si4701/2/3 via I2C
4             # Copyright : Copyright (c) 2013-2017 Mark Dootson
5             # License : This is free software; you can redistribute it and/or modify it under
6             # the same terms as the Perl 5 programming language system itself.
7             #########################################################################################
8              
9             package HiPi::Interface::Si470N;
10              
11             #########################################################################################
12              
13              
14             # DOES NOT WORK WITH CURRENT I2C DRIVER
15              
16 1     1   1089 use strict;
  1         2  
  1         30  
17 1     1   6 use warnings;
  1         2  
  1         28  
18 1     1   5 use parent qw( HiPi::Interface );
  1         2  
  1         5  
19 1     1   68 use Carp;
  1         4  
  1         53  
20 1     1   6 use HiPi qw( :i2c :si470n :rpi );
  1         2  
  1         347  
21 1     1   9 use HiPi::GPIO;
  1         2  
  1         36  
22 1     1   5 use HiPi::Device::I2C;
  1         12  
  1         96  
23              
24             our $VERSION ='0.81';
25              
26             __PACKAGE__->create_accessors( qw(
27             devicename address
28             _mapped_registers _register_names
29             _register_name_order _datamap
30             sdapin resetpin
31             gpiodev
32             ) );
33              
34             use constant {
35 1         3262 DEVICEID => 0x00,
36             CHIPID => 0x01,
37             POWERCFG => 0x02,
38             CHANNEL => 0x03,
39             SYSCONFIG1 => 0x04,
40             SYSCONFIG2 => 0x05,
41             SYSCONFIG3 => 0x06,
42             TEST1 => 0x07,
43             TEST2 => 0x08,
44             BOOTCONFIG => 0x09,
45             STATUSRSSI => 0x0A,
46             READCHAN => 0x0B,
47             RDSA => 0x0C,
48             RDSB => 0x0D,
49             RDSC => 0x0E,
50             RDSD => 0x0F,
51 1     1   14 };
  1         2  
52              
53             sub new {
54 0     0 0   my ($class, %userparams) = @_;
55            
56 0           my $pi = HiPi::RaspberryPi->new();
57            
58 0 0         my %params = (
59             devicename => ( $pi->board_type == RPI_BOARD_TYPE_1 ) ? '/dev/i2c-0' : '/dev/i2c-1',
60             address => 0x10,
61             device => undef,
62             sdapin => I2C_SDA,
63             );
64            
65             # get user params
66            
67 0           foreach my $key( keys (%userparams) ) {
68 0           $params{$key} = $userparams{$key};
69             }
70            
71 0 0         unless( defined($params{resetpin}) ) {
72 0           croak qq(you must connect a reset pin to the device and pass the GPIO number to the constructor as param 'resetpin');
73             }
74            
75 0           $params{gpiodev} = HiPi::GPIO->new;
76             $params{device} ||= HiPi::Device::I2C->new(
77             devicename => $params{devicename},
78 0   0       busmode => 'i2c',
79             );
80            
81 0           my $self = $class->SUPER::new(%params);
82            
83 0           $self->_init();
84            
85 0 0         unless( $self->device->check_address( $self->address ) ) {
86 0           $self->reset;
87             } else {
88 0           $self->device->select_address( $self->address );
89 0           $self->read_registers;
90             }
91            
92 0           return $self;
93             }
94              
95             sub _init {
96 0     0     my $self = shift;
97            
98             # set up register names
99            
100 0           my $regnames = {
101             DEVICEID => 0x00,
102             CHIPID => 0x01,
103             POWERCFG => 0x02,
104             CHANNEL => 0x03,
105             SYSCONFIG1 => 0x04,
106             SYSCONFIG2 => 0x05,
107             SYSCONFIG3 => 0x06,
108             TEST1 => 0x07,
109             TEST2 => 0x08,
110             BOOTCONFIG => 0x09,
111             STATUSRSSI => 0x0A,
112             READCHAN => 0x0B,
113             RDSA => 0x0C,
114             RDSB => 0x0D,
115             RDSC => 0x0E,
116             RDSD => 0x0F,
117             };
118            
119 0           $self->_register_names( $regnames );
120            
121             # and name order
122            
123 0           my @nameorder = qw(
124             DEVICEID
125             CHIPID
126             POWERCFG
127             CHANNEL
128             SYSCONFIG1
129             SYSCONFIG2
130             SYSCONFIG3
131             TEST1
132             TEST2
133             BOOTCONFIG
134             STATUSRSSI
135             READCHAN
136             RDSA
137             RDSB
138             RDSC
139             RDSD
140             );
141            
142 0           $self->_register_name_order( \@nameorder );
143            
144             # configure the data items
145            
146 0           my $datamap = {
147             # DEVICEID
148             PN => { word => DEVICEID , shiftbits => [ 0, 12, 4 ] },
149             MFGID => { word => DEVICEID , shiftbits => [ 4, 0, 12 ] },
150            
151             # CHIPID
152             REV => { word => CHIPID , shiftbits => [ 0, 10, 6 ] },
153             DEV => { word => CHIPID , shiftbits => [ 6, 6, 4 ] },
154             FIRMWARE => { word => CHIPID , shiftbits => [ 10, 0, 6 ] },
155            
156             # POWERCFG
157             DSMUTE => { word => POWERCFG , shiftbits => [ 0, 15, 1 ] },
158             DMUTE => { word => POWERCFG , shiftbits => [ 1, 14, 1 ] },
159             MONO => { word => POWERCFG , shiftbits => [ 2, 13, 1 ] },
160             # RESERVED => { word => POWERCFG , shiftbits => [ 3, 12, 1 ] },
161             RDSM => { word => POWERCFG , shiftbits => [ 4, 11, 1 ] },
162             SKMODE => { word => POWERCFG , shiftbits => [ 5, 10, 1 ] },
163             SEEKUP => { word => POWERCFG , shiftbits => [ 6, 9, 1 ] },
164             SEEK => { word => POWERCFG , shiftbits => [ 7, 8, 1 ] },
165             # RESERVED => { word => POWERCFG , shiftbits => [ 8, 7, 1 ] },
166             DISABLE => { word => POWERCFG , shiftbits => [ 9, 6, 1 ] },
167             # RESERVED => { word => POWERCFG , shiftbits => [ 10, 1, 5 ] },
168             ENABLE => { word => POWERCFG , shiftbits => [ 15, 0, 1 ] },
169            
170             # CHANNEL
171             TUNE => { word => CHANNEL , shiftbits => [ 0, 15, 1 ] },
172             # RESERVED => { word => CHANNEL , shiftbits => [ 1, 10, 5 ] },
173             CHAN => { word => CHANNEL , shiftbits => [ 6, 0, 10 ] },
174            
175             # SYSCONFIG1
176             RDSIEN => { word => SYSCONFIG1 , shiftbits => [ 0, 15, 1 ] },
177             STCIEN => { word => SYSCONFIG1 , shiftbits => [ 1, 14, 1 ] },
178             # RESERVED => { word => SYSCONFIG1 , shiftbits => [ 2, 13, 1 ] },
179             RDS => { word => SYSCONFIG1 , shiftbits => [ 3, 12, 1 ] },
180             DE => { word => SYSCONFIG1 , shiftbits => [ 4, 11, 1 ] },
181             AGCD => { word => SYSCONFIG1 , shiftbits => [ 5, 10, 1 ] },
182             # RESERVED => { word => SYSCONFIG1 , shiftbits => [ 6, 8, 2 ] },
183             BLNDADJ => { word => SYSCONFIG1 , shiftbits => [ 8, 6, 2 ] },
184             GPIO3 => { word => SYSCONFIG1 , shiftbits => [ 10, 4, 2 ] },
185             GPIO2 => { word => SYSCONFIG1 , shiftbits => [ 12, 2, 2 ] },
186             GPIO1 => { word => SYSCONFIG1 , shiftbits => [ 14 , 0, 2 ] },
187            
188             # SYSCONFIG2
189             SEEKTH => { word => SYSCONFIG2 , shiftbits => [ 0, 8, 8 ] },
190             BAND => { word => SYSCONFIG2 , shiftbits => [ 8, 6, 2 ] },
191             SPACE => { word => SYSCONFIG2 , shiftbits => [ 10, 4, 2 ] },
192             VOLUME => { word => SYSCONFIG2 , shiftbits => [ 12, 0, 4 ] },
193            
194             # SYSCONFIG3
195             SMUTER => { word => SYSCONFIG3 , shiftbits => [ 0, 14, 2 ] },
196             SMUTEA => { word => SYSCONFIG3 , shiftbits => [ 2, 12, 2 ] },
197             # RESERVED => { word => SYSCONFIG3 , shiftbits => [ 4, 9, 3 ] },
198             VOLEXT => { word => SYSCONFIG3 , shiftbits => [ 7, 8, 1 ] },
199             SKSNR => { word => SYSCONFIG3 , shiftbits => [ 8, 4, 4 ] },
200             SKCNT => { word => SYSCONFIG3 , shiftbits => [ 12, 0, 4 ] },
201            
202             # TEST1
203             XOSCEN => { word => TEST1 , shiftbits => [ 0, 15, 1 ] },
204             AHIZEN => { word => TEST1 , shiftbits => [ 1, 14, 1 ] },
205             # RESERVED => { word => TEST1 , shiftbits => [ 2, 0, 14 ] },
206            
207             # STATUSRSSI
208             RDSR => { word => STATUSRSSI , shiftbits => [ 0, 15, 1 ] },
209             STC => { word => STATUSRSSI , shiftbits => [ 1, 14, 1 ] },
210             SFBL => { word => STATUSRSSI , shiftbits => [ 2, 13, 1 ] },
211             AFCRL => { word => STATUSRSSI , shiftbits => [ 3, 12, 1 ] },
212             RDSS => { word => STATUSRSSI , shiftbits => [ 4, 11, 1 ] },
213             BLERA => { word => STATUSRSSI , shiftbits => [ 5, 9, 2 ] },
214             ST => { word => STATUSRSSI , shiftbits => [ 7, 8, 1 ] },
215             RSSI => { word => STATUSRSSI , shiftbits => [ 8, 0, 8 ] },
216            
217             # READCHAN
218             BLERB => { word => READCHAN , shiftbits => [ 0, 14, 2 ] },
219             BLERC => { word => READCHAN , shiftbits => [ 2, 12, 2 ] },
220             BLERD => { word => READCHAN , shiftbits => [ 4, 10, 2 ] },
221             READCHAN => { word => READCHAN , shiftbits => [ 6, 0, 10 ] },
222            
223             };
224            
225 0           $self->_datamap( $datamap );
226            
227 0           return;
228             }
229              
230             sub reset {
231 0     0 0   my $self = shift;
232            
233             # disconnect from i2c device
234 0           $self->device->close;
235 0           $self->device( undef );
236            
237 0           my $rstpin = $self->resetpin;
238 0           my $sdapin = $self->sdapin;
239              
240             # set reset pin and sda pin as output
241 0           $self->gpiodev->set_pin_mode( $rstpin, RPI_MODE_OUTPUT );
242 0           $self->gpiodev->set_pin_mode( $sdapin, RPI_MODE_OUTPUT );
243            
244             # set reset and sda pins low
245            
246 0           $self->gpiodev->set_pin_level( $sdapin, RPI_LOW );
247            
248             # delay
249 0           $self->sleep_seconds( 0.1 );
250            
251 0           $self->gpiodev->set_pin_level( $rstpin, RPI_LOW );
252            
253             # delay
254 0           $self->sleep_seconds( 0.1 );
255            
256             # set reset high
257 0           $self->gpiodev->set_pin_level( $rstpin, RPI_HIGH );
258              
259             # delay
260 0           $self->sleep_seconds( 0.1 );
261              
262             # restore I2C operation
263 0           $self->gpiodev->set_pin_mode( $sdapin, RPI_MODE_ALT0 );
264            
265             # delay
266 0           $self->sleep_seconds( 0.1 );
267            
268 0           $self->device(HiPi::Device::I2C->new( address => $self->address, busmode => 'i2c' ) );
269            
270 0           $self->read_registers;
271 0           $self->set_register(TEST1, 0x8100);
272 0           $self->update_registers( 0.5 );
273            
274             # setup mode
275 0           $self->set_register(POWERCFG, 1);
276            
277             # set for europe
278 0           $self->configure_europe(1);
279            
280             # seek settings
281 0           $self->set_config_value('SEEKTH', 0x19);
282 0           $self->set_config_value('SKSNR', 0x4);
283 0           $self->set_config_value('SKCNT', 0x8);
284            
285 0           $self->update_registers( 0.1 );
286 0           $self->read_registers();
287            
288 0           return;
289             }
290              
291             sub power_off {
292 0     0 0   my $self = shift;
293 0           $self->set_config_value('ENABLE', 1);
294 0           $self->set_config_value('DISABLE', 1);
295 0           $self->set_config_value('RDS', 0);
296            
297 0           $self->update_registers( 0.1 );
298             }
299              
300             sub power_on {
301 0     0 0   my $self = shift;
302 0           $self->set_config_value('ENABLE', 1);
303 0           $self->update_registers( 0.1 );
304             }
305              
306             sub name_to_register {
307 0     0 0   my($self, $rname) = @_;
308 0   0       $rname //= 'UNKNOWN';
309 0 0         if( exists($self->_register_names->{$rname}) ) {
310 0           return $self->_register_names->{$rname};
311             } else {
312 0           carp qq(register name $rname is unknown);
313 0           return undef;
314             }
315             }
316              
317             sub register_to_name {
318 0     0 0   my( $self, $register ) = @_;
319 0   0       $register //= -1;
320 0 0 0       return 'UNKNOWN' if(( $register < 0 ) || ($register > 15));
321 0           return $self->_register_name_order->[$register];
322             }
323              
324             sub read_registers {
325 0     0 0   my($self) = @_;
326            
327 0           my @bytes = $self->device->bus_read( undef, 32 );
328            
329             # change 32 bytes into 16 16 bit words
330 0           my @words = ();
331 0           for ( my $i = 0; $i < @bytes; $i += 2 ) {
332 0           push @words, ( $bytes[$i] << 8 ) + $bytes[$i + 1];
333             }
334            
335             # map to correct write order
336            
337 0           my @mappedwords = ();
338 0           for ( my $i = 6; $i < 16; $i ++ ) {
339 0           $mappedwords[$i - 6] = $words[$i];
340             }
341 0           for ( my $i = 0; $i < 6; $i ++ ) {
342 0           $mappedwords[$i + 10] = $words[$i];
343             }
344            
345 0           $self->_mapped_registers( \@mappedwords );
346            
347 0 0         return ( wantarray ) ? @{$self->_mapped_registers } : 1;
  0            
348             }
349              
350             sub write_registers {
351 0     0 0   my($self) = @_;
352 0           my $regvals = $self->_mapped_registers;
353 0 0 0       return unless( $regvals && ref( $regvals ) eq 'ARRAY');
354            
355 0           my @bytes = ();
356            
357             # write words 2 to 7
358 0           for ( my $i = 2; $i < 8; $i ++) {
359 0           my $high = $regvals->[$i] >> 8;
360 0           my $low = $regvals->[$i] & 0xFF;
361 0           push @bytes, ( $high, $low );
362             }
363            
364 0           my $rval = $self->device->bus_write( @bytes );
365 0           return $rval;
366             }
367              
368             sub update_registers {
369 0     0 0   my($self, $delay) = @_;
370 0   0       $delay ||= 0.1;
371 0           $self->write_registers();
372 0           $self->sleep_seconds( $delay );
373 0           $self->read_registers;
374 0           return 1;
375             }
376              
377             sub set_config_value {
378 0     0 0   my( $self, $valuename, $newvalue ) = @_;
379 0   0       $valuename //= 'UNKNOWN';
380 0   0       $newvalue ||= 0;
381 0           my $config = $self->_datamap->{$valuename};
382 0 0         unless( $config ) {
383 0           carp qq(unknownvalue $valuename);
384 0           return undef;
385             }
386 0           my $register = $config->{word};
387 0           my $wordname = $self->register_to_name( $register );
388 0           my $currentword = $self->get_register($register);
389              
390 0           my( $bitsbefore, $bitsafter, $bitlen ) = @{ $config->{shiftbits} };
  0            
391            
392 0           my $mask = ( (2 ** $bitlen) -1 ) << $bitsafter;
393            
394 0           my $currentvalue = ($currentword & $mask) >> $bitsafter;
395            
396 0 0         return $currentvalue if $newvalue == $currentvalue;
397            
398 0           my $newbits = $newvalue << $bitsafter;
399 0           my $newword = ($currentword & ~$mask) | ($newbits & $mask);
400            
401 0           $self->set_register($register, $newword);
402 0           return $newvalue;
403             }
404              
405             sub get_word_value {
406 0     0 0   my($self, $wordname) = @_;
407 0           my $register = $self->name_to_register( $wordname );
408 0           my $word = $self->get_register($register);
409 0           return $word;
410             }
411              
412             sub get_config_value {
413 0     0 0   my($self, $valuename) = @_;
414 0   0       $valuename //= 'UNKNOWN';
415 0           my $config = $self->_datamap->{$valuename};
416 0 0         unless( $config ) {
417 0           carp qq(unknownvalue $valuename);
418 0           return undef;
419             }
420 0           my $currentword = $self->get_register($config->{word});
421 0           my( $bitsbefore, $bitsafter, $bitlen ) = @{ $config->{shiftbits} };
  0            
422            
423 0           my $mask = ( (2 ** $bitlen) -1 ) << $bitsafter;
424 0           my $currentvalue = ($currentword & $mask) >> $bitsafter;
425 0           return $currentvalue;
426             }
427              
428             sub configure_europe {
429 0     0 0   my($self, $skipwrite) = @_;
430 0           $self->set_config_value('DE', 1);
431 0           $self->set_config_value('BAND', 0);
432 0           $self->set_config_value('SPACE', 1);
433 0 0         $self->update_registers( 0.1 ) unless $skipwrite;
434             }
435              
436             sub configure_japan {
437 0     0 0   my($self, $skipwrite) = @_;
438 0           $self->set_config_value('DE', 1);
439 0           $self->set_config_value('BAND', 2);
440 0           $self->set_config_value('SPACE', 1);
441 0 0         $self->update_registers( 0.1 ) unless $skipwrite;
442             }
443              
444             sub configure_japan_wide {
445 0     0 0   my($self, $skipwrite) = @_;
446 0           $self->set_config_value('DE', 1);
447 0           $self->set_config_value('BAND', 1);
448 0           $self->set_config_value('SPACE', 1);
449 0 0         $self->update_registers( 0.1 ) unless $skipwrite;
450             }
451              
452             sub configure_usa {
453 0     0 0   my($self, $skipwrite) = @_;
454 0           $self->set_config_value('DE', 0);
455 0           $self->set_config_value('BAND', 0);
456 0           $self->set_config_value('SPACE', 0);
457 0 0         $self->update_registers( 0.1 ) unless $skipwrite;
458             }
459              
460             sub configure_australia {
461 0     0 0   my($self, $skipwrite) = @_;
462 0           $self->set_config_value('DE', 1);
463 0           $self->set_config_value('BAND', 0);
464 0           $self->set_config_value('SPACE', 0);
465 0 0         $self->update_registers( 0.1 ) unless $skipwrite;
466             }
467              
468             sub set_frequency {
469 0     0 0   my($self, $frequency) = @_;
470            
471 0           my $spacebits = $self->get_config_value('SPACE');
472 0           my $bandbits = $self->get_config_value('BAND');
473            
474 0 0         my $baseline = ( $bandbits ) ? 7600 : 8750;
475 0           my $spacing;
476 0 0         if( $spacebits == 1) {
    0          
477 0           $spacing = 10;
478             } elsif( $spacebits == 2 ) {
479 0           $spacing = 5;
480             } else {
481 0           $spacing = 20;
482             }
483            
484 0           my $channel = ( ($frequency * 100 ) - $baseline ) / $spacing;
485            
486 0           $self->set_channel($channel);
487             }
488              
489             sub set_channel {
490 0     0 0   my($self, $channel) = @_;
491            
492 0           $self->set_config_value('CHAN', $channel);
493 0           $self->set_config_value('TUNE', 1);
494 0           $self->update_registers(0.01);
495 0           $self->wait_for_stc;
496             }
497              
498             sub get_channel {
499 0     0 0   my $self = shift;
500 0           my $channel = $self->get_config_value('READCHAN');
501 0           return $channel;
502             }
503              
504             sub get_frequency {
505 0     0 0   my $self = shift;
506            
507 0           my $spacebits = $self->get_config_value('SPACE');
508 0           my $bandbits = $self->get_config_value('BAND');
509            
510 0 0         my $baseline = ( $bandbits ) ? 7600 : 8750;
511 0           my $spacing;
512 0 0         if( $spacebits == 1) {
    0          
513 0           $spacing = 10;
514             } elsif( $spacebits == 2 ) {
515 0           $spacing = 5;
516             } else {
517 0           $spacing = 20;
518             }
519 0           my $channel = $self->get_config_value('READCHAN');
520            
521 0 0         my $frequency = ( $channel ) ? (( $spacing * $channel ) + $baseline) / 100 : 0;
522 0           return $frequency;
523             }
524              
525             sub set_volume {
526 0     0 0   my($self, $volume) = @_;
527             # volume 0 to 30
528 0   0       $volume ||= 0;
529 0 0         $volume = 0 if $volume < 0;
530 0 0         $volume = 30 if $volume > 30;
531            
532 0           my $volext = 1;
533 0 0         if( $volume >= 16 ) {
534 0           $volume -= 15;
535 0           $volext = 0;
536             }
537            
538 0 0         $self->disable_mute if $volume;
539            
540 0           $self->set_config_value('VOLUME', $volume);
541 0           $self->set_config_value('VOLEXT', $volext);
542            
543 0           $self->update_registers( 0.01 );
544             }
545              
546             sub get_volume {
547 0     0 0   my $self = shift;
548 0           my $volume = $self->get_config_value('VOLUME');
549 0           my $volext = $self->get_config_value('VOLEXT');
550            
551 0 0         $volume += 15 unless $volext;
552 0           return $volume;
553             }
554              
555             sub seek_up {
556 0     0 0   my($self) = @_;
557 0           $self->set_config_value('SEEKUP', 1);
558 0           $self->set_config_value('SEEK', 1);
559 0           $self->update_registers(0.01);
560 0           $self->wait_for_stc;
561             }
562              
563             sub seek_down {
564 0     0 0   my($self) = @_;
565 0           $self->set_config_value('SEEKUP', 0);
566 0           $self->set_config_value('SEEK', 1);
567 0           $self->update_registers(0.01);
568 0           $self->wait_for_stc;
569             }
570              
571             sub wait_for_stc {
572 0     0 0   my $self = shift;
573            
574 0           my $count = 500; # 5 second max seek time
575            
576 0   0       while(!$self->get_config_value('STC') && $count > 0) {
577 0           $self->read_registers;
578 0           $self->sleep_seconds(0.01);
579 0           $count --;
580             }
581            
582 0           $self->set_config_value('SEEK', 0);
583 0           $self->set_config_value('TUNE', 0);
584            
585 0           $self->update_registers(0.01);
586            
587 0           $count = 500;
588            
589 0   0       while($self->get_config_value('STC') && $count > 0) {
590 0           $self->read_registers;
591 0           $self->sleep_seconds(0.01);
592             }
593             }
594              
595             sub sleep_seconds {
596 0     0 0   my($self, $seconds) = @_;
597 0           $self->delay( $seconds * 1000 );
598             }
599              
600             # whole register access
601              
602             sub set_register {
603 0     0 0   my($self, $register, $newword) = @_;
604 0 0         return unless($self->_mapped_registers);
605 0           $self->_mapped_registers->[$register] = $newword;
606 0           return;
607             }
608              
609             sub get_register {
610 0     0 0   my($self, $register) = @_;
611 0 0         return ( $self->_mapped_registers ) ? $self->_mapped_registers->[$register] : 0;
612             }
613              
614             # enable / disable
615              
616             sub enable_seek_wrap {
617 0     0 0   my $self = shift;
618 0           $self->set_config_value('SKMODE', 0);
619 0           $self->update_registers( 0.01 );
620             }
621              
622             sub disable_seek_wrap {
623 0     0 0   my $self = shift;
624 0           $self->set_config_value('SKMODE', 1);
625 0           $self->update_registers( 0.01 );
626             }
627              
628             sub enable_mute {
629 0     0 0   my $self = shift;
630 0           $self->set_config_value('DMUTE', 0);
631 0           $self->update_registers( 0.01 );
632             }
633              
634             sub disable_mute {
635 0     0 0   my $self = shift;
636 0           $self->set_config_value('DMUTE', 1);
637 0           $self->update_registers( 0.01 );
638             }
639              
640             sub enable_soft_mute {
641 0     0 0   my $self = shift;
642 0           $self->set_config_value('DSMUTE', 0);
643 0           $self->update_registers( 0.01 );
644             }
645              
646             sub disable_soft_mute {
647 0     0 0   my $self = shift;
648 0           $self->set_config_value('DSMUTE', 1);
649 0           $self->update_registers( 0.01 );
650             }
651              
652             1;
653              
654             __END__