File Coverage

blib/lib/Device/Chip/DS1307.pm
Criterion Covered Total %
statement 39 142 27.4
branch 1 4 25.0
condition 1 3 33.3
subroutine 14 32 43.7
pod 2 21 9.5
total 57 202 28.2


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2015-2021 -- leonerd@leonerd.org.uk
5              
6 3     3   201037 use v5.26;
  3         26  
7 3     3   475 use Object::Pad 0.57;
  3         9247  
  3         12  
8              
9             package Device::Chip::DS1307 0.06;
10             class Device::Chip::DS1307
11 3     3   1494 :isa(Device::Chip::Base::RegisteredI2C);
  3         22108  
  3         91  
12              
13 3     3   405 use utf8;
  3         4  
  3         9  
14              
15 3     3   70 use Carp;
  3         6  
  3         142  
16              
17 3     3   14 use Future::AsyncAwait;
  3         5  
  3         8  
18              
19 3     3   107 use constant DEFAULT_ADDR => 0x68;
  3         3  
  3         453  
20              
21             =encoding UTF-8
22              
23             =head1 NAME
24              
25             C - chip driver for a F
26              
27             =head1 DESCRIPTION
28              
29             This L subclass provides specific communication to a
30             F F chip attached to a computer via an I²C adapter.
31              
32             =cut
33              
34             has $_address :param = DEFAULT_ADDR;
35              
36             method I2C_options
37 2     2 0 598 {
38             return (
39 2         10 addr => $_address,
40             max_bitrate => 100E3,
41             );
42             }
43              
44             use constant {
45 3         329 REG_SECONDS => 0x00,
46             REG_MINUTES => 0x01,
47             REG_HOURS => 0x02,
48             REG_WDAY => 0x03,
49             REG_MDAY => 0x04,
50             REG_MONTH => 0x05,
51             REG_YEAR => 0x06,
52             REG_CONTROL => 0x07,
53 3     3   18 };
  3         4  
54              
55             use constant {
56             # REG_SECONDS
57 3         7136 MASK_CLOCKHALT => 1<<7,
58              
59             # REG_HOURS
60             MASK_12H => 1<<6,
61             MASK_PM => 1<<5,
62              
63             # REG_CONTROL
64             MASK_OUT => 1<<7,
65             MASK_SQWE => 1<<4,
66             MASK_RS => 3<<0,
67 3     3   15 };
  3         4  
68              
69 0         0 async method read_reg_u8 ( $reg )
  0         0  
  0         0  
70 0         0 {
71 0         0 return unpack "C", await $self->read_reg( $reg );
72 0     0 0 0 }
73              
74 0         0 async method write_reg_u8 ( $reg, $value )
  0         0  
  0         0  
  0         0  
75 0         0 {
76 0         0 await $self->write_reg( $reg, pack "C", $value );
77 0     0 0 0 }
78              
79 6     6   17 sub _unpack_bcd { ( $_[0] >> 4 )*10 + ( $_[0] % 16 ) }
80 7     7   26 sub _pack_bcd { int( $_[0] / 10 ) << 4 | ( $_[0] % 10 ) }
81              
82 0         0 async method read_reg_bcd ( $reg )
  0         0  
  0         0  
83 0         0 {
84 0         0 return _unpack_bcd unpack "C", await $self->read_reg( $reg );
85 0     0 0 0 }
86              
87 0         0 async method write_reg_bcd ( $reg, $value )
  0         0  
  0         0  
  0         0  
88 0         0 {
89 0         0 await $self->write_reg( $reg, pack "C", _pack_bcd( $value ) );
90 0     0 0 0 }
91              
92             =head1 METHODS
93              
94             The following methods documented in an C expression return L
95             instances.
96              
97             =cut
98              
99             =head2 read_FIELD
100              
101             $sec = await $ds->read_seconds;
102             $min = await $ds->read_minutes;
103             $hr = await $ds->read_hours;
104             $wday = await $ds->read_wday;
105             $mday = await $ds->read_mday;
106             $mon = await $ds->read_month;
107             $year = await $ds->read_year;
108              
109             Reads a timekeeping field and returns a decimal integer. The following fields
110             are recognised:
111              
112             The C field is always returned in 24-hour mode, even if the chip is in
113             12-hour ("AM/PM") mode.
114              
115             =cut
116              
117             # REG_SECONDS also contains the CLOCK HALTED flag
118 0         0 async method read_seconds ()
  0         0  
119 0         0 {
120 0         0 my $v = await $self->read_reg_u8( REG_SECONDS );
121 0         0 $v &= ~MASK_CLOCKHALT;
122 0         0 return _unpack_bcd $v;
123 0     0 0 0 }
124              
125 0     0 0 0 async method read_minutes () { return await $self->read_reg_bcd( REG_MINUTES ); }
  0         0  
  0         0  
  0         0  
  0         0  
126              
127             # REG_HOURS is either in 12 or 24-hour mode.
128 0         0 async method read_hours ()
  0         0  
129 0         0 {
130 0         0 my $v = await $self->read_reg_u8( REG_HOURS );
131 0 0       0 if( $v & MASK_12H ) {
132 0         0 my $pm = $v & MASK_PM;
133 0         0 $v &= ~(MASK_12H|MASK_PM);
134 0         0 return _unpack_bcd( $v ) + 12*$pm;
135             }
136             else {
137 0         0 return _unpack_bcd $v;
138             }
139 0     0 0 0 }
140              
141 0     0 0 0 async method read_wday () { return await $self->read_reg_u8 ( REG_WDAY ); }
  0         0  
  0         0  
  0         0  
  0         0  
