• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eldruin / ds1307-rs / 16734533376

04 Aug 2025 09:21PM UTC coverage: 45.702% (-46.3%) from 91.983%
16734533376

Pull #4

github

web-flow
Merge 40c09645d into 45395fe48
Pull Request #4: Add async support with embedded-hal-async

0 of 239 new or added lines in 6 files covered. (0.0%)

1 existing line in 1 file now uncovered.

218 of 477 relevant lines covered (45.7%)

0.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.72
/src/datetime.rs
1
use crate::{BitFlags, Ds1307, Error, Register, ADDR};
2
#[cfg(feature = "blocking")]
3
use embedded_hal::i2c::I2c;
4
#[cfg(feature = "async")]
5
use embedded_hal_async::i2c::I2c as AsyncI2c;
6
#[cfg(feature = "blocking")]
7
pub use rtcc::{DateTimeAccess, Rtcc};
8
pub use rtcc::{Datelike, Hours, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
9

10
#[cfg(feature = "blocking")]
11
impl<I2C, E> DateTimeAccess for Ds1307<I2C>
12
where
13
    I2C: I2c<Error = E>,
14
{
15
    type Error = Error<E>;
16

17
    fn datetime(&mut self) -> Result<NaiveDateTime, Self::Error> {
1✔
18
        let mut data = [0; 7];
1✔
19
        self.i2c
1✔
20
            .write_read(ADDR, &[0x00], &mut data)
×
21
            .map_err(Error::I2C)?;
×
22
        let year = 2000 + u16::from(packed_bcd_to_decimal(data[Register::YEAR as usize]));
1✔
23
        let month = packed_bcd_to_decimal(data[Register::MONTH as usize]);
1✔
24
        let day = packed_bcd_to_decimal(data[Register::DOM as usize]);
1✔
25
        let hour = self.get_hours_from_register(data[Register::HOURS as usize])?;
1✔
26
        let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize]);
1✔
27
        let second = packed_bcd_to_decimal(remove_ch_bit(data[Register::SECONDS as usize]));
1✔
28
        let date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into())
2✔
29
            .ok_or(Error::InvalidInputData)?;
1✔
30
        date.and_hms_opt(get_h24(hour).into(), minute.into(), second.into())
2✔
31
            .ok_or(Error::InvalidInputData)
1✔
32
    }
33

34
    fn set_datetime(&mut self, datetime: &NaiveDateTime) -> Result<(), Self::Error> {
1✔
35
        if datetime.year() < 2000 || datetime.year() > 2099 {
1✔
36
            return Err(Error::InvalidInputData);
1✔
37
        }
38
        let hour = self.get_hours_register_value(Hours::H24(datetime.hour() as u8))?;
1✔
39
        let ch_flag = self.read_register(Register::SECONDS)? & BitFlags::CH;
1✔
40
        let payload = [
1✔
41
            Register::SECONDS,
×
42
            decimal_to_packed_bcd(datetime.second() as u8) | ch_flag,
1✔
43
            decimal_to_packed_bcd(datetime.minute() as u8),
1✔
44
            hour,
×
45
            datetime.weekday().number_from_sunday() as u8,
1✔
46
            decimal_to_packed_bcd(datetime.day() as u8),
1✔
47
            decimal_to_packed_bcd(datetime.month() as u8),
1✔
48
            decimal_to_packed_bcd((datetime.year() - 2000) as u8),
1✔
49
        ];
50
        self.i2c.write(ADDR, &payload).map_err(Error::I2C)
1✔
51
    }
52
}
53

54
#[cfg(feature = "blocking")]
55
#[allow(clippy::manual_range_contains)]
56
impl<I2C, E> Rtcc for Ds1307<I2C>
57
where
58
    I2C: I2c<Error = E>,
