Skip to content

Commit fdf287e

Browse files
authored
fix #4 start() returns bool to indicate overflow (#6)
* fix #4 let start() detect overflow + refactor
1 parent 1e043f4 commit fdf287e

File tree

6 files changed

+137
-48
lines changed

6 files changed

+137
-48
lines changed

CountDown.cpp

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
11
//
22
// FILE: CountDown.cpp
33
// AUTHOR: Rob Tillaart
4-
// VERSION: 0.2.3
4+
// VERSION: 0.2.4
55
// PURPOSE: CountDown library for Arduino
66
// URL: https://github.com/RobTillaart/CountDown
77
//
8-
// HISTORY:
9-
// 0.2.3 2020-12-17 add arduino-ci + unit test
10-
// 0.2.2 2020-07-08 add MINUTES; refactor
11-
// 0.2.1 2020-06-05 fix library.json
12-
// 0.2.0 2020-03-29 #pragma once, removed pre 1.0 support
13-
// 0.1.3 2017-07-16 TODO improved seconds - OdoMeter see below ... TODO
14-
// 0.1.2 2017-07-16 added start(days, hours, minutes, seconds) + cont() == continue countdown
15-
// 0.1.1 2015-10-29 added start(h, m, s)
16-
// 0.1.0 2015-10-27 initial version
17-
//
8+
// HISTORY:
9+
// 0.2.4 2021-01-15 start detect overflow now.
10+
// 0.2.3 2020-12-17 add arduino-ci + unit test
11+
// 0.2.2 2020-07-08 add MINUTES; refactor
12+
// 0.2.1 2020-06-05 fix library.json
13+
// 0.2.0 2020-03-29 #pragma once, removed pre 1.0 support
14+
// 0.1.3 2017-07-16 TODO improved seconds - OdoMeter see below ... TODO
15+
// 0.1.2 2017-07-16 added start(days, hours, minutes, seconds) + cont() == continue countdown
16+
// 0.1.1 2015-10-29 added start(h, m, s)
17+
// 0.1.0 2015-10-27 initial version
18+
1819

1920
#include "CountDown.h"
2021

22+
2123
CountDown::CountDown(const enum Resolution res)
2224
{
2325
setResolution(res);
2426
stop();
2527
}
2628

29+
2730
void CountDown::setResolution(const enum Resolution res)
2831
{
2932
_res = res;
3033
_ticks = 0;
3134
}
3235

33-
void CountDown::start(uint32_t ticks)
36+
37+
bool CountDown::start(uint32_t ticks)
3438
{
3539
_ticks = ticks;
3640
_state = CountDown::RUNNING;
@@ -42,30 +46,45 @@ void CountDown::start(uint32_t ticks)
4246
{
4347
_starttime = millis();
4448
}
49+
return true; // can not overflow
4550
}
4651

47-
void CountDown::start(uint8_t days, uint16_t hours, uint32_t minutes, uint32_t seconds)
52+
53+
bool CountDown::start(uint8_t days, uint16_t hours, uint32_t minutes, uint32_t seconds)
4854
{
55+
float _days = seconds / 86400.0 + minutes / 1440.0 + hours / 24.0 + days;
56+
bool rv = (_days < 49.7102696);
57+
4958
uint32_t ticks = 86400UL * days + 3600UL * hours + 60UL * minutes + seconds;
5059
if (ticks > 4294967) ticks = 4294967; // prevent underlying millis() overflow
5160
setResolution(SECONDS);
5261
start(ticks);
62+
63+
return rv;
5364
}
5465

55-
void CountDown::start(uint8_t days, uint16_t hours, uint32_t minutes)
66+
67+
bool CountDown::start(uint8_t days, uint16_t hours, uint32_t minutes)
5668
{
69+
float _days = minutes / 1440.0 + hours / 24.0 + days;
70+
bool rv = (_days < 49.7102696);
71+
5772
uint32_t ticks = 86400UL * days + 3600UL * hours + 60UL * minutes;
5873
if (ticks > 4294967) ticks = 4294967; // prevent underlying millis() overflow
5974
setResolution(MINUTES);
6075
start(ticks);
76+
77+
return rv;
6178
}
6279

80+
6381
void CountDown::stop()
6482
{
6583
calcRemaining();
6684
_state = CountDown::STOPPED;
6785
}
6886

87+
6988
void CountDown::cont()
7089
{
7190
if (_state == CountDown::STOPPED)
@@ -74,20 +93,22 @@ void CountDown::cont()
7493
}
7594
}
7695

96+
7797
bool CountDown::isRunning()
7898
{
79-
if (_state == CountDown::STOPPED) return false;
80-
if (remaining() == 0) return false;
81-
return true;
99+
calcRemaining();
100+
return (_state == CountDown::RUNNING);
82101
}
83102

