1
+ // Licensed to the .NET Foundation under one or more agreements.
2
+ // The .NET Foundation licenses this file to you under the MIT license.
3
+
4
+ using System ;
5
+ using System . Device ;
6
+ using System . Device . Gpio ;
7
+ using System . Device . Model ;
8
+ using Iot . Device . Common ;
9
+
10
+ namespace Iot . Device . Rtc
11
+ {
12
+ /// <summary>
13
+ /// Realtime Clock Ds1302.
14
+ /// </summary>
15
+ [ Interface ( "Realtime Clock Ds1302" ) ]
16
+ public class Ds1302 : RtcBase
17
+ {
18
+ private readonly GpioPin _clockPin ;
19
+ private readonly GpioPin _communicationEnabledPin ;
20
+ private readonly GpioPin _dataPin ;
21
+ private readonly byte enableWrite = 0b1000_0000 ;
22
+ private readonly byte disableWrite = 0b0000_0000 ;
23
+ private readonly byte enableWriteOrRead = 0b1000_0001 ;
24
+ private readonly bool _shouldDispose ;
25
+ private PinMode _currentDataPinDirection ;
26
+ private GpioController _controller ;
27
+
28
+ /// <summary>
29
+ /// Initializes a new instance of the <see cref="Ds1302"/> class.
30
+ /// </summary>
31
+ /// <param name="clockPin">Clock pin number.</param>
32
+ /// <param name="dataPin">Data pin number.</param>
33
+ /// <param name="communicationEnabledPin">Communication enabled pin number.</param>
34
+ /// <param name="controller">Gpio controller.</param>
35
+ /// <param name="shouldDispose">True to dispose the Gpio Controller.</param>
36
+ /// <exception cref="ArgumentNullException">When pin numbers are not valid.</exception>
37
+ public Ds1302 ( int clockPin , int dataPin , int communicationEnabledPin , GpioController ? controller = null , bool shouldDispose = true )
38
+ {
39
+ _controller = controller ?? new GpioController ( ) ;
40
+ _shouldDispose = shouldDispose || controller is null ;
41
+
42
+ if ( clockPin < 0 || dataPin < 0 || communicationEnabledPin < 0 )
43
+ {
44
+ throw new ArgumentOutOfRangeException ( ) ;
45
+ }
46
+
47
+ _clockPin = _controller . OpenPin ( clockPin , PinMode . Output ) ;
48
+ _communicationEnabledPin = _controller . OpenPin ( communicationEnabledPin , PinMode . Output ) ;
49
+ _dataPin = _controller . OpenPin ( dataPin , PinMode . Input ) ;
50
+
51
+ _communicationEnabledPin . Write ( PinValue . Low ) ;
52
+ _clockPin . Write ( PinValue . Low ) ;
53
+ }
54
+
55
+ /// <summary>
56
+ /// Checks if the clock is halted.
57
+ /// </summary>
58
+ /// <returns><b>true</b> when clock is halted, else <b>false</b></returns>
59
+ public bool IsHalted ( )
60
+ {
61
+ PrepareRead ( Ds1302Registers . REG_SECONDS ) ;
62
+ byte seconds = ReadByte ( ) ;
63
+ EndTransmission ( ) ;
64
+ return ( byte ) ( seconds & enableWrite ) > 0 ;
65
+ }
66
+
67
+ /// <summary>
68
+ /// Halts the clock.
69
+ /// </summary>
70
+ public void Halt ( )
71
+ {
72
+ PrepareWrite ( Ds1302Registers . REG_SECONDS ) ;
73
+ WriteByte ( enableWrite ) ;
74
+ EndTransmission ( ) ;
75
+ }
76
+
77
+ /// <summary>
78
+ /// Read time from the device.
79
+ /// </summary>
80
+ /// <returns>Time from the device.</returns>
81
+ protected override DateTime ReadTime ( )
82
+ {
83
+ PrepareRead ( Ds1302Registers . REG_BURST ) ;
84
+ var seconds = NumberHelper . Bcd2Dec ( ( byte ) ( ReadByte ( ) & 0b0111_1111 ) ) ;
85
+ var minutes = NumberHelper . Bcd2Dec ( ( byte ) ( ReadByte ( ) & 0b0111_1111 ) ) ;
86
+ var hours = NumberHelper . Bcd2Dec ( ( byte ) ( ReadByte ( ) & 0b0011_1111 ) ) ;
87
+ var days = NumberHelper . Bcd2Dec ( ( byte ) ( ReadByte ( ) & 0b0011_1111 ) ) ;
88
+ var months = NumberHelper . Bcd2Dec ( ( byte ) ( ReadByte ( ) & 0b0001_1111 ) ) ;
89
+ var dayOfWeek = NumberHelper . Bcd2Dec ( ( byte ) ( ReadByte ( ) & 0b0000_0111 ) ) ;
90
+ var years = NumberHelper . Bcd2Dec ( ( byte ) ( ReadByte ( ) & 0b0111_1111 ) ) ;
91
+
92
+ EndTransmission ( ) ;
93
+
94
+ return new DateTime ( 2000 + years , months , days , hours , minutes , seconds , 0 ) ;
95
+ }
96
+
97
+ /// <summary>
98
+ /// Sets date and time.
99
+ /// </summary>
100
+ /// <param name="time">Date and time.</param>
101
+ protected override void SetTime ( DateTime time )
102
+ {
103
+ PrepareWrite ( Ds1302Registers . REG_WP ) ;
104
+ WriteByte ( disableWrite ) ;
105
+ EndTransmission ( ) ;
106
+
107
+ PrepareWrite ( Ds1302Registers . REG_BURST ) ;
108
+ WriteByte ( NumberHelper . Dec2Bcd ( time . Second ) ) ;
109
+ WriteByte ( NumberHelper . Dec2Bcd ( time . Minute ) ) ;
110
+ WriteByte ( NumberHelper . Dec2Bcd ( time . Hour ) ) ;
111
+ WriteByte ( NumberHelper . Dec2Bcd ( time . Day ) ) ;
112
+ WriteByte ( NumberHelper . Dec2Bcd ( time . Month ) ) ;
113
+ WriteByte ( NumberHelper . Dec2Bcd ( ( int ) time . DayOfWeek ) ) ;
114
+ WriteByte ( NumberHelper . Dec2Bcd ( time . Year - 2000 ) ) ;
115
+
116
+ WriteByte ( enableWrite ) ;
117
+ EndTransmission ( ) ;
118
+ }
119
+
120
+ /// <summary>
121
+ /// <inheritdoc/>
122
+ /// </summary>
123
+ /// <param name="disposing">True to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
124
+ protected override void Dispose ( bool disposing )
125
+ {
126
+ _dataPin ? . Dispose ( ) ;
127
+ _clockPin ? . Dispose ( ) ;
128
+ _communicationEnabledPin ? . Dispose ( ) ;
129
+ if ( _shouldDispose )
130
+ {
131
+ _controller ? . Dispose ( ) ;
132
+ _controller = null ;
133
+ }
134
+ }
135
+
136
+ private byte ReadByte ( )
137
+ {
138
+ byte readValue = 0 ;
139
+ for ( byte i = 0 ; i < 8 ; i ++ )
140
+ {
141
+ if ( _dataPin . Read ( ) == PinValue . High )
142
+ {
143
+ readValue |= ( byte ) ( 0x01 << i ) ;
144
+ }
145
+
146
+ MoveToNextBit ( ) ;
147
+ }
148
+
149
+ return readValue ;
150
+ }
151
+
152
+ private void PrepareRead ( Ds1302Registers ds1302Register )
153
+ {
154
+ SetDirectionOfDataPin ( PinMode . Output ) ;
155
+ _communicationEnabledPin . Write ( PinValue . High ) ;
156
+ WriteByte ( ( byte ) ( enableWriteOrRead | ( byte ) ds1302Register ) ) ;
157
+ SetDirectionOfDataPin ( PinMode . Input ) ;
158
+ }
159
+
160
+ private void PrepareWrite ( Ds1302Registers ds1302Register )
161
+ {
162
+ SetDirectionOfDataPin ( PinMode . Output ) ;
163
+ _communicationEnabledPin . Write ( PinValue . High ) ;
164
+ WriteByte ( ( byte ) ( enableWrite | ( byte ) ds1302Register ) ) ;
165
+ }
166
+
167
+ private void EndTransmission ( )
168
+ {
169
+ _communicationEnabledPin . Write ( PinValue . Low ) ;
170
+ }
171
+
172
+ private void SetDirectionOfDataPin ( PinMode direction )
173
+ {
174
+ if ( _currentDataPinDirection != direction )
175
+ {
176
+ _currentDataPinDirection = direction ;
177
+ _dataPin . SetPinMode ( _currentDataPinDirection ) ;
178
+ }
179
+ }
180
+
181
+ private void WriteByte ( byte register )
182
+ {
183
+ for ( int i = 0 ; i < 8 ; i ++ )
184
+ {
185
+ _dataPin . Write ( ( register & 0x01 ) > 0 ? PinValue . High : PinValue . Low ) ;
186
+ MoveToNextBit ( ) ;
187
+ register >>= 1 ;
188
+ }
189
+ }
190
+
191
+ private void MoveToNextBit ( )
192
+ {
193
+ _clockPin . Write ( PinValue . High ) ;
194
+ DelayHelper . DelayMicroseconds ( 1 , true ) ;
195
+ _clockPin . Write ( PinValue . Low ) ;
196
+ DelayHelper . DelayMicroseconds ( 1 , true ) ;
197
+ }
198
+ }
199
+ }
0 commit comments