59
{
60
    fn seconds(&mut self) -> Result<u8, Self::Error> {
1✔
61
        let data = self.read_register(Register::SECONDS)?;
1✔
62
        Ok(packed_bcd_to_decimal(remove_ch_bit(data)))
1✔
63
    }
64

65
    fn minutes(&mut self) -> Result<u8, Self::Error> {
1✔
66
        self.read_register_decimal(Register::MINUTES)
1✔
67
    }
68

69
    fn hours(&mut self) -> Result<Hours, Self::Error> {
1✔
70
        let data = self.read_register(Register::HOURS)?;
1✔
71
        self.get_hours_from_register(data)
1✔
72
    }
73

74
    fn weekday(&mut self) -> Result<u8, Self::Error> {
1✔
75
        self.read_register_decimal(Register::DOW)
1✔
76
    }
77

78
    fn day(&mut self) -> Result<u8, Self::Error> {
1✔
79
        self.read_register_decimal(Register::DOM)
1✔
80
    }
81

82
    fn month(&mut self) -> Result<u8, Self::Error> {
1✔
83
        self.read_register_decimal(Register::MONTH)
1✔
84
    }
85

86
    fn year(&mut self) -> Result<u16, Self::Error> {
1✔
87
        let year = self.read_register_decimal(Register::YEAR)?;
1✔
88
        Ok(2000 + u16::from(year))
1✔
89
    }
90

91
    fn date(&mut self) -> Result<NaiveDate, Self::Error> {
1✔
92
        let mut data = [0; 3];
1✔
93
        self.i2c
1✔
94
            .write_read(ADDR, &[Register::DOM], &mut data)
×
95
            .map_err(Error::I2C)?;
×
96
        let year = 2000 + u16::from(packed_bcd_to_decimal(data[2]));
1✔
97
        let month = packed_bcd_to_decimal(data[1]);
1✔
98
        let day = packed_bcd_to_decimal(data[0]);
1✔
99
        NaiveDate::from_ymd_opt(year.into(), month.into(), day.into())
2✔
100
            .ok_or(Error::InvalidInputData)
1✔
101
    }
102

103
    fn time(&mut self) -> Result<NaiveTime, Self::Error> {
1✔
104
        let mut data = [0; 3];
1✔
105
        self.i2c
1✔
106
            .write_read(ADDR, &[Register::SECONDS], &mut data)
×
107
            .map_err(Error::I2C)?;
×
108
        let hour = self.get_hours_from_register(data[Register::HOURS as usize])?;
1✔
109
        let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize]);
1✔
110
        let second = packed_bcd_to_decimal(remove_ch_bit(data[Register::SECONDS as usize]));
1✔
111
        NaiveTime::from_hms_opt(get_h24(hour).into(), minute.into(), second.into())
2✔
112
            .ok_or(Error::InvalidInputData)
1✔
113
    }
114

115
    fn set_seconds(&mut self, seconds: u8) -> Result<(), Self::Error> {
1✔
116
        if seconds > 59 {
1✔
117
            return Err(Error::InvalidInputData);
1✔
118
        }
119
        // needs to keep the CH bit status so we read it first
120
        let data = self.read_register(Register::SECONDS)?;
1✔
121
        self.write_register(
1✔
122
            Register::SECONDS,
×
123
            data & BitFlags::CH | decimal_to_packed_bcd(seconds),
1✔
124
        )
125
    }
126

127
    fn set_minutes(&mut self, minutes: u8) -> Result<(), Self::Error> {
1✔
128
        if minutes > 59 {
1✔
129
            return Err(Error::InvalidInputData);
1✔
130
        }
131
        self.write_register_decimal(Register::MINUTES, minutes)
1✔
132
    }
133

134
    fn set_hours(&mut self, hours: Hours) -> Result<(), Self::Error> {
1✔
135
        let value = self.get_hours_register_value(hours)?;
1✔
136
        self.write_register(Register::HOURS, value)
1✔
137
    }
138

139
    fn set_weekday(&mut self, weekday: u8) -> Result<(), Self::Error> {
1✔
140
        if weekday < 1 || weekday > 7 {
1✔
141
            return Err(Error::InvalidInputData);
1✔
142
        }
143
        self.write_register(Register::DOW, weekday)
1✔
144
    }
145

146
    fn set_day(&mut self, day: u8) -> Result<(), Self::Error> {
1✔
147
        if day < 1 || day > 31 {
1✔
148
            return Err(Error::InvalidInputData);
1✔
149
        }
150
        self.write_register_decimal(Register::DOM, day)
1✔
151
    }
152

153
    fn set_month(&mut self, month: u8) -> Result<(), Self::Error> {
1✔
154
        if month < 1 || month > 12 {
1✔
155
            return Err(Error::InvalidInputData);
1✔
156
        }
157
        self.write_register_decimal(Register::MONTH, month)
1✔
158
    }