103+
84104
uint32_t CountDown::remaining()
85105
{
86106
calcRemaining();
87107
if (_remaining == 0) _state = CountDown::STOPPED;
88108
return _remaining;
89109
}
90110

111+
91112
void CountDown::calcRemaining()
92113
{
93114
uint32_t t = 0;
@@ -109,7 +130,7 @@ void CountDown::calcRemaining()
109130
t = millis() - _starttime;
110131
break;
111132
}
112-
_remaining = _ticks > t ? _ticks - t: 0;
133+
_remaining = _ticks > t ? _ticks - t : 0;
113134
if (_remaining == 0)
114135
{
115136
_state = CountDown::STOPPED;

CountDown.h

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,41 @@
22
//
33
// FILE: CountDown.h
44
// AUTHOR: Rob Tillaart
5-
// VERSION: 0.2.3
5+
// VERSION: 0.2.4
66
// PURPOSE: CountDown library for Arduino
77
// URL: https://github.com/RobTillaart/CountDown
88
//
99
// HISTORY: See CountDown.cpp
1010
//
1111

12+
1213
#include "Arduino.h"
1314

14-
#define COUNTDOWN_LIB_VERSION "0.2.3"
15+
16+
#define COUNTDOWN_LIB_VERSION (F("0.2.4"))
17+
1518

1619
class CountDown
1720
{
1821
public:
1922
enum Resolution { MILLIS, MICROS, SECONDS, MINUTES };
2023

2124
explicit CountDown(const enum Resolution res = MILLIS);
22-
void setResolution(const enum Resolution res = MILLIS);
2325

24-
void start(uint32_t ticks);
25-
// Implicit set resolution to SECONDS.
26-
void start(uint8_t days, uint16_t hours, uint32_t minutes, uint32_t seconds);
27-
// Implicit set resolution to MINUTES.
28-
void start(uint8_t days, uint16_t hours, uint32_t minutes);
29-
void stop();
30-
void cont();
26+
void setResolution(const enum Resolution res = MILLIS);
27+
28+
bool start(uint32_t ticks);
29+
// Implicit set resolution to SECONDS.
30+
bool start(uint8_t days, uint16_t hours, uint32_t minutes, uint32_t seconds);
31+
// Implicit set resolution to MINUTES.
32+
bool start(uint8_t days, uint16_t hours, uint32_t minutes);
33+
34+
void stop();
35+
void cont();
3136

3237
uint32_t remaining();
33-
bool isRunning();
34-
enum Resolution resolution() const { return _res; };
38+
bool isRunning();
39+
enum Resolution resolution() const { return _res; };
3540

3641
private:
3742
enum State { RUNNING, STOPPED };

README.md

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,47 +4,75 @@
44
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/CountDown/blob/master/LICENSE)
55
[![GitHub release](https://img.shields.io/github/release/RobTillaart/CountDown.svg?maxAge=3600)](https://github.com/RobTillaart/CountDown/releases)
66

7+
78
# CountDown
89

910
Arduino Library to implement a CountDown clock (in SW polling, no HW timer).
1011

12+
1113
## Description
1214

15+
The countdown library is a clock that counts down from a given time to zero.
16+
It does not call a function or so as the user is responsible to check the time remaining.
17+
Typically one checks the remaining time in every loop.
18+
19+
UNder the hood the function uses **micros()** or **millis()** which results in a maximum time
20+
of 4294 seconds in micros (1h10m) or something like 49+ days when using millis.
21+
22+
For longer periods one could cascade countDown, so when one is finished the next starts.
23+
24+
25+
## Interface
26+
1327
The main functions of the CountDown clock are:
1428

15-
- **void start(ticks);**
16-
- **void start(days, hours, minutes, seconds);**
17-
- **void start(days, hours, minutes);**
18-
- **void stop();**
19-
- **void cont();** *(continue is a C-Keyword)*
20-
- **uint32_t remaining();**
21-
- **bool isRunning();**
29+
- **bool start(ticks)**
30+
- **bool start(days, hours, minutes, seconds)**
31+
- **bool start(days, hours, minutes)**
32+
- **void stop()**
33+
- **void cont()** *(continue is a C-Keyword)*
34+
- **uint32_t remaining()**
35+
- **bool isRunning()**
2236

2337
These functions work straightforward.
2438

39+
40+
## Operation
41+
2542
The function **start(days, hours, minutes, seconds)** has changed its
2643
parameters type to minimize them, given that the total time may not exceed 2^32 milliseconds.
2744
This allows the user to call **start()** with e.g. four hundred minutes **start(0, 0, 400, 0)**
2845
or a million seconds **start(0, 0, 0, 1000000)** as parameter.
29-
The resolution is implicitly set to *SECONDS*.
30-
31-
Note: the function **start()** does not check if the parameters cause an overflow
32-
in the underlying math. That is responsibility of the user.
46+
The resolution is implicitly set to **SECONDS**.
3347

34-
The function **start(days, hours, minutes)** is new since 0.2.2.
35-
It also uses **millis()** under the hood. The resolution is implicitly set to *MINUTES*.
48+
Since 0.2.4 the function **start()** will check if the parameters cause an overflow
49+
in the underlying math. If there is no overflow call to **start()** returns true.
50+
If there is an overflow it returns false
3651

3752
Total amount of time to countdown for **MICROS** may not exceed 2\^32 micros ~ 1hr 10 minutes.
3853
Total amount of time to countdown for **MILLIS**, **SECONDS** and **MINUTES**
3954
may not exceed 2\^32 millis ~49 days
4055

41-
## Operation
56+
57+
The function **start(days, hours, minutes)** is new since 0.2.2.
58+
It also uses **millis()** under the hood. The resolution is implicitly set to **MINUTES**.
59+
60+
61+
| Call to start() | resolution | max time | comments |
62+
|:--------------------------------------|:-----------------|:---------:|:---------|
63+
| start(days, hours, minutes, seconds) | SECONDS = millis | 49+ days |
64+
| start(days, hours, minutes) | MINUTES = millis | 49+ days |
65+
| start(ticks) | MILLIS = millis | 49+ days | default |
66+
| start(ticks) | MICROS = micros | ~70 min | use setResolution(MICROS) |
67+
| start(ticks) | SECONDS = millis | 49+ days | use setResolution(SECONDS) |
68+
| start(ticks) | MINUTES = millis | 49+ days | use setResolution(MINUTES) |
69+
4270

4371
The Countdown clock uses by default **millis()** to do the time keeping,
4472
although this can be changed runtime by **setResolution(res)**. The parameter
4573
**res** can be:
4674
- **MICROS**
47-
- **MILLIS**
75+
- **MILLIS** // default
4876
- **SECONDS** // based upon millis()
4977
- **MINUTES** // based upon millis()
5078

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"type": "git",
1616
"url": "https://github.com/RobTillaart/CountDown.git"
1717
},
18-
"version":"0.2.3",
18+
"version":"0.2.4",
1919
"frameworks": "arduino",
2020
"platforms": "*"
2121
}

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=CountDown
2-
version=0.2.3
2+
version=0.2.4
33
author=Rob Tillaart <rob.tillaart@gmail.com>
44
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
55
sentence=Arduino library to implement a CountDown clock in SW.

test/unit_test_001.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,29 +40,45 @@ unittest_teardown()
4040

4141
unittest(test_constructor)
4242
{
43+
fprintf(stderr, "VERSION: %s\n", COUNTDOWN_LIB_VERSION);
44+
4345
CountDown a(CountDown::MINUTES);
4446
CountDown b(CountDown::SECONDS);
4547
CountDown c(CountDown::MILLIS);
4648
CountDown d(CountDown::MICROS);
49+
CountDown e; // default MILLIS
4750

4851
assertEqual(CountDown::MINUTES, a.resolution());
4952
assertEqual(CountDown::SECONDS, b.resolution());
5053
assertEqual(CountDown::MILLIS, c.resolution());
5154
assertEqual(CountDown::MICROS, d.resolution());
55+
assertEqual(CountDown::MILLIS, e.resolution());
56+
57+
fprintf(stderr, "\nisRunning\n");
5258

5359
assertFalse(a.isRunning());
5460
assertFalse(b.isRunning());
5561
assertFalse(c.isRunning());
5662
assertFalse(d.isRunning());
63+
assertFalse(e.isRunning());
5764

58-
a.start(10);
65+
fprintf(stderr, "\nbase\n");
66+
67+
a.setResolution(CountDown::SECONDS);
68+
assertTrue(a.start(10));
5969
assertTrue(a.isRunning());
70+
6071
a.stop();
6172
assertFalse(a.isRunning());
73+
6274
a.cont();
6375
assertTrue(a.isRunning());
76+
6477
a.stop();
6578
assertFalse(a.isRunning());
79+
80+
assertTrue(a.start(0));
81+
assertFalse(a.isRunning());
6682
}
6783

6884

@@ -87,6 +103,25 @@ unittest(test_run)
87103

88104
}
89105

106+
107+
unittest(test_overflow)
108+
{
109+
CountDown cd;
110+
assertEqual(CountDown::MILLIS, cd.resolution());
111+
112+
assertFalse(cd.isRunning());
113+
assertFalse(cd.start(50, 0, 0));
114+
assertFalse(cd.start(50, 0, 0, 0));
115+
116+
assertFalse(cd.start(0, 1200, 0));
117+
assertFalse(cd.start(0, 1200, 0, 0));
118+
119+
assertFalse(cd.start(0, 0, 72000));
120+
assertFalse(cd.start(0, 0, 72000, 0));
121+
122+
assertFalse(cd.start(0, 0, 0, 4320000));
123+
}
124+
90125
unittest_main()
91126

92127
// --------

0 commit comments

Comments
 (0)