File Coverage

blib/lib/Device/Chip/PCF8563.pm
Criterion Covered Total %
statement 59 59 100.0
branch 3 6 50.0
condition 1 3 33.3
subroutine 14 14 100.0
pod 2 3 66.6
total 79 85 92.9


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, 2016-2023 -- leonerd@leonerd.org.uk
5              
6 2     2   261463 use v5.26;
  2         16  
7 2     2   11 use warnings;
  2         4  
  2         58  
8 2     2   617 use Object::Pad 0.800;
  2         10943  
  2         112  
9              
10             package Device::Chip::PCF8563 0.04;
11             class Device::Chip::PCF8563
12 2     2   1142 :isa(Device::Chip::Base::RegisteredI2C);
  2         32001  
  2         76  
13              
14 2     2   343 use utf8;
  2         5  
  2         9  
15              
16 2     2   55 use Carp;
  2         4  
  2         114  
17              
18 2     2   12 use Future::AsyncAwait;
  2         4  
  2         8  
19              
20 2     2   107 use constant DEFAULT_ADDR => 0xA2 >> 1;
  2         4  
  2         346  
21              
22             =encoding UTF-8
23              
24             =head1 NAME
25              
26             C - chip driver for a F
27              
28             =head1 SYNOPSIS
29              
30             use Device::Chip::PCF8563;
31             use Future::AsyncAwait;
32              
33             use POSIX qw( mktime strftime );
34              
35             my $chip = Device::Chip::PCF8563->new;
36             await $chip->mount( Device::Chip::Adapter::...->new );
37              
38             printf "The current time on this chip is ",
39             await strftime( "%Y-%m-%d %H:%M:%S", localtime mktime $chip->read_time );
40              
41             =head1 DESCRIPTION
42              
43             This L subclass provides specific communication to a
44             F F chip attached to a computer via an I²C adapter.
45              
46             =cut
47              
48             method I2C_options
49 1     1 0 420 {
50             return (
51 1         8 addr => DEFAULT_ADDR,
52             max_bitrate => 100E3,
53             );
54             }
55              
56             use constant {
57 2         1826 REG_CTRL1 => 0x00,
58             REG_CTRL2 => 0x01,
59             REG_VLSECONDS => 0x02,
60 2     2   15 };
  2         3  
61              
62 6     6   9 sub _unpack_bcd ( $v ) { ( $v >> 4 )*10 + ( $v % 16 ) }
  6         6  
  6         7  
  6         18  
63 7     7   9 sub _pack_bcd ( $v ) { int( $v / 10 ) << 4 | ( $v % 10 ) }
  7         9  
  7         27  
  7         41  
64              
65             =head1 METHODS
66              
67             The following methods documented in an C expression return L
68             instances.
69              
70             =cut
71              
72             =head2 read_time
73              
74             @tm = await $chip->read_time;
75              
76             Returns a 7-element C-compatible list of values by reading the
77             timekeeping registers, suitable for passing to C, etc... Note
78             that the returned list does not contain the C or C fields.
79              
80             Because the F only stores a 2-digit year number plus a single century
81             bit, the year is presumed to be in the range C<2000>-C<2199>.
82              
83             This method presumes C-compatible semantics for the C field
84             stored on the chip; i.e. that 0 is Sunday.
85              
86             This method performs an atomic reading of all the timekeeping registers as a
87             single I²C transaction, so is preferrable to invoking multiple calls to
88             individual read methods.
89              
90             =cut
91              
92 1         2 async method read_time ()
  1         2  
93 1         4 {
94 1         7 my ( $bcd_sec, $bcd_min, $bcd_hour, $bcd_mday, $wday, $bcd_mon, $bcd_year ) =
95             unpack "C7", await $self->read_reg( REG_VLSECONDS, 7 );
96              
97 1 50       1365 die "VL bit is set; time is unreliable" if $bcd_sec & 0x80;
98              
99 1         2 my $century = $bcd_mon & 0x80;
100              
101             return (
102 1 50       4 _unpack_bcd( $bcd_sec ),
103             _unpack_bcd( $bcd_min & 0x7F ),
104             _unpack_bcd( $bcd_hour & 0x3F ),
105             _unpack_bcd( $bcd_mday & 0x3F ),
106             _unpack_bcd( $bcd_mon & 0x1F ) - 1,
107             _unpack_bcd( $bcd_year ) + 100 + ( $century ? 100 : 0 ),
108             $wday & 0x07,
109             );
110 1     1 1 11581 }
111              
112             =head2 write_time
113              
114             await $chip->write_time( @tm );
115              
116             Writes the timekeeping registers from a 7-element C-compatible list
117             of values. This method ignores the C and C fields, if present.
118              
119             Because the F only stores a 2-digit year number and a century bit,
120             the year must be in the range C<2000>-C<2199> (i.e. numerical values of C<100>
121             to C<299>).
122              
123             This method performs an atomic writing of all the timekeeping registers as a
124             single I²C transaction, so is preferrable to invoking multiple calls to
125             individual write methods.
126              
127             =cut
128              
129 1         2 async method write_time ( $sec, $min, $hour, $mday, $mon, $year, $wday )
  1         2  
  1         2  
  1         1  
  1         2  
  1         1  
  1         2  
  1         1  
  1         2  
130 1         9 {
131 1 50 33     6 $year >= 100 and $year <= 299 or croak "Invalid year ($year)";
132              
133 1         2 my $century = $year >= 200;
134 1         3 $year %= 100;
135              
136 1         5 await $self->write_reg( REG_VLSECONDS, pack "C7",
137             _pack_bcd( $sec ),
138             _pack_bcd( $min ),
139             _pack_bcd( $hour ),
140             _pack_bcd( $mday ),
141             _pack_bcd( $wday ),
142             _pack_bcd( $mon + 1 ) | ( $century ? 0x80 : 0 ),
143             _pack_bcd( $year ),
144             );
145 1     1 1 284 }
146              
147             =head1 AUTHOR
148              
149             Paul Evans
150              
151             =cut
152              
153             0x55AA;