159

160
    fn set_year(&mut self, year: u16) -> Result<(), Self::Error> {
1✔
161
        if year < 2000 || year > 2099 {
1✔
162
            return Err(Error::InvalidInputData);
1✔
163
        }
164
        self.write_register_decimal(Register::YEAR, (year - 2000) as u8)
1✔
165
    }
166

167
    fn set_date(&mut self, date: &NaiveDate) -> Result<(), Self::Error> {
1✔
168
        if date.year() < 2000 || date.year() > 2099 {
1✔
169
            return Err(Error::InvalidInputData);
×
170
        }
171
        let payload = [
1✔
172
            Register::DOW,
×
173
            date.weekday().number_from_sunday() as u8,
1✔
174
            decimal_to_packed_bcd(date.day() as u8),
1✔
175
            decimal_to_packed_bcd(date.month() as u8),
1✔
176
            decimal_to_packed_bcd((date.year() - 2000) as u8),
1✔
177
        ];
178
        self.i2c.write(ADDR, &payload).map_err(Error::I2C)
1✔
179
    }
180

181
    fn set_time(&mut self, time: &NaiveTime) -> Result<(), Self::Error> {
1✔
182
        let hour = self.get_hours_register_value(Hours::H24(time.hour() as u8))?;
1✔
183
        let ch_flag = self.read_register(Register::SECONDS)? & BitFlags::CH;
1✔
184
        let payload = [
1✔
185
            Register::SECONDS,
×
186
            decimal_to_packed_bcd(time.second() as u8) | ch_flag,
1✔
187
            decimal_to_packed_bcd(time.minute() as u8),
1✔
188
            hour,
×
189
        ];
190
        self.i2c.write(ADDR, &payload).map_err(Error::I2C)
1✔
191
    }
192
}
193

194
#[cfg(feature = "async")]
195
impl<I2C, E> Ds1307<I2C>
196
where
197
    I2C: AsyncI2c<Error = E>,
198
{
199
    /// Get the current date and time asynchronously.
NEW
200
    pub async fn datetime_async(&mut self) -> Result<NaiveDateTime, Error<E>> {
×
NEW
201
        let mut data = [0; 7];
×
NEW
202
        self.i2c
×
NEW
203
            .write_read(ADDR, &[0x00], &mut data)
×
NEW
204
            .await
×
NEW
205
            .map_err(Error::I2C)?;
×
NEW
206
        let year = 2000 + u16::from(packed_bcd_to_decimal(data[Register::YEAR as usize]));
×
NEW
207
        let month = packed_bcd_to_decimal(data[Register::MONTH as usize]);
×
NEW
208
        let day = packed_bcd_to_decimal(data[Register::DOM as usize]);
×
NEW
209
        let hour = self
×
NEW
210
            .get_hours_from_register_async(data[Register::HOURS as usize])
×
NEW
211
            .await?;
×
NEW
212
        let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize]);
×
NEW
213
        let second = packed_bcd_to_decimal(remove_ch_bit(data[Register::SECONDS as usize]));
×
NEW
214
        let date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into())
×
NEW
215
            .ok_or(Error::InvalidInputData)?;
×
NEW
216
        date.and_hms_opt(get_h24(hour).into(), minute.into(), second.into())
×
NEW
217
            .ok_or(Error::InvalidInputData)
×
218
    }
219

220
    /// Set the current date and time asynchronously.
NEW
221
    pub async fn set_datetime_async(&mut self, datetime: &NaiveDateTime) -> Result<(), Error<E>> {
×
NEW
222
        if datetime.year() < 2000 || datetime.year() > 2099 {
×
NEW
223
            return Err(Error::InvalidInputData);
×
224
        }
NEW
225
        let hour = self
×
NEW
226
            .get_hours_register_value_async(Hours::H24(datetime.hour() as u8))
×
NEW
227
            .await?;
×
NEW
228
        let ch_flag = self.read_register_async(Register::SECONDS).await? & BitFlags::CH;
×
NEW
229
        let payload = [
×
NEW
230
            Register::SECONDS,
×
NEW
231
            decimal_to_packed_bcd(datetime.second() as u8) | ch_flag,
×
NEW
232
            decimal_to_packed_bcd(datetime.minute() as u8),
×
NEW
233
            hour,
×
NEW
234
            datetime.weekday().number_from_sunday() as u8,
×
NEW
235
            decimal_to_packed_bcd(datetime.day() as u8),
×
NEW
236
            decimal_to_packed_bcd(datetime.month() as u8),
×
NEW
237
            decimal_to_packed_bcd((datetime.year() - 2000) as u8),
×
238
        ];
NEW
239
        self.i2c.write(ADDR, &payload).await.map_err(Error::I2C)
×
240
    }