142 0     0 0 0 async method read_mday () { return await $self->read_reg_bcd( REG_MDAY ); }
  0         0  
  0         0  
  0         0  
  0         0  
143 0     0 0 0 async method read_month () { return await $self->read_reg_bcd( REG_MONTH ); }
  0         0  
  0         0  
  0         0  
  0         0  
144 0     0 0 0 async method read_year () { return await $self->read_reg_bcd( REG_YEAR ); }
  0         0  
  0         0  
  0         0  
  0         0  
145              
146             =head2 write_FIELD
147              
148             await $ds->write_seconds( $sec );
149             await $ds->write_minutes( $min );
150             await $ds->write_hours ( $hr );
151             await $ds->write_wday ( $wday );
152             await $ds->write_mday ( $mday );
153             await $ds->write_month ( $mon );
154             await $ds->write_year ( $year );
155              
156             Writes a timekeeping field as a decimal integer. The following fields are
157             recognised:
158              
159             The C field is always written back in 24-hour mode.
160              
161             =cut
162              
163 0     0 0 0 async method write_seconds () { await $self->write_reg_bcd( REG_SECONDS, $_[1] ); }
  0         0  
  0         0  
  0         0  
  0         0  
164 0     0 0 0 async method write_minutes () { await $self->write_reg_bcd( REG_MINUTES, $_[1] ); }
  0         0  
  0         0  
  0         0  
  0         0  
165 0     0 0 0 async method write_hours () { await $self->write_reg_bcd( REG_HOURS, $_[1] ); }
  0         0  
  0         0  
  0         0  
  0         0  
166 0     0 0 0 async method write_wday () { await $self->write_reg_u8 ( REG_WDAY, $_[1] ); }
  0         0  
  0         0  
  0         0  
  0         0  
167 0     0 0 0 async method write_mday () { await $self->write_reg_bcd( REG_MDAY, $_[1] ); }
  0         0  
  0         0  
  0         0  
  0         0  
168 0     0 0 0 async method write_month () { await $self->write_reg_bcd( REG_MONTH, $_[1] ); }
  0         0  
  0         0  
  0         0  
  0         0  
169 0     0 0 0 async method write_year () { await $self->write_reg_bcd( REG_YEAR, $_[1] ); }
  0         0  
  0         0  
  0         0  
  0         0  
170              
171             =head2 read_time
172              
173             @tm = await $ds->read_time;
174              
175             Returns a 7-element C-compatible list of values by reading the
176             timekeeping registers, suitable for passing to C, etc... Note
177             that the returned list does not contain the C or C fields.
178              
179             Because the F only stores a 2-digit year number, the year is presumed
180             to be in the range C<2000>-C<2099>.
181              
182             This method presumes C-compatible semantics for the C field
183             stored on the chip; i.e. that 0 is Sunday.
184              
185             This method performs an atomic reading of all the timekeeping registers as a
186             single I²C transaction, so is preferrable to invoking multiple calls to
187             individual read methods.
188              
189             =cut
190              
191             async method read_time
192 1         3 {
193 1         5 my ( $bcd_sec, $bcd_min, $bcd_hour, $wday, $bcd_mday, $bcd_mon, $bcd_year ) =
194             unpack "C7", await $self->read_reg( REG_SECONDS, 7 );
195              
196             return (
197 1         7395 _unpack_bcd( $bcd_sec ),
198             _unpack_bcd( $bcd_min ),
199             _unpack_bcd( $bcd_hour ),
200             _unpack_bcd( $bcd_mday ),
201             _unpack_bcd( $bcd_mon ) - 1,
202             _unpack_bcd( $bcd_year ) + 100,
203             $wday,
204             );
205 1     1 1 209 }
206              
207             =head2 write_time
208              
209             await $ds->write_time( @tm );
210              
211             Writes the timekeeping registers from a 7-element C-compatible list
212             of values. This method ignores the C and C fields, if present.
213              
214             Because the F only stores a 2-digit year number, the year must be in
215             the range C<2000>-C<2099> (i.e. numerical values of C<100> to C<199>).
216              
217             This method performs an atomic writing of all the timekeeping registers as a
218             single I²C transaction, so is preferrable to invoking multiple calls to
219             individual write methods.
220              
221             =cut
222              
223             async method write_time
224 1         3 {
225 1         2 my ( $sec, $min, $hour, $mday, $mon, $year, $wday ) = @_;
226              
227 1 50 33     7 $year >= 100 and $year <= 199 or croak "Invalid year ($year)";
228              
229 1         3 await $self->write_reg( REG_SECONDS, pack "C7",
230             _pack_bcd( $sec ),
231             _pack_bcd( $min ),
232             _pack_bcd( $hour ),
233             _pack_bcd( $wday ),
234             _pack_bcd( $mday ),
235             _pack_bcd( $mon + 1 ),
236             _pack_bcd( $year - 100 ),
237             );
238 1     1 1 192 }
239              
240             =head1 AUTHOR
241              
242             Paul Evans
243              
244             =cut
245              
246             0x55AA;