241

242
    /// Get seconds asynchronously.
NEW
243
    pub async fn seconds_async(&mut self) -> Result<u8, Error<E>> {
×
NEW
244
        let data = self.read_register_async(Register::SECONDS).await?;
×
NEW
245
        Ok(packed_bcd_to_decimal(remove_ch_bit(data)))
×
246
    }
247

248
    /// Get minutes asynchronously.
NEW
249
    pub async fn minutes_async(&mut self) -> Result<u8, Error<E>> {
×
NEW
250
        self.read_register_decimal_async(Register::MINUTES).await
×
251
    }
252

253
    /// Get hours asynchronously.
NEW
254
    pub async fn hours_async(&mut self) -> Result<Hours, Error<E>> {
×
NEW
255
        let data = self.read_register_async(Register::HOURS).await?;
×
NEW
256
        self.get_hours_from_register_async(data).await
×
257
    }
258

259
    /// Get weekday asynchronously.
NEW
260
    pub async fn weekday_async(&mut self) -> Result<u8, Error<E>> {
×
NEW
261
        self.read_register_decimal_async(Register::DOW).await
×
262
    }
263

264
    /// Get day asynchronously.
NEW
265
    pub async fn day_async(&mut self) -> Result<u8, Error<E>> {
×
NEW
266
        self.read_register_decimal_async(Register::DOM).await
×
267
    }
268

269
    /// Get month asynchronously.
NEW
270
    pub async fn month_async(&mut self) -> Result<u8, Error<E>> {
×
NEW
271
        self.read_register_decimal_async(Register::MONTH).await
×
272
    }
273

274
    /// Get year asynchronously.
NEW
275
    pub async fn year_async(&mut self) -> Result<u16, Error<E>> {
×
NEW
276
        let year = self.read_register_decimal_async(Register::YEAR).await?;
×
NEW
277
        Ok(2000 + u16::from(year))
×
278
    }
279

280
    /// Get date asynchronously.
NEW
281
    pub async fn date_async(&mut self) -> Result<NaiveDate, Error<E>> {
×
NEW
282
        let mut data = [0; 3];
×
NEW
283
        self.i2c
×
NEW
284
            .write_read(ADDR, &[Register::DOM], &mut data)
×
NEW
285
            .await
×
NEW
286
            .map_err(Error::I2C)?;
×
NEW
287
        let year = 2000 + u16::from(packed_bcd_to_decimal(data[2]));
×
NEW
288
        let month = packed_bcd_to_decimal(data[1]);
×
NEW
289
        let day = packed_bcd_to_decimal(data[0]);
×
NEW
290
        NaiveDate::from_ymd_opt(year.into(), month.into(), day.into())
×
NEW
291
            .ok_or(Error::InvalidInputData)
×
292
    }
293

294
    /// Get time asynchronously.
NEW
295
    pub async fn time_async(&mut self) -> Result<NaiveTime, Error<E>> {
×
NEW
296
        let mut data = [0; 3];
×
NEW
297
        self.i2c
×
NEW
298
            .write_read(ADDR, &[Register::SECONDS], &mut data)
×
NEW
299
            .await
×
NEW
300
            .map_err(Error::I2C)?;
×
NEW
301
        let hour = self
×
NEW
302
            .get_hours_from_register_async(data[Register::HOURS as usize])
×
NEW
303
            .await?;
×
NEW
304
        let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize]);
×
NEW
305
        let second = packed_bcd_to_decimal(remove_ch_bit(data[Register::SECONDS as usize]));
×
NEW
306
        NaiveTime::from_hms_opt(get_h24(hour).into(), minute.into(), second.into())
×
NEW
307
            .ok_or(Error::InvalidInputData)
×
308
    }
309

310
    /// Set seconds asynchronously.
NEW
311
    pub async fn set_seconds_async(&mut self, seconds: u8) -> Result<(), Error<E>> {
×
NEW
312
        if seconds > 59 {
×
NEW
313
            return Err(Error::InvalidInputData);
×
314
        }
NEW
315
        let data = self.read_register_async(Register::SECONDS).await?;
×
NEW
316
        self.write_register_async(
×
NEW
317
            Register::SECONDS,
×
NEW
318
            data & BitFlags::CH | decimal_to_packed_bcd(seconds),
×
319
        )
NEW
320
        .await
×
321
    }
322

323
    /// Set minutes asynchronously.
NEW
324
    pub async fn set_minutes_async(&mut self, minutes: u8) -> Result<(), Error<E>> {
×
NEW
325
        if minutes > 59 {
×
NEW
326
            return Err(Error::InvalidInputData);
×
327
        }
NEW
328
        self.write_register_decimal_async(Register::MINUTES, minutes)
×
NEW
329
            .await
×
330
    }
331

332
    /// Set hours asynchronously.
NEW
333
    pub async fn set_hours_async(&mut self, hours: Hours) -> Result<(), Error<E>> {
×
NEW
334
        let value = self.get_hours_register_value_async(hours).await?;
×
NEW
335
        self.write_register_async(Register::HOURS, value).await
×
336
    }
337

338
    /// Set weekday asynchronously.
NEW
339
    pub async fn set_weekday_async(&mut self, weekday: u8) -> Result<(), Error<E>> {
×
NEW
340
        if weekday < 1 || weekday > 7 {
×
NEW
341
            return Err(Error::InvalidInputData);
×
342
        }
NEW
343
        self.write_register_async(Register::DOW, weekday).await
×
344
    }
345

346
    /// Set day asynchronously.
NEW
347
    pub async fn set_day_async(&mut self, day: u8) -> Result<(), Error<E>> {
×
NEW
348
        if day < 1 || day > 31 {
×
NEW
349
            return Err(Error::InvalidInputData);
×
350
        }
NEW
351
        self.write_register_decimal_async(Register::DOM, day).await
×
352
    }
353

354
    /// Set month asynchronously.
NEW
355
    pub async fn set_month_async(&mut self, month: u8) -> Result<(), Error<E>> {
×
NEW
356
        if month < 1 || month > 12 {
×
NEW
357
            return Err(Error::InvalidInputData);
×
358
        }
NEW
359
        self.write_register_decimal_async(Register::MONTH, month)
×
NEW
360
            .await
×
361
    }
362

363
    /// Set year asynchronously.
NEW
364
    pub async fn set_year_async(&mut self, year: u16) -> Result<(), Error<E>> {
×
NEW
365
        if year < 2000 || year > 2099 {
×
NEW
366
            return Err(Error::InvalidInputData);
×
367
        }
NEW
368
        self.write_register_decimal_async(Register::YEAR, (year - 2000) as u8)
×
NEW
369
            .await
×
370
    }
371

372
    /// Set date asynchronously.
NEW
373
    pub async fn set_date_async(&mut self, date: &NaiveDate) -> Result<(), Error<E>> {
×
NEW
374
        if date.year() < 2000 || date.year() > 2099 {
×
NEW
375
            return Err(Error::InvalidInputData);
×
376
        }
NEW
377
        let payload = [
×
NEW
378
            Register::DOW,
×
NEW
379
            date.weekday().number_from_sunday() as u8,
×
NEW
380
            decimal_to_packed_bcd(date.day() as u8),
×
NEW
381
            decimal_to_packed_bcd(date.month() as u8),
×
NEW
382
            decimal_to_packed_bcd((date.year() - 2000) as u8),
×
383
        ];
NEW
384
        self.i2c.write(ADDR, &payload).await.map_err(Error::I2C)
×
385
    }
386

387
    /// Set time asynchronously.
NEW
388
    pub async fn set_time_async(&mut self, time: &NaiveTime) -> Result<(), Error<E>> {
×
NEW
389
        let hour = self
×
NEW
390
            .get_hours_register_value_async(Hours::H24(time.hour() as u8))
×
NEW
391
            .await?;
×
NEW
392
        let ch_flag = self.read_register_async(Register::SECONDS).await? & BitFlags::CH;
×
NEW
393
        let payload = [
×
NEW
394
            Register::SECONDS,
×
NEW
395
            decimal_to_packed_bcd(time.second() as u8) | ch_flag,
×
NEW
396
            decimal_to_packed_bcd(time.minute() as u8),
×
NEW
397
            hour,
×
398
        ];
NEW
399
        self.i2c.write(ADDR, &payload).await.map_err(Error::I2C)
×
400
    }
401
}
402

403
#[cfg(feature = "blocking")]
404
#[allow(clippy::manual_range_contains)]
405
impl<I2C, E> Ds1307<I2C>
406
where
407
    I2C: I2c<Error = E>,
408
{
409
    fn get_hours_from_register(&self, data: u8) -> Result<Hours, Error<E>> {
2✔
410
        if is_24h_format(data) {
4✔
411
            Ok(Hours::H24(packed_bcd_to_decimal(data & !BitFlags::H24_H12)))
2✔
412
        } else if is_am(data) {
2✔
413
            Ok(Hours::AM(packed_bcd_to_decimal(
1✔
414
                data & !(BitFlags::H24_H12 | BitFlags::AM_PM),
1✔
415
            )))
416
        } else {
417
            Ok(Hours::PM(packed_bcd_to_decimal(
1✔
418
                data & !(BitFlags::H24_H12 | BitFlags::AM_PM),
1✔
419
            )))
420
        }
421
    }
422

423
    fn get_hours_register_value(&mut self, hours: Hours) -> Result<u8, Error<E>> {
2✔
424
        match hours {
2✔
425
            Hours::H24(h) if h > 23 => Err(Error::InvalidInputData),
3✔
426
            Hours::H24(h) => Ok(decimal_to_packed_bcd(h)),
2✔
427
            Hours::AM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData),
2✔
428
            Hours::AM(h) => Ok(BitFlags::H24_H12 | decimal_to_packed_bcd(h)),
1✔
429
            Hours::PM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData),
2✔
430
            Hours::PM(h) => Ok(BitFlags::H24_H12 | BitFlags::AM_PM | decimal_to_packed_bcd(h)),
1✔
431
        }
432
    }
433

434
    fn read_register_decimal(&mut self, register: u8) -> Result<u8, Error<E>> {
1✔
435
        let data = self.read_register(register)?;
1✔
436
        Ok(packed_bcd_to_decimal(data))
1✔
437
    }
438

439
    fn write_register_decimal(&mut self, register: u8, decimal_number: u8) -> Result<(), Error<E>> {
1✔
440
        self.write_register(register, decimal_to_packed_bcd(decimal_number))
1✔
441
    }
442
}
443

444
#[cfg(feature = "async")]
445
#[allow(clippy::manual_range_contains)]
446
impl<I2C, E> Ds1307<I2C>
447
where
448
    I2C: AsyncI2c<Error = E>,
449
{
NEW
450
    async fn get_hours_from_register_async(&self, data: u8) -> Result<Hours, Error<E>> {
×
NEW
451
        if is_24h_format(data) {
×
NEW
452
            Ok(Hours::H24(packed_bcd_to_decimal(data & !BitFlags::H24_H12)))
×
NEW
453
        } else if is_am(data) {
×
NEW
454
            Ok(Hours::AM(packed_bcd_to_decimal(
×
NEW
455
                data & !(BitFlags::H24_H12 | BitFlags::AM_PM),
×
456
            )))
457
        } else {
NEW
458
            Ok(Hours::PM(packed_bcd_to_decimal(
×
NEW
459
                data & !(BitFlags::H24_H12 | BitFlags::AM_PM),
×
460
            )))
461
        }
462
    }
463

NEW
464
    async fn get_hours_register_value_async(&mut self, hours: Hours) -> Result<u8, Error<E>> {
×
NEW
465
        match hours {
×
NEW
466
            Hours::H24(h) if h > 23 => Err(Error::InvalidInputData),
×
NEW
467
            Hours::H24(h) => Ok(decimal_to_packed_bcd(h)),
×
NEW
468
            Hours::AM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData),
×
NEW
469
            Hours::AM(h) => Ok(BitFlags::H24_H12 | decimal_to_packed_bcd(h)),
×
NEW
470
            Hours::PM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData),
×
NEW
471
            Hours::PM(h) => Ok(BitFlags::H24_H12 | BitFlags::AM_PM | decimal_to_packed_bcd(h)),
×
472
        }
473
    }
474

NEW
475
    async fn read_register_decimal_async(&mut self, register: u8) -> Result<u8, Error<E>> {
×
NEW
476
        let data = self.read_register_async(register).await?;
×
NEW
477
        Ok(packed_bcd_to_decimal(data))
×
478
    }
479

480
    async fn write_register_decimal_async(
481
        &mut self,
482
        register: u8,
483
        decimal_number: u8,
484
    ) -> Result<(), Error<E>> {
NEW
485
        self.write_register_async(register, decimal_to_packed_bcd(decimal_number))
×
NEW
486
            .await
×
487
    }
488
}
489

490
fn is_24h_format(hours_data: u8) -> bool {
2✔
491
    hours_data & BitFlags::H24_H12 == 0
2✔
492
}
493

494
fn is_am(hours_data: u8) -> bool {
1✔
495
    hours_data & BitFlags::AM_PM == 0
1✔
496
}
497

498
fn remove_ch_bit(value: u8) -> u8 {
2✔
499
    value & !BitFlags::CH
2✔
500
}
501

502
/// Transforms a number in packed BCD format to decimal
503
fn packed_bcd_to_decimal(bcd: u8) -> u8 {
4✔
504
    (bcd >> 4) * 10 + (bcd & 0xF)
4✔
505
}
506

507
/// Transforms a decimal number to packed BCD format
508
fn decimal_to_packed_bcd(dec: u8) -> u8 {
4✔
509
    ((dec / 10) << 4) | (dec % 10)
4✔
510
}
511

512
fn get_h24(hour: Hours) -> u8 {
2✔
513
    match hour {
2✔
514
        Hours::H24(h) => h,
2✔
515
        Hours::AM(h) => h,
1✔
516
        Hours::PM(h) => h + 12,
2✔
517
    }
518
}
519

520
#[cfg(test)]
521
mod tests {
522
    use super::*;
523

524
    #[test]
525
    fn can_convert_to_h24() {
526
        assert_eq!(0, get_h24(Hours::H24(0)));
527
        assert_eq!(0, get_h24(Hours::AM(0)));
528
        assert_eq!(12, get_h24(Hours::PM(0)));
529

530
        assert_eq!(1, get_h24(Hours::H24(1)));
531
        assert_eq!(1, get_h24(Hours::AM(1)));
532
        assert_eq!(13, get_h24(Hours::PM(1)));
533

534
        assert_eq!(23, get_h24(Hours::H24(23)));
535
        assert_eq!(12, get_h24(Hours::AM(12)));
536
        assert_eq!(23, get_h24(Hours::PM(11)));
537
    }
538

539
    #[test]
540
    fn can_convert_packed_bcd_to_decimal() {
541
        assert_eq!(0, packed_bcd_to_decimal(0b0000_0000));
542
        assert_eq!(1, packed_bcd_to_decimal(0b0000_0001));
543
        assert_eq!(9, packed_bcd_to_decimal(0b0000_1001));
544
        assert_eq!(10, packed_bcd_to_decimal(0b0001_0000));
545
        assert_eq!(11, packed_bcd_to_decimal(0b0001_0001));
546
        assert_eq!(19, packed_bcd_to_decimal(0b0001_1001));
547
        assert_eq!(20, packed_bcd_to_decimal(0b0010_0000));
548
        assert_eq!(21, packed_bcd_to_decimal(0b0010_0001));
549
        assert_eq!(59, packed_bcd_to_decimal(0b0101_1001));
550
    }
551

552
    #[test]
553
    fn can_convert_decimal_to_packed_bcd() {
554
        assert_eq!(0b0000_0000, decimal_to_packed_bcd(0));
555
        assert_eq!(0b0000_0001, decimal_to_packed_bcd(1));
556
        assert_eq!(0b0000_1001, decimal_to_packed_bcd(9));
557
        assert_eq!(0b0001_0000, decimal_to_packed_bcd(10));
558
        assert_eq!(0b0001_0001, decimal_to_packed_bcd(11));
559
        assert_eq!(0b0001_1001, decimal_to_packed_bcd(19));
560
        assert_eq!(0b0010_0000, decimal_to_packed_bcd(20));
561
        assert_eq!(0b0010_0001, decimal_to_packed_bcd(21));
562
        assert_eq!(0b0101_1001, decimal_to_packed_bcd(59));
563
    }
564
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc