├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── custom.md
│ └── feature_request.md
└── workflows
│ ├── stale.yml
│ └── sync_issues.yml
├── .gitignore
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── examples
├── alarm_samd21
│ └── alarm_samd21.ino
├── alarm_samd51
│ └── alarm_samd51.ino
├── rtc_samd21
│ └── rtc_samd21.ino
└── rtc_samd51
│ └── rtc_samd51.ino
├── keywords.txt
├── library.properties
└── src
├── DateTime.cpp
├── DateTime.h
├── RTC_SAMD21.cpp
├── RTC_SAMD21.h
├── RTC_SAMD51.cpp
└── RTC_SAMD51.h
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: 'Close stale issues and PRs'
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: '0 4 * * *'
7 |
8 | jobs:
9 | stale:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Checkout repository
14 | uses: actions/checkout@v4
15 |
16 | - name: Checkout script repository
17 | uses: actions/checkout@v4
18 | with:
19 | repository: Seeed-Studio/sync-github-all-issues
20 | path: ci
21 |
22 | - name: Run script
23 | run: ./ci/tools/stale.sh
24 | env:
25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26 |
--------------------------------------------------------------------------------
/.github/workflows/sync_issues.yml:
--------------------------------------------------------------------------------
1 | name: Automate Issue Management
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 | - edited
8 | - assigned
9 | - unassigned
10 | - labeled
11 | - unlabeled
12 | - reopened
13 |
14 | jobs:
15 | add_issue_to_project:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Add issue to GitHub Project
19 | uses: actions/add-to-project@v1.0.2
20 | with:
21 | project-url: https://github.com/orgs/Seeed-Studio/projects/17
22 | github-token: ${{ secrets.ISSUE_ASSEMBLE }}
23 | labeled: bug
24 | label-operator: NOT
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: generic
2 | dist: bionic
3 | sudo: false
4 | cache:
5 | directories:
6 | - ~/arduino_ide
7 | - ~/.arduino15/packages/
8 |
9 | before_install:
10 | - wget -c https://files.seeedstudio.com/arduino/seeed-arduino-ci.sh
11 | script:
12 | - chmod +x seeed-arduino-ci.sh
13 | - cat $PWD/seeed-arduino-ci.sh
14 | - $PWD/seeed-arduino-ci.sh -b "Seeeduino:samd:seeed_wio_terminal" -s rtc_samd51/alarm_samd51
15 | - $PWD/seeed-arduino-ci.sh -b "Seeeduino:samd:seeed_XIAO_m0" -s rtc_samd21/alarm_samd21
16 |
17 | notifications:
18 | email:
19 | on_success: change
20 | on_failure: change
21 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at zuobaozhu@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing guidelines
2 |
3 | All guidelines for contributing to the Seeed_Arduino_RTC repository can be found at [`How to contribute guideline`](https://github.com/Seeed-Studio/Seeed_Arduino_RTC/wiki/How_to_contribute).
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Seeed Studio
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Seeed_Arduino_RTC [](https://travis-ci.com/Seeed-Studio/Seeed_Arduino_RTC)
2 | ## Introduction
3 | Seeed Arduino RTC is a Arduino library for RTC Moudle. At present, samd21 is supported and samd51 has built-in RTC module.
4 | ## How to install Arduino Library
5 | please refer [here](https://wiki.seeedstudio.com/How_to_install_Arduino_Library/).
6 |
7 | ## Usage
8 |
9 | ```C++
10 | #include "RTC_SAMD21.h"
11 | #include "DateTime.h"
12 |
13 | RTC_SAMD21 rtc;
14 | void setup()
15 | {
16 | rtc.begin();
17 |
18 | Serial.begin(115200);
19 |
20 | while (!Serial)
21 | {
22 | ;
23 | }
24 |
25 | DateTime now = DateTime(F(__DATE__), F(__TIME__));
26 | Serial.println("adjust time!");
27 | rtc.adjust(now);
28 |
29 | now = rtc.now();
30 |
31 | Serial.print(now.year(), DEC);
32 | Serial.print('/');
33 | Serial.print(now.month(), DEC);
34 | Serial.print('/');
35 | Serial.print(now.day(), DEC);
36 | Serial.print(" ");
37 | Serial.print(now.hour(), DEC);
38 | Serial.print(':');
39 | Serial.print(now.minute(), DEC);
40 | Serial.print(':');
41 | Serial.print(now.second(), DEC);
42 | Serial.println();
43 |
44 | }
45 | void loop()
46 | {
47 | now = rtc.now();
48 |
49 | Serial.print(now.year(), DEC);
50 | Serial.print('/');
51 | Serial.print(now.month(), DEC);
52 | Serial.print('/');
53 | Serial.print(now.day(), DEC);
54 | Serial.print(" ");
55 | Serial.print(now.hour(), DEC);
56 | Serial.print(':');
57 | Serial.print(now.minute(), DEC);
58 | Serial.print(':');
59 | Serial.print(now.second(), DEC);
60 | Serial.println();
61 |
62 | }
63 |
64 | ```
65 |
66 | ## API Reference
67 | - **begin(*void*) : bool**
68 | ```C++
69 | rtc.begin()
70 | ```
71 | - **now(*void*) : DateTime**
72 | ```C++
73 | DateTime now = rtc.now();
74 | ```
75 | - **adjust(*const DateTime*) : void**
76 | ```C++
77 | DateTime now = DateTime(F(__DATE__), F(__TIME__));
78 | rtc.adjust(now);
79 | DateTime now = DateTime(2020, 7, 15, 0, 0, 0);
80 | rtc.adjust(now);
81 | ```
82 | - **setAlarm(*const DateTime*) : void**
83 | ```C++
84 | DateTime alarm = DateTime(2020, 7, 15, 18, 0, 0);
85 | rtc.setAlarm(now);
86 | ```
87 | - **alarm(*void*) : DateTime**
88 | ```C++
89 | DateTime now = rtc.alarm();
90 | ```
91 | - **disableAlarm(*uint8_t*) : void**
92 | ```C++
93 | rtc.disableAlarm(0);
94 | ```
95 | - **enableAlarm(*uint8_t*) : void**
96 | ```C++
97 | rtc.enableAlarm(0);
98 | ```
99 | - **attachInterrupt(*rtcCallBack*) : void**
100 | ```C++
101 | rtc.attachInterrupt(rtcCallBack);
102 | ```
103 | - **detachInterrupt(*void*) : void**
104 | ```C++
105 | rtc.detachInterrupt();
106 | ```
107 |
108 | ----
109 | ## License
110 | This software is written by seeed studio
111 | and is licensed under [The MIT License](http://opensource.org/licenses/mit-license.php). Check License.txt for more information.
112 |
113 | Contributing to this software is warmly welcomed. You can do this basically by
114 | [forking](https://help.github.com/articles/fork-a-repo), committing modifications and then [pulling requests](https://help.github.com/articles/using-pull-requests) (follow the links above
115 | for operating guide). Adding change log and your contact into file header is encouraged.
116 | Thanks for your contribution.
117 |
118 | Seeed Studio is an open hardware facilitation company based in Shenzhen, China.
119 | Benefiting from local manufacture power and convenient global logistic system,
120 | we integrate resources to serve new era of innovation. Seeed also works with
121 | global distributors and partners to push open hardware movement.
--------------------------------------------------------------------------------
/examples/alarm_samd21/alarm_samd21.ino:
--------------------------------------------------------------------------------
1 | #include "RTC_SAMD21.h"
2 | #include "DateTime.h"
3 |
4 | RTC_SAMD21 rtc;
5 | void setup()
6 | {
7 | rtc.begin();
8 |
9 | Serial.begin(115200);
10 |
11 | while (!Serial)
12 | {
13 | ;
14 | }
15 |
16 |
17 | DateTime now = DateTime(F(__DATE__), F(__TIME__));
18 |
19 | //!!! notice The year is limited to 2000-2099
20 | Serial.println("adjust time!");
21 | rtc.adjust(now);
22 |
23 | now = rtc.now();
24 |
25 | Serial.print(now.year(), DEC);
26 | Serial.print('/');
27 | Serial.print(now.month(), DEC);
28 | Serial.print('/');
29 | Serial.print(now.day(), DEC);
30 | Serial.print(" ");
31 | Serial.print(now.hour(), DEC);
32 | Serial.print(':');
33 | Serial.print(now.minute(), DEC);
34 | Serial.print(':');
35 | Serial.print(now.second(), DEC);
36 | Serial.println();
37 |
38 | DateTime alarm = DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second() + 15);
39 |
40 | rtc.setAlarm(alarm); // match after 15 seconds
41 | rtc.enableAlarm(rtc.MATCH_HHMMSS); // match Every Day
42 |
43 | rtc.attachInterrupt(alarmMatch); // callback while alarm is match
44 |
45 | }
46 |
47 | void loop()
48 | {
49 | }
50 |
51 | void alarmMatch()
52 | {
53 |
54 | Serial.println("Alarm Match!");
55 | DateTime now = rtc.now();
56 | Serial.print(now.year(), DEC);
57 | Serial.print('/');
58 | Serial.print(now.month(), DEC);
59 | Serial.print('/');
60 | Serial.print(now.day(), DEC);
61 | Serial.print(" ");
62 | Serial.print(now.hour(), DEC);
63 | Serial.print(':');
64 | Serial.print(now.minute(), DEC);
65 | Serial.print(':');
66 | Serial.print(now.second(), DEC);
67 | Serial.println();
68 | }
69 |
--------------------------------------------------------------------------------
/examples/alarm_samd51/alarm_samd51.ino:
--------------------------------------------------------------------------------
1 | #include "RTC_SAMD51.h"
2 | #include "DateTime.h"
3 |
4 | RTC_SAMD51 rtc;
5 | void setup()
6 | {
7 | rtc.begin();
8 |
9 | Serial.begin(115200);
10 |
11 | while (!Serial)
12 | {
13 | ;
14 | }
15 |
16 |
17 | DateTime now = DateTime(F(__DATE__), F(__TIME__));
18 |
19 | //!!! notice The year is limited to 2000-2099
20 | Serial.println("adjust time!");
21 | rtc.adjust(now);
22 |
23 | now = rtc.now();
24 |
25 | Serial.print(now.year(), DEC);
26 | Serial.print('/');
27 | Serial.print(now.month(), DEC);
28 | Serial.print('/');
29 | Serial.print(now.day(), DEC);
30 | Serial.print(" ");
31 | Serial.print(now.hour(), DEC);
32 | Serial.print(':');
33 | Serial.print(now.minute(), DEC);
34 | Serial.print(':');
35 | Serial.print(now.second(), DEC);
36 | Serial.println();
37 |
38 | DateTime alarm = DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second() + 15);
39 |
40 | rtc.setAlarm(0,alarm); // match after 15 seconds
41 | rtc.enableAlarm(0, rtc.MATCH_HHMMSS); // match Every Day
42 |
43 | rtc.attachInterrupt(alarmMatch); // callback while alarm is match
44 |
45 | }
46 |
47 | void loop()
48 | {
49 | }
50 |
51 | void alarmMatch(uint32_t flag)
52 | {
53 |
54 | Serial.println("Alarm Match!");
55 | DateTime now = rtc.now();
56 | Serial.print(now.year(), DEC);
57 | Serial.print('/');
58 | Serial.print(now.month(), DEC);
59 | Serial.print('/');
60 | Serial.print(now.day(), DEC);
61 | Serial.print(" ");
62 | Serial.print(now.hour(), DEC);
63 | Serial.print(':');
64 | Serial.print(now.minute(), DEC);
65 | Serial.print(':');
66 | Serial.print(now.second(), DEC);
67 | Serial.println();
68 | }
69 |
--------------------------------------------------------------------------------
/examples/rtc_samd21/rtc_samd21.ino:
--------------------------------------------------------------------------------
1 | #include "RTC_SAMD21.h"
2 | #include "DateTime.h"
3 |
4 | RTC_SAMD21 rtc;
5 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
6 | void setup()
7 | {
8 | Serial.begin(115200);
9 | rtc.begin();
10 |
11 | DateTime now = DateTime(F(__DATE__), F(__TIME__));
12 | //!!! notice The year is limited to 2000-2099
13 | Serial.println("adjust time!");
14 | rtc.adjust(now);
15 |
16 | }
17 |
18 | void loop()
19 | {
20 |
21 | DateTime now = rtc.now();
22 |
23 | Serial.print(now.year(), DEC);
24 | Serial.print('/');
25 | Serial.print(now.month(), DEC);
26 | Serial.print('/');
27 | Serial.print(now.day(), DEC);
28 |
29 | Serial.print(" (");
30 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
31 | Serial.print(") ");
32 | Serial.print(now.hour(), DEC);
33 | Serial.print(':');
34 | Serial.print(now.minute(), DEC);
35 | Serial.print(':');
36 | Serial.print(now.second(), DEC);
37 | Serial.println();
38 |
39 | Serial.print(" since midnight 1/1/1970 = ");
40 | Serial.print(now.unixtime());
41 | Serial.print("s = ");
42 | Serial.print(now.unixtime() / 86400L);
43 | Serial.println("d");
44 |
45 | // calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future
46 | DateTime future(now + TimeSpan(7, 12, 30, 6));
47 |
48 | Serial.print(" now + 7d + 12h + 30m + 6s: ");
49 | Serial.print(future.year(), DEC);
50 | Serial.print('/');
51 | Serial.print(future.month(), DEC);
52 | Serial.print('/');
53 | Serial.print(future.day(), DEC);
54 | Serial.print(' ');
55 | Serial.print(future.hour(), DEC);
56 | Serial.print(':');
57 | Serial.print(future.minute(), DEC);
58 | Serial.print(':');
59 | Serial.print(future.second(), DEC);
60 | Serial.println();
61 |
62 | Serial.println();
63 | delay(1000);
64 | }
65 |
--------------------------------------------------------------------------------
/examples/rtc_samd51/rtc_samd51.ino:
--------------------------------------------------------------------------------
1 | #include "RTC_SAMD51.h"
2 | #include "DateTime.h"
3 |
4 | RTC_SAMD51 rtc;
5 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
6 | void setup()
7 | {
8 | Serial.begin(115200);
9 | rtc.begin();
10 |
11 | DateTime now = DateTime(F(__DATE__), F(__TIME__));
12 | //!!! notice The year is limited to 2000-2099
13 | Serial.println("adjust time!");
14 | rtc.adjust(now);
15 |
16 | }
17 |
18 | void loop()
19 | {
20 |
21 | DateTime now = rtc.now();
22 |
23 | Serial.print(now.year(), DEC);
24 | Serial.print('/');
25 | Serial.print(now.month(), DEC);
26 | Serial.print('/');
27 | Serial.print(now.day(), DEC);
28 |
29 | Serial.print(" (");
30 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
31 | Serial.print(") ");
32 | Serial.print(now.hour(), DEC);
33 | Serial.print(':');
34 | Serial.print(now.minute(), DEC);
35 | Serial.print(':');
36 | Serial.print(now.second(), DEC);
37 | Serial.println();
38 |
39 | Serial.print(" since midnight 1/1/1970 = ");
40 | Serial.print(now.unixtime());
41 | Serial.print("s = ");
42 | Serial.print(now.unixtime() / 86400L);
43 | Serial.println("d");
44 |
45 | // calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future
46 | DateTime future(now + TimeSpan(7, 12, 30, 6));
47 |
48 | Serial.print(" now + 7d + 12h + 30m + 6s: ");
49 | Serial.print(future.year(), DEC);
50 | Serial.print('/');
51 | Serial.print(future.month(), DEC);
52 | Serial.print('/');
53 | Serial.print(future.day(), DEC);
54 | Serial.print(' ');
55 | Serial.print(future.hour(), DEC);
56 | Serial.print(':');
57 | Serial.print(future.minute(), DEC);
58 | Serial.print(':');
59 | Serial.print(future.second(), DEC);
60 | Serial.println();
61 |
62 | Serial.println();
63 | delay(1000);
64 | }
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 | #######################################
2 | # Syntax Coloring Map For Seeed Arduino RTC
3 | #######################################
4 |
5 | #######################################
6 | # Datatypes (KEYWORD1)
7 | #######################################
8 |
9 | DateTime KEYWORD1
10 | TimeSpan KEYWORD1
11 | RTC_SAMD21 KEYWORD1
12 | RTC_SAMD51 KEYWORD1
13 |
14 |
15 | #######################################
16 | # Methods and Functions (KEYWORD2)
17 | #######################################
18 |
19 | year KEYWORD2
20 | month KEYWORD2
21 | day KEYWORD2
22 | hour KEYWORD2
23 | twelveHour KEYWORD2
24 | isPM KEYWORD2
25 | minute KEYWORD2
26 | second KEYWORD2
27 | dayOfTheWeek KEYWORD2
28 | secondstime KEYWORD2
29 | unixtime KEYWORD2
30 | days KEYWORD2
31 | hours KEYWORD2
32 | minutes KEYWORD2
33 | seconds KEYWORD2
34 | totalseconds KEYWORD2
35 | begin KEYWORD2
36 | adjust KEYWORD2
37 | now KEYWORD2
38 | timestamp KEYWORD2
39 | toString KEYWORD2
40 | writenvram KEYWORD2
41 | setAlarm KEYWORD2
42 | disableAlarm KEYWORD2
43 |
44 | #######################################
45 | # Constants (LITERAL1)
46 | #######################################
47 | TIMESTAMP_FULL LITERAL1
48 | TIMESTAMP_DATE LITERAL1
49 | TIMESTAMP_TIME LITERAL1
50 |
51 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=Seeed Arduino RTC
2 | version=2.0.0
3 | author=Seeed Studio
4 | maintainer=Seeed Studio
5 | sentence=RTC library for SAMD21 and SAMD51.
6 | paragraph=When your project needs to be unplugged, how to keep the time counting? This library can help you keep the current time
7 | category=Timing
8 | url=https://github.com/Seeed-Studio/Seeed_Arduino_RTC
9 | architectures=samd
10 |
--------------------------------------------------------------------------------
/src/DateTime.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | @file RTClib.h
4 | Original library by JeeLabs http://news.jeelabs.org/code/, released to the
5 | public domain
6 | License: MIT (see LICENSE)
7 | This is a fork of JeeLab's fantastic real time clock library for Arduino.
8 | For details on using this library with an RTC module like the DS1307, PCF8523,
9 | or DS3231, see the guide at:
10 | https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
11 | Adafruit invests time and resources providing this open source code,
12 | please support Adafruit and open-source hardware by purchasing
13 | products from Adafruit!
14 | */
15 | /**************************************************************************/
16 |
17 |
18 | #include "DateTime.h"
19 |
20 |
21 | /**
22 | Number of days in each month, from January to November. December is not
23 | needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time
24 | library. C.f. https://github.com/adafruit/RTClib/issues/114
25 | */
26 | static const uint8_t daysInMonth[] PROGMEM = {31, 28, 31, 30, 31, 30,
27 | 31, 31, 30, 31, 30};
28 |
29 | /**************************************************************************/
30 | /*!
31 | @brief Given a date, return number of days since 2000/01/01,
32 | valid for 2000--2099
33 | @param y Year
34 | @param m Month
35 | @param d Day
36 | @return Number of days
37 | */
38 | /**************************************************************************/
39 | static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
40 | if (y >= 2000)
41 | y -= 2000;
42 | uint16_t days = d;
43 | for (uint8_t i = 1; i < m; ++i)
44 | days += pgm_read_byte(daysInMonth + i - 1);
45 | if (m > 2 && y % 4 == 0)
46 | ++days;
47 | return days + 365 * y + (y + 3) / 4 - 1;
48 | }
49 |
50 | /**************************************************************************/
51 | /*!
52 | @brief Given a number of days, hours, minutes, and seconds, return the
53 | total seconds
54 | @param days Days
55 | @param h Hours
56 | @param m Minutes
57 | @param s Seconds
58 | @return Number of seconds total
59 | */
60 | /**************************************************************************/
61 | static uint32_t time2ulong(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
62 | return ((days * 24UL + h) * 60 + m) * 60 + s;
63 | }
64 |
65 |
66 | /**************************************************************************/
67 | /*!
68 | @brief Constructor from
69 | [Unix time](https://en.wikipedia.org/wiki/Unix_time).
70 | This builds a DateTime from an integer specifying the number of seconds
71 | elapsed since the epoch: 1970-01-01 00:00:00. This number is analogous
72 | to Unix time, with two small differences:
73 | - The Unix epoch is specified to be at 00:00:00
74 | [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time),
75 | whereas this class has no notion of time zones. The epoch used in
76 | this class is then at 00:00:00 on whatever time zone the user chooses
77 | to use, ignoring changes in DST.
78 | - Unix time is conventionally represented with signed numbers, whereas
79 | this constructor takes an unsigned argument. Because of this, it does
80 | _not_ suffer from the
81 | [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem).
82 | If called without argument, it returns the earliest time representable
83 | by this class: 2000-01-01 00:00:00.
84 | @see The `unixtime()` method is the converse of this constructor.
85 | @param t Time elapsed in seconds since 1970-01-01 00:00:00.
86 | */
87 | /**************************************************************************/
88 | DateTime::DateTime(uint32_t t) {
89 | t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970
90 |
91 | ss = t % 60;
92 | t /= 60;
93 | mm = t % 60;
94 | t /= 60;
95 | hh = t % 24;
96 | uint16_t days = t / 24;
97 | uint8_t leap;
98 | for (yOff = 0;; ++yOff) {
99 | leap = yOff % 4 == 0;
100 | if (days < 365U + leap)
101 | break;
102 | days -= 365 + leap;
103 | }
104 | for (m = 1; m < 12; ++m) {
105 | uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
106 | if (leap && m == 2)
107 | ++daysPerMonth;
108 | if (days < daysPerMonth)
109 | break;
110 | days -= daysPerMonth;
111 | }
112 | d = days + 1;
113 | }
114 |
115 | /**************************************************************************/
116 | /*!
117 | @brief Constructor from (year, month, day, hour, minute, second).
118 | @warning If the provided parameters are not valid (e.g. 31 February),
119 | the constructed DateTime will be invalid.
120 | @see The `isValid()` method can be used to test whether the
121 | constructed DateTime is valid.
122 | @param year Either the full year (range: 2000--2099) or the offset from
123 | year 2000 (range: 0--99).
124 | @param month Month number (1--12).
125 | @param day Day of the month (1--31).
126 | @param hour,min,sec Hour (0--23), minute (0--59) and second (0--59).
127 | */
128 | /**************************************************************************/
129 | DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
130 | uint8_t min, uint8_t sec) {
131 | if (year >= 2000)
132 | year -= 2000;
133 | yOff = year;
134 | m = month;
135 | d = day;
136 | hh = hour;
137 | mm = min;
138 | ss = sec;
139 | }
140 |
141 | /**************************************************************************/
142 | /*!
143 | @brief Copy constructor.
144 | @param copy DateTime to copy.
145 | */
146 | /**************************************************************************/
147 | DateTime::DateTime(const DateTime ©)
148 | : yOff(copy.yOff), m(copy.m), d(copy.d), hh(copy.hh), mm(copy.mm),
149 | ss(copy.ss) {}
150 |
151 |
152 | /**************************************************************************/
153 | /*!
154 | @brief Convert a string containing two digits to uint8_t, e.g. "09" returns
155 | 9
156 | @param p Pointer to a string containing two digits
157 | */
158 | /**************************************************************************/
159 | static uint8_t conv2d(const char *p) {
160 | uint8_t v = 0;
161 | if ('0' <= *p && *p <= '9')
162 | v = *p - '0';
163 | return 10 * v + *++p - '0';
164 | }
165 |
166 | /**************************************************************************/
167 | /*!
168 | @brief Constructor for generating the build time.
169 | This constructor expects its parameters to be strings in the format
170 | generated by the compiler's preprocessor macros `__DATE__` and
171 | `__TIME__`. Usage:
172 | ```
173 | DateTime buildTime(__DATE__, __TIME__);
174 | ```
175 | @note The `F()` macro can be used to reduce the RAM footprint, see
176 | the next constructor.
177 | @param date Date string, e.g. "Apr 16 2020".
178 | @param time Time string, e.g. "18:34:56".
179 | */
180 | /**************************************************************************/
181 | DateTime::DateTime(const char *date, const char *time) {
182 | yOff = conv2d(date + 9);
183 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
184 | switch (date[0]) {
185 | case 'J':
186 | m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7);
187 | break;
188 | case 'F':
189 | m = 2;
190 | break;
191 | case 'A':
192 | m = date[2] == 'r' ? 4 : 8;
193 | break;
194 | case 'M':
195 | m = date[2] == 'r' ? 3 : 5;
196 | break;
197 | case 'S':
198 | m = 9;
199 | break;
200 | case 'O':
201 | m = 10;
202 | break;
203 | case 'N':
204 | m = 11;
205 | break;
206 | case 'D':
207 | m = 12;
208 | break;
209 | }
210 | d = conv2d(date + 4);
211 | hh = conv2d(time);
212 | mm = conv2d(time + 3);
213 | ss = conv2d(time + 6);
214 | }
215 |
216 | /**************************************************************************/
217 | /*!
218 | @brief Memory friendly constructor for generating the build time.
219 | This version is intended to save RAM by keeping the date and time
220 | strings in program memory. Use it with the `F()` macro:
221 | ```
222 | DateTime buildTime(F(__DATE__), F(__TIME__));
223 | ```
224 | @param date Date PROGMEM string, e.g. F("Apr 16 2020").
225 | @param time Time PROGMEM string, e.g. F("18:34:56").
226 | */
227 | /**************************************************************************/
228 | DateTime::DateTime(const __FlashStringHelper *date,
229 | const __FlashStringHelper *time) {
230 | char buff[11];
231 | memcpy_P(buff, date, 11);
232 | yOff = conv2d(buff + 9);
233 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
234 | switch (buff[0]) {
235 | case 'J':
236 | m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7);
237 | break;
238 | case 'F':
239 | m = 2;
240 | break;
241 | case 'A':
242 | m = buff[2] == 'r' ? 4 : 8;
243 | break;
244 | case 'M':
245 | m = buff[2] == 'r' ? 3 : 5;
246 | break;
247 | case 'S':
248 | m = 9;
249 | break;
250 | case 'O':
251 | m = 10;
252 | break;
253 | case 'N':
254 | m = 11;
255 | break;
256 | case 'D':
257 | m = 12;
258 | break;
259 | }
260 | d = conv2d(buff + 4);
261 | memcpy_P(buff, time, 8);
262 | hh = conv2d(buff);
263 | mm = conv2d(buff + 3);
264 | ss = conv2d(buff + 6);
265 | }
266 |
267 | /**************************************************************************/
268 | /*!
269 | @brief Constructor for creating a DateTime from an ISO8601 date string.
270 | This constructor expects its parameters to be a string in the
271 | https://en.wikipedia.org/wiki/ISO_8601 format, e.g:
272 | "2020-06-25T15:29:37"
273 | Usage:
274 | ```
275 | DateTime dt("2020-06-25T15:29:37");
276 | ```
277 | @note The year must be > 2000, as only the yOff is considered.
278 | @param iso8601dateTime
279 | A dateTime string in iso8601 format,
280 | e.g. "2020-06-25T15:29:37".
281 | */
282 | /**************************************************************************/
283 | DateTime::DateTime(const char *iso8601dateTime) {
284 | char ref[] = "2000-01-01T00:00:00";
285 | memcpy(ref, iso8601dateTime, min(strlen(ref), strlen(iso8601dateTime)));
286 | yOff = conv2d(ref + 2);
287 | m = conv2d(ref + 5);
288 | d = conv2d(ref + 8);
289 | hh = conv2d(ref + 11);
290 | mm = conv2d(ref + 14);
291 | ss = conv2d(ref + 17);
292 | }
293 |
294 | /**************************************************************************/
295 | /*!
296 | @brief Check whether this DateTime is valid.
297 | @return true if valid, false if not.
298 | */
299 | /**************************************************************************/
300 | bool DateTime::isValid() const {
301 | if (yOff >= 100)
302 | return false;
303 | DateTime other(unixtime());
304 | return yOff == other.yOff && m == other.m && d == other.d && hh == other.hh &&
305 | mm == other.mm && ss == other.ss;
306 | }
307 |
308 | /**************************************************************************/
309 | /*!
310 | @brief Writes the DateTime as a string in a user-defined format.
311 | The _buffer_ parameter should be initialized by the caller with a string
312 | specifying the requested format. This format string may contain any of
313 | the following specifiers:
314 | | specifier | output |
315 | |-----------|--------------------------------------------------------|
316 | | YYYY | the year as a 4-digit number (2000--2099) |
317 | | YY | the year as a 2-digit number (00--99) |
318 | | MM | the month as a 2-digit number (01--12) |
319 | | MMM | the abbreviated English month name ("Jan"--"Dec") |
320 | | DD | the day as a 2-digit number (01--31) |
321 | | DDD | the abbreviated English day of the week ("Mon"--"Sun") |
322 | | AP | either "AM" or "PM" |
323 | | ap | either "am" or "pm" |
324 | | hh | the hour as a 2-digit number (00--23 or 01--12) |
325 | | mm | the minute as a 2-digit number (00--59) |
326 | | ss | the second as a 2-digit number (00--59) |
327 | If either "AP" or "ap" is used, the "hh" specifier uses 12-hour mode
328 | (range: 01--12). Otherwise it works in 24-hour mode (range: 00--23).
329 | The specifiers within _buffer_ will be overwritten with the appropriate
330 | values from the DateTime. Any characters not belonging to one of the
331 | above specifiers are left as-is.
332 | __Example__: The format "DDD, DD MMM YYYY hh:mm:ss" generates an output
333 | of the form "Thu, 16 Apr 2020 18:34:56.
334 | @see The `timestamp()` method provides similar functionnality, but it
335 | returns a `String` object and supports a limited choice of
336 | predefined formats.
337 | @param[in,out] buffer Array of `char` for holding the format description
338 | and the formatted DateTime. Before calling this method, the buffer
339 | should be initialized by the user with the format string. The method
340 | will overwrite the buffer with the formatted date and/or time.
341 | @return A pointer to the provided buffer. This is returned for
342 | convenience, in order to enable idioms such as
343 | `Serial.println(now.toString(buffer));`
344 | */
345 | /**************************************************************************/
346 |
347 | char *DateTime::toString(char *buffer) {
348 | uint8_t apTag =
349 | (strstr(buffer, "ap") != nullptr) || (strstr(buffer, "AP") != nullptr);
350 | uint8_t hourReformatted, isPM;
351 | if (apTag) { // 12 Hour Mode
352 | if (hh == 0) { // midnight
353 | isPM = false;
354 | hourReformatted = 12;
355 | } else if (hh == 12) { // noon
356 | isPM = true;
357 | hourReformatted = 12;
358 | } else if (hh < 12) { // morning
359 | isPM = false;
360 | hourReformatted = hh;
361 | } else { // 1 o'clock or after
362 | isPM = true;
363 | hourReformatted = hh - 12;
364 | }
365 | }
366 |
367 | for (size_t i = 0; i < strlen(buffer) - 1; i++) {
368 | if (buffer[i] == 'h' && buffer[i + 1] == 'h') {
369 | if (!apTag) { // 24 Hour Mode
370 | buffer[i] = '0' + hh / 10;
371 | buffer[i + 1] = '0' + hh % 10;
372 | } else { // 12 Hour Mode
373 | buffer[i] = '0' + hourReformatted / 10;
374 | buffer[i + 1] = '0' + hourReformatted % 10;
375 | }
376 | }
377 | if (buffer[i] == 'm' && buffer[i + 1] == 'm') {
378 | buffer[i] = '0' + mm / 10;
379 | buffer[i + 1] = '0' + mm % 10;
380 | }
381 | if (buffer[i] == 's' && buffer[i + 1] == 's') {
382 | buffer[i] = '0' + ss / 10;
383 | buffer[i + 1] = '0' + ss % 10;
384 | }
385 | if (buffer[i] == 'D' && buffer[i + 1] == 'D' && buffer[i + 2] == 'D') {
386 | static PROGMEM const char day_names[] = "SunMonTueWedThuFriSat";
387 | const char *p = &day_names[3 * dayOfTheWeek()];
388 | buffer[i] = pgm_read_byte(p);
389 | buffer[i + 1] = pgm_read_byte(p + 1);
390 | buffer[i + 2] = pgm_read_byte(p + 2);
391 | } else if (buffer[i] == 'D' && buffer[i + 1] == 'D') {
392 | buffer[i] = '0' + d / 10;
393 | buffer[i + 1] = '0' + d % 10;
394 | }
395 | if (buffer[i] == 'M' && buffer[i + 1] == 'M' && buffer[i + 2] == 'M') {
396 | static PROGMEM const char month_names[] =
397 | "JanFebMarAprMayJunJulAugSepOctNovDec";
398 | const char *p = &month_names[3 * (m - 1)];
399 | buffer[i] = pgm_read_byte(p);
400 | buffer[i + 1] = pgm_read_byte(p + 1);
401 | buffer[i + 2] = pgm_read_byte(p + 2);
402 | } else if (buffer[i] == 'M' && buffer[i + 1] == 'M') {
403 | buffer[i] = '0' + m / 10;
404 | buffer[i + 1] = '0' + m % 10;
405 | }
406 | if (buffer[i] == 'Y' && buffer[i + 1] == 'Y' && buffer[i + 2] == 'Y' &&
407 | buffer[i + 3] == 'Y') {
408 | buffer[i] = '2';
409 | buffer[i + 1] = '0';
410 | buffer[i + 2] = '0' + (yOff / 10) % 10;
411 | buffer[i + 3] = '0' + yOff % 10;
412 | } else if (buffer[i] == 'Y' && buffer[i + 1] == 'Y') {
413 | buffer[i] = '0' + (yOff / 10) % 10;
414 | buffer[i + 1] = '0' + yOff % 10;
415 | }
416 | if (buffer[i] == 'A' && buffer[i + 1] == 'P') {
417 | if (isPM) {
418 | buffer[i] = 'P';
419 | buffer[i + 1] = 'M';
420 | } else {
421 | buffer[i] = 'A';
422 | buffer[i + 1] = 'M';
423 | }
424 | } else if (buffer[i] == 'a' && buffer[i + 1] == 'p') {
425 | if (isPM) {
426 | buffer[i] = 'p';
427 | buffer[i + 1] = 'm';
428 | } else {
429 | buffer[i] = 'a';
430 | buffer[i + 1] = 'm';
431 | }
432 | }
433 | }
434 | return buffer;
435 | }
436 |
437 | /**************************************************************************/
438 | /*!
439 | @brief Return the hour in 12-hour format.
440 | @return Hour (1--12).
441 | */
442 | /**************************************************************************/
443 | uint8_t DateTime::twelveHour() const {
444 | if (hh == 0 || hh == 12) { // midnight or noon
445 | return 12;
446 | } else if (hh > 12) { // 1 o'clock or later
447 | return hh - 12;
448 | } else { // morning
449 | return hh;
450 | }
451 | }
452 |
453 | /**************************************************************************/
454 | /*!
455 | @brief Return the day of the week.
456 | @return Day of week as an integer from 0 (Sunday) to 6 (Saturday).
457 | */
458 | /**************************************************************************/
459 | uint8_t DateTime::dayOfTheWeek() const {
460 | uint16_t day = date2days(yOff, m, d);
461 | return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
462 | }
463 |
464 | /**************************************************************************/
465 | /*!
466 | @brief Return Unix time: seconds since 1 Jan 1970.
467 | @see The `DateTime::DateTime(uint32_t)` constructor is the converse of
468 | this method.
469 | @return Number of seconds since 1970-01-01 00:00:00.
470 | */
471 | /**************************************************************************/
472 | uint32_t DateTime::unixtime(void) const {
473 | uint32_t t;
474 | uint16_t days = date2days(yOff, m, d);
475 | t = time2ulong(days, hh, mm, ss);
476 | t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000
477 |
478 | return t;
479 | }
480 |
481 | /**************************************************************************/
482 | /*!
483 | @brief Convert the DateTime to seconds since 1 Jan 2000
484 | The result can be converted back to a DateTime with:
485 | ```cpp
486 | DateTime(SECONDS_FROM_1970_TO_2000 + value)
487 | ```
488 | @return Number of seconds since 2000-01-01 00:00:00.
489 | */
490 | /**************************************************************************/
491 | uint32_t DateTime::secondstime(void) const {
492 | uint32_t t;
493 | uint16_t days = date2days(yOff, m, d);
494 | t = time2ulong(days, hh, mm, ss);
495 | return t;
496 | }
497 |
498 | /**************************************************************************/
499 | /*!
500 | @brief Add a TimeSpan to the DateTime object
501 | @param span TimeSpan object
502 | @return New DateTime object with span added to it.
503 | */
504 | /**************************************************************************/
505 | DateTime DateTime::operator+(const TimeSpan &span) {
506 | return DateTime(unixtime() + span.totalseconds());
507 | }
508 |
509 | /**************************************************************************/
510 | /*!
511 | @brief Subtract a TimeSpan from the DateTime object
512 | @param span TimeSpan object
513 | @return New DateTime object with span subtracted from it.
514 | */
515 | /**************************************************************************/
516 | DateTime DateTime::operator-(const TimeSpan &span) {
517 | return DateTime(unixtime() - span.totalseconds());
518 | }
519 |
520 | /**************************************************************************/
521 | /*!
522 | @brief Subtract one DateTime from another
523 | @note Since a TimeSpan cannot be negative, the subtracted DateTime
524 | should be less (earlier) than or equal to the one it is
525 | subtracted from.
526 | @param right The DateTime object to subtract from self (the left object)
527 | @return TimeSpan of the difference between DateTimes.
528 | */
529 | /**************************************************************************/
530 | TimeSpan DateTime::operator-(const DateTime &right) {
531 | return TimeSpan(unixtime() - right.unixtime());
532 | }
533 |
534 | /**************************************************************************/
535 | /*!
536 | @brief Test if one DateTime is less (earlier) than another.
537 | @param right Comparison DateTime object
538 | @return True if the left DateTime is earlier than the right one,
539 | false otherwise.
540 | */
541 | /**************************************************************************/
542 | bool DateTime::operator<(const DateTime &right) const {
543 | return unixtime() < right.unixtime();
544 | }
545 |
546 | /**************************************************************************/
547 | /*!
548 | @brief Test if two DateTime objects are equal.
549 | @param right Comparison DateTime object
550 | @return True if both DateTime objects are the same, false otherwise.
551 | */
552 | /**************************************************************************/
553 | bool DateTime::operator==(const DateTime &right) const {
554 | return unixtime() == right.unixtime();
555 | }
556 |
557 | /**************************************************************************/
558 | /*!
559 | @brief Return a ISO 8601 timestamp as a `String` object.
560 | The generated timestamp conforms to one of the predefined, ISO
561 | 8601-compatible formats for representing the date (if _opt_ is
562 | `TIMESTAMP_DATE`), the time (`TIMESTAMP_TIME`), or both
563 | (`TIMESTAMP_FULL`).
564 | @see The `toString()` method provides more general string formatting.
565 | @param opt Format of the timestamp
566 | @return Timestamp string, e.g. "2020-04-16T18:34:56".
567 | */
568 | /**************************************************************************/
569 | String DateTime::timestamp(timestampOpt opt) {
570 | char buffer[20];
571 |
572 | // Generate timestamp according to opt
573 | switch (opt) {
574 | case TIMESTAMP_TIME:
575 | // Only time
576 | sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss);
577 | break;
578 | case TIMESTAMP_DATE:
579 | // Only date
580 | sprintf(buffer, "%d-%02d-%02d", 2000 + yOff, m, d);
581 | break;
582 | default:
583 | // Full
584 | sprintf(buffer, "%d-%02d-%02dT%02d:%02d:%02d", 2000 + yOff, m, d, hh, mm,
585 | ss);
586 | }
587 | return String(buffer);
588 | }
589 |
590 | /**************************************************************************/
591 | /*!
592 | @brief Create a new TimeSpan object in seconds
593 | @param seconds Number of seconds
594 | */
595 | /**************************************************************************/
596 | TimeSpan::TimeSpan(int32_t seconds) : _seconds(seconds) {}
597 |
598 | /**************************************************************************/
599 | /*!
600 | @brief Create a new TimeSpan object using a number of
601 | days/hours/minutes/seconds e.g. Make a TimeSpan of 3 hours and 45 minutes:
602 | new TimeSpan(0, 3, 45, 0);
603 | @param days Number of days
604 | @param hours Number of hours
605 | @param minutes Number of minutes
606 | @param seconds Number of seconds
607 | */
608 | /**************************************************************************/
609 | TimeSpan::TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds)
610 | : _seconds((int32_t)days * 86400L + (int32_t)hours * 3600 +
611 | (int32_t)minutes * 60 + seconds) {}
612 |
613 | /**************************************************************************/
614 | /*!
615 | @brief Copy constructor, make a new TimeSpan using an existing one
616 | @param copy The TimeSpan to copy
617 | */
618 | /**************************************************************************/
619 | TimeSpan::TimeSpan(const TimeSpan ©) : _seconds(copy._seconds) {}
620 |
621 | /**************************************************************************/
622 | /*!
623 | @brief Add two TimeSpans
624 | @param right TimeSpan to add
625 | @return New TimeSpan object, sum of left and right
626 | */
627 | /**************************************************************************/
628 | TimeSpan TimeSpan::operator+(const TimeSpan &right) {
629 | return TimeSpan(_seconds + right._seconds);
630 | }
631 |
632 | /**************************************************************************/
633 | /*!
634 | @brief Subtract a TimeSpan
635 | @param right TimeSpan to subtract
636 | @return New TimeSpan object, right subtracted from left
637 | */
638 | /**************************************************************************/
639 | TimeSpan TimeSpan::operator-(const TimeSpan &right) {
640 | return TimeSpan(_seconds - right._seconds);
641 | }
--------------------------------------------------------------------------------
/src/DateTime.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************/
2 | /*!
3 | @file RTClib.h
4 | Original library by JeeLabs http://news.jeelabs.org/code/, released to the
5 | public domain
6 | License: MIT (see LICENSE)
7 | This is a fork of JeeLab's fantastic real time clock library for Arduino.
8 | For details on using this library with an RTC module like the DS1307, PCF8523,
9 | or DS3231, see the guide at:
10 | https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
11 | Adafruit invests time and resources providing this open source code,
12 | please support Adafruit and open-source hardware by purchasing
13 | products from Adafruit!
14 | */
15 | /**************************************************************************/
16 |
17 |
18 | #ifndef __DATETIME_H__
19 | #define __DATETIME_H__
20 | #include "Arduino.h"
21 | #include "time.h"
22 |
23 | #define SECONDS_PER_DAY 86400L ///< 60 * 60 * 24
24 | #define SECONDS_FROM_1970_TO_2000 \
25 | 946684800 ///< Unixtime for 2000-01-01 08:00:00, useful for initialization
26 |
27 |
28 | /**************************************************************************/
29 | /*!
30 | @brief Timespan which can represent changes in time with seconds accuracy.
31 | */
32 | /**************************************************************************/
33 | class TimeSpan {
34 | public:
35 | TimeSpan(int32_t seconds = 0);
36 | TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds);
37 | TimeSpan(const TimeSpan ©);
38 |
39 | /*!
40 | @brief Number of days in the TimeSpan
41 | e.g. 4
42 | @return int16_t days
43 | */
44 | int16_t days() const { return _seconds / 86400L; }
45 | /*!
46 | @brief Number of hours in the TimeSpan
47 | This is not the total hours, it includes the days
48 | e.g. 4 days, 3 hours - NOT 99 hours
49 | @return int8_t hours
50 | */
51 | int8_t hours() const { return _seconds / 3600 % 24; }
52 | /*!
53 | @brief Number of minutes in the TimeSpan
54 | This is not the total minutes, it includes days/hours
55 | e.g. 4 days, 3 hours, 27 minutes
56 | @return int8_t minutes
57 | */
58 | int8_t minutes() const { return _seconds / 60 % 60; }
59 | /*!
60 | @brief Number of seconds in the TimeSpan
61 | This is not the total seconds, it includes the days/hours/minutes
62 | e.g. 4 days, 3 hours, 27 minutes, 7 seconds
63 | @return int8_t seconds
64 | */
65 | int8_t seconds() const { return _seconds % 60; }
66 | /*!
67 | @brief Total number of seconds in the TimeSpan, e.g. 358027
68 | @return int32_t seconds
69 | */
70 | int32_t totalseconds() const { return _seconds; }
71 |
72 | TimeSpan operator+(const TimeSpan &right);
73 | TimeSpan operator-(const TimeSpan &right);
74 |
75 | protected:
76 | int32_t _seconds; ///< Actual TimeSpan value is stored as seconds
77 | };
78 |
79 | class DateTime {
80 | public:
81 |
82 | DateTime(uint32_t t = SECONDS_FROM_1970_TO_2000);
83 | DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour = 0,
84 | uint8_t min = 0, uint8_t sec = 0);
85 | DateTime(const DateTime ©);
86 | DateTime(const char *date, const char *time);
87 | DateTime(const __FlashStringHelper *date, const __FlashStringHelper *time);
88 | DateTime(const char *iso8601date);
89 | bool isValid() const;
90 | char *toString(char *buffer);
91 |
92 |
93 | /*!
94 | @brief Return the year.
95 | @return Year (range: 2000--2099).
96 | */
97 | uint16_t year() const { return 2000 + yOff; }
98 | /*!
99 | @brief Return the month.
100 | @return Month number (1--12).
101 | */
102 | uint8_t month() const { return m; }
103 | /*!
104 | @brief Return the day of the month.
105 | @return Day of the month (1--31).
106 | */
107 | uint8_t day() const { return d; }
108 | /*!
109 | @brief Return the hour
110 | @return Hour (0--23).
111 | */
112 | uint8_t hour() const { return hh; }
113 |
114 | uint8_t twelveHour() const;
115 | /*!
116 | @brief Return whether the time is PM.
117 | @return 0 if the time is AM, 1 if it's PM.
118 | */
119 | uint8_t isPM() const { return hh >= 12; }
120 | /*!
121 | @brief Return the minute.
122 | @return Minute (0--59).
123 | */
124 | uint8_t minute() const { return mm; }
125 | /*!
126 | @brief Return the second.
127 | @return Second (0--59).
128 | */
129 | uint8_t second() const { return ss; }
130 |
131 | uint8_t dayOfTheWeek() const;
132 |
133 | /* 32-bit times as seconds since 2000-01-01. */
134 | uint32_t secondstime() const;
135 |
136 | /* 32-bit times as seconds since 1970-01-01. */
137 | uint32_t unixtime(void) const;
138 |
139 | /*!
140 | Format of the ISO 8601 timestamp generated by `timestamp()`. Each
141 | option corresponds to a `toString()` format as follows:
142 | */
143 | enum timestampOpt {
144 | TIMESTAMP_FULL, //!< `YYYY-MM-DDThh:mm:ss`
145 | TIMESTAMP_TIME, //!< `hh:mm:ss`
146 | TIMESTAMP_DATE //!< `YYYY-MM-DD`
147 | };
148 | String timestamp(timestampOpt opt = TIMESTAMP_FULL);
149 |
150 | DateTime operator+(const TimeSpan &span);
151 | DateTime operator-(const TimeSpan &span);
152 | TimeSpan operator-(const DateTime &right);
153 | bool operator<(const DateTime &right) const;
154 | /*!
155 | @brief Test if one DateTime is greater (later) than another.
156 | @param right DateTime object to compare
157 | @return True if the left DateTime is later than the right one,
158 | false otherwise
159 | */
160 | bool operator>(const DateTime &right) const { return right < *this; }
161 | /*!
162 | @brief Test if one DateTime is less (earlier) than or equal to another
163 | @param right DateTime object to compare
164 | @return True if the left DateTime is earlier than or equal to the
165 | right one, false otherwise
166 | */
167 | bool operator<=(const DateTime &right) const { return !(*this > right); }
168 | /*!
169 | @brief Test if one DateTime is greater (later) than or equal to another
170 | @param right DateTime object to compare
171 | @return True if the left DateTime is later than or equal to the right
172 | one, false otherwise
173 | */
174 | bool operator>=(const DateTime &right) const { return !(*this < right); }
175 | bool operator==(const DateTime &right) const;
176 | /*!
177 | @brief Test if two DateTime objects are not equal.
178 | @param right DateTime object to compare
179 | @return True if the two objects are not equal, false if they are
180 | */
181 | bool operator!=(const DateTime &right) const { return !(*this == right); }
182 |
183 | protected:
184 | uint8_t yOff; ///< Year offset from 2000
185 | uint8_t m; ///< Month 1-12
186 | uint8_t d; ///< Day 1-31
187 | uint8_t hh; ///< Hours 0-23
188 | uint8_t mm; ///< Minutes 0-59
189 | uint8_t ss; ///< Seconds 0-59
190 | };
191 |
192 | #endif // __DATETIME_H__
--------------------------------------------------------------------------------
/src/RTC_SAMD21.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | RTC library for Arduino Zero.
3 | Copyright (c) 2015 Arduino LLC. All right reserved.
4 | This library is free software; you can redistribute it and/or
5 | modify it under the terms of the GNU Lesser General Public
6 | License as published by the Free Software Foundation; either
7 | version 2.1 of the License, or (at your option) any later version.
8 | This library is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 | Lesser General Public License for more details.
12 | You should have received a copy of the GNU Lesser General Public
13 | License along with this library; if not, write to the Free Software
14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
15 | */
16 |
17 | #ifdef __SAMD21__
18 | #include "RTC_SAMD21.h"
19 |
20 | rtcCallBack RTC_callBack = NULL;
21 |
22 | bool RTC_SAMD21::begin()
23 | {
24 | uint16_t tmp_reg = 0;
25 |
26 | PM->APBAMASK.reg |= PM_APBAMASK_RTC; // turn on digital interface clock
27 | config32kOSC();
28 |
29 | // If the RTC is in clock mode and the reset was
30 | // not due to POR or BOD, preserve the clock time
31 | // POR causes a reset anyway, BOD behaviour is?
32 | bool validTime = false;
33 | RTC_MODE2_CLOCK_Type oldTime;
34 |
35 | if ((PM->RCAUSE.reg & (PM_RCAUSE_SYST | PM_RCAUSE_WDT | PM_RCAUSE_EXT)))
36 | {
37 | if (RTC->MODE2.CTRL.reg & RTC_MODE2_CTRL_MODE_CLOCK)
38 | {
39 | validTime = true;
40 | oldTime.reg = RTC->MODE2.CLOCK.reg;
41 | }
42 | }
43 |
44 | // Setup clock GCLK2 with OSC32K divided by 32
45 | configureClock();
46 |
47 | RTCdisable();
48 |
49 | RTCreset();
50 |
51 | tmp_reg |= RTC_MODE2_CTRL_MODE_CLOCK; // set clock operating mode
52 | tmp_reg |= RTC_MODE2_CTRL_PRESCALER_DIV1024; // set prescaler to 1024 for MODE2
53 | tmp_reg &= ~RTC_MODE2_CTRL_MATCHCLR; // disable clear on match
54 |
55 | //According to the datasheet RTC_MODE2_CTRL_CLKREP = 0 for 24h
56 | tmp_reg &= ~RTC_MODE2_CTRL_CLKREP; // 24h time representation
57 |
58 | RTC->MODE2.READREQ.reg &= ~RTC_READREQ_RCONT; // disable continuously mode
59 |
60 | RTC->MODE2.CTRL.reg = tmp_reg;
61 | while (RTCisSyncing())
62 | ;
63 |
64 | NVIC_EnableIRQ(RTC_IRQn); // enable RTC interrupt
65 | NVIC_SetPriority(RTC_IRQn, 0x00);
66 |
67 | RTC->MODE2.INTENSET.reg |= RTC_MODE2_INTENSET_ALARM0; // enable alarm interrupt
68 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = MATCH_OFF; // default alarm match is off (disabled)
69 |
70 | while (RTCisSyncing())
71 | ;
72 |
73 | RTCenable();
74 | RTCresetRemove();
75 |
76 | // If desired and valid, restore the time value, else use first valid time value
77 | if ((validTime) && (oldTime.reg != 0L))
78 | {
79 | RTC->MODE2.CLOCK.reg = oldTime.reg;
80 | }
81 | else
82 | {
83 | RTC->MODE2.CLOCK.reg = RTC_MODE2_CLOCK_YEAR(DEFAULT_YEAR - 2000) | RTC_MODE2_CLOCK_MONTH(DEFAULT_MONTH) | RTC_MODE2_CLOCK_DAY(DEFAULT_DAY) | RTC_MODE2_CLOCK_HOUR(DEFAULT_HOUR) | RTC_MODE2_CLOCK_MINUTE(DEFAULT_MINUTE) | RTC_MODE2_CLOCK_SECOND(DEFAULT_SECOND);
84 | }
85 |
86 | while (RTCisSyncing())
87 | ;
88 |
89 | return true;
90 | }
91 |
92 | void RTC_SAMD21::adjust(const DateTime &dt)
93 | {
94 | RTC_MODE2_CLOCK_Type newTime;
95 |
96 | newTime.bit.SECOND = dt.second();
97 | newTime.bit.MINUTE = dt.minute();
98 | newTime.bit.HOUR = dt.hour();
99 | newTime.bit.DAY = dt.day();
100 | newTime.bit.MONTH = dt.month();
101 | newTime.bit.YEAR = dt.year() - 2000;
102 |
103 | RTC->MODE2.CLOCK.reg = newTime.reg;
104 | while (RTCisSyncing())
105 | ;
106 | }
107 |
108 | DateTime RTC_SAMD21::now()
109 | {
110 | RTCreadRequest();
111 | uint8_t ss = RTC->MODE2.CLOCK.bit.SECOND;
112 | uint8_t mm = RTC->MODE2.CLOCK.bit.MINUTE;
113 | uint8_t hh = RTC->MODE2.CLOCK.bit.HOUR;
114 | uint8_t d = RTC->MODE2.CLOCK.bit.DAY;
115 | uint8_t m = RTC->MODE2.CLOCK.bit.MONTH;
116 | uint16_t y = RTC->MODE2.CLOCK.bit.YEAR;
117 |
118 | return DateTime(y, m, d, hh, mm, ss);
119 | }
120 |
121 | DateTime RTC_SAMD21::alarm()
122 | {
123 |
124 | uint8_t ss = RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND;
125 | uint8_t mm = RTC->MODE2.Mode2Alarm[0].ALARM.bit.MINUTE;
126 | uint8_t hh = RTC->MODE2.Mode2Alarm[0].ALARM.bit.HOUR;
127 | uint8_t d = RTC->MODE2.Mode2Alarm[0].ALARM.bit.DAY;
128 | uint8_t m = RTC->MODE2.Mode2Alarm[0].ALARM.bit.MONTH;
129 | uint16_t y = RTC->MODE2.Mode2Alarm[0].ALARM.bit.YEAR;
130 |
131 | return DateTime(y, m, d, hh, mm, ss);
132 | }
133 |
134 | void RTC_SAMD21::setAlarm(const DateTime &dt)
135 | {
136 | RTC_MODE2_CLOCK_Type alarmTime;
137 |
138 | alarmTime.bit.SECOND = dt.second();
139 | alarmTime.bit.MINUTE = dt.minute();
140 | alarmTime.bit.HOUR = dt.hour();
141 | alarmTime.bit.DAY = dt.day();
142 | alarmTime.bit.MONTH = dt.month();
143 | alarmTime.bit.YEAR = dt.year() - 2000;
144 |
145 | RTC->MODE2.Mode2Alarm[0].ALARM.reg = alarmTime.reg;
146 | }
147 |
148 | void RTC_SAMD21::enableAlarm(Alarm_Match match)
149 | {
150 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = match;
151 | while (RTCisSyncing())
152 | ;
153 | }
154 |
155 | void RTC_SAMD21::disableAlarm()
156 | {
157 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = 0x00;
158 | while (RTCisSyncing())
159 | ;
160 | }
161 |
162 | void RTC_SAMD21::attachInterrupt(rtcCallBack callback)
163 | {
164 | RTC_callBack = callback;
165 | }
166 |
167 | void RTC_SAMD21::detachInterrupt()
168 | {
169 | RTC_callBack = NULL;
170 | }
171 |
172 | void RTC_SAMD21::standbyMode()
173 | {
174 | // Entering standby mode when connected
175 | // via the native USB port causes issues.
176 | SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
177 | __DSB();
178 | __WFI();
179 | }
180 |
181 | /* Attach peripheral clock to 32k oscillator */
182 | void RTC_SAMD21::configureClock()
183 | {
184 | GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4);
185 | while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)
186 | ;
187 | #ifdef CRYSTALLESS
188 | GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL);
189 | #else
190 | GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL);
191 | #endif
192 | while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)
193 | ;
194 | GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2 | (RTC_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
195 | while (GCLK->STATUS.bit.SYNCBUSY)
196 | ;
197 | }
198 |
199 | /*
200 | * Private Utility Functions
201 | */
202 |
203 | /* Configure the 32768Hz Oscillator */
204 | void RTC_SAMD21::config32kOSC()
205 | {
206 | #ifndef CRYSTALLESS
207 | SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND |
208 | SYSCTRL_XOSC32K_RUNSTDBY |
209 | SYSCTRL_XOSC32K_EN32K |
210 | SYSCTRL_XOSC32K_XTALEN |
211 | SYSCTRL_XOSC32K_STARTUP(6) |
212 | SYSCTRL_XOSC32K_ENABLE;
213 | #endif
214 | }
215 |
216 | /* Synchronise the CLOCK register for reading*/
217 | inline void RTC_SAMD21::RTCreadRequest()
218 | {
219 |
220 | RTC->MODE2.READREQ.reg = RTC_READREQ_RREQ;
221 | while (RTCisSyncing())
222 | ;
223 | }
224 |
225 | /* Wait for sync in write operations */
226 | inline bool RTC_SAMD21::RTCisSyncing()
227 | {
228 | return (RTC->MODE2.STATUS.bit.SYNCBUSY);
229 | }
230 |
231 | void RTC_SAMD21::RTCdisable()
232 | {
233 | RTC->MODE2.CTRL.reg &= ~RTC_MODE2_CTRL_ENABLE; // disable RTC
234 | while (RTCisSyncing())
235 | ;
236 | }
237 |
238 | void RTC_SAMD21::RTCenable()
239 | {
240 | RTC->MODE2.CTRL.reg |= RTC_MODE2_CTRL_ENABLE; // enable RTC
241 | while (RTCisSyncing())
242 | ;
243 | }
244 |
245 | void RTC_SAMD21::RTCreset()
246 | {
247 | RTC->MODE2.CTRL.reg |= RTC_MODE2_CTRL_SWRST; // software reset
248 | while (RTCisSyncing())
249 | ;
250 | }
251 |
252 | void RTC_SAMD21::RTCresetRemove()
253 | {
254 | RTC->MODE2.CTRL.reg &= ~RTC_MODE2_CTRL_SWRST; // software reset remove
255 | while (RTCisSyncing())
256 | ;
257 | }
258 |
259 | extern "C"
260 | {
261 | void RTC_Handler(void)
262 | {
263 | if (RTC_callBack != NULL)
264 | {
265 | RTC_callBack();
266 | }
267 |
268 | RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; // must clear flag at end
269 | }
270 | }
271 | #endif
--------------------------------------------------------------------------------
/src/RTC_SAMD21.h:
--------------------------------------------------------------------------------
1 | /*
2 | RTC library for Arduino Zero.
3 | Copyright (c) 2015 Arduino LLC. All right reserved.
4 | This library is free software; you can redistribute it and/or
5 | modify it under the terms of the GNU Lesser General Public
6 | License as published by the Free Software Foundation; either
7 | version 2.1 of the License, or (at your option) any later version.
8 | This library is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 | Lesser General Public License for more details.
12 | You should have received a copy of the GNU Lesser General Public
13 | License along with this library; if not, write to the Free Software
14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
15 | */
16 |
17 | #ifdef __SAMD21__
18 | #ifndef __RTC_SAMD21_H__
19 | #define __RTC_SAMD21_H__
20 | #include "DateTime.h"
21 |
22 | typedef voidFuncPtr rtcCallBack;
23 |
24 | // Default date & time after reset
25 | #define DEFAULT_YEAR 2000 // 2000..2063
26 | #define DEFAULT_MONTH 1 // 1..12
27 | #define DEFAULT_DAY 1 // 1..31
28 | #define DEFAULT_HOUR 0 // 1..23
29 | #define DEFAULT_MINUTE 0 // 0..59
30 | #define DEFAULT_SECOND 0 // 0..59
31 |
32 | class RTC_SAMD21
33 | {
34 | public:
35 | enum Alarm_Match : uint8_t // Should we have this enum or just use the identifiers from /component/rtc.h ?
36 | {
37 | MATCH_OFF = RTC_MODE2_MASK_SEL_OFF_Val, // Never
38 | MATCH_SS = RTC_MODE2_MASK_SEL_SS_Val, // Every Minute
39 | MATCH_MMSS = RTC_MODE2_MASK_SEL_MMSS_Val, // Every Hour
40 | MATCH_HHMMSS = RTC_MODE2_MASK_SEL_HHMMSS_Val, // Every Day
41 | MATCH_DHHMMSS = RTC_MODE2_MASK_SEL_DDHHMMSS_Val, // Every Month
42 | MATCH_MMDDHHMMSS = RTC_MODE2_MASK_SEL_MMDDHHMMSS_Val, // Every Year
43 | MATCH_YYMMDDHHMMSS = RTC_MODE2_MASK_SEL_YYMMDDHHMMSS_Val // Once, on a specific date and a specific time
44 | };
45 |
46 | boolean begin();
47 | void adjust(const DateTime &dt);
48 | DateTime now();
49 | void setAlarm(const DateTime &dt);
50 | DateTime alarm();
51 | void enableAlarm(Alarm_Match match);
52 | void disableAlarm();
53 | void attachInterrupt(rtcCallBack callback);
54 | void detachInterrupt();
55 | void standbyMode();
56 |
57 | private:
58 | void config32kOSC(void);
59 | void configureClock(void);
60 | void RTCreadRequest();
61 | bool RTCisSyncing(void);
62 | void RTCdisable();
63 | void RTCenable();
64 | void RTCreset();
65 | void RTCresetRemove();
66 | };
67 | #endif
68 | #endif
--------------------------------------------------------------------------------
/src/RTC_SAMD51.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 | Author: Hongtai Liu (lht856@foxmail.com)
4 | Copyright (C) 2020 Seeed Technology Co.,Ltd.
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 | */
21 |
22 | #ifdef __SAMD51__
23 | #include "RTC_SAMD51.h"
24 |
25 | rtcCallBack RTC_callBack = NULL;
26 |
27 | bool RTC_SAMD51::begin()
28 | {
29 | config32kOSC();
30 |
31 | uint16_t tmp_reg_a = 0;
32 |
33 | // If the RTC is in clock mode and the reset was
34 | // not due to POR or BOD, preserve the clock time
35 | // POR causes a reset anyway, BOD behaviour is?
36 | bool validTime = false;
37 | RTC_MODE2_CLOCK_Type oldTime;
38 |
39 | if (RTC->MODE2.CTRLA.reg & RTC_MODE2_CTRLA_MODE_CLOCK)
40 | {
41 | validTime = true;
42 | oldTime.reg = RTC->MODE2.CLOCK.reg;
43 | }
44 |
45 | configureClock();
46 |
47 | RTCdisable();
48 |
49 | RTCreset();
50 |
51 | tmp_reg_a |= RTC_MODE2_CTRLA_MODE_CLOCK; // set clock operating mode
52 | tmp_reg_a |= RTC_MODE2_CTRLA_PRESCALER_DIV1024; // set prescaler to 1024 for MODE2 so that f = GCLK_RTC / 1024 = 1.024K / 1024 = 1Hz
53 | tmp_reg_a &= ~RTC_MODE2_CTRLA_MATCHCLR; // disable clear on match
54 |
55 | //According to the datasheet RTC_MODE2_CTRL_CLKREP = 0 for 24h
56 | tmp_reg_a &= ~RTC_MODE2_CTRLA_CLKREP; // 24h time representation
57 |
58 | RTC->MODE2.CTRLA.reg = tmp_reg_a;
59 | while (RTCisSyncing())
60 | ;
61 |
62 | NVIC_EnableIRQ(RTC_IRQn); // enable RTC interrupt
63 | NVIC_SetPriority(RTC_IRQn, 0x00);
64 |
65 | RTC->MODE2.INTENSET.reg |= RTC_MODE2_INTENSET_ALARM0; // enable alarm0 interrupt
66 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = MATCH_OFF; // default alarm0 match is off (disabled)
67 |
68 | RTC->MODE2.INTENSET.reg |= RTC_MODE2_INTENSET_ALARM1; // enable alarm1 interrupt
69 | RTC->MODE2.Mode2Alarm[1].MASK.bit.SEL = MATCH_OFF; // default alarm1 match is off (disabled)
70 |
71 | while (RTCisSyncing())
72 | ;
73 |
74 | RTCenable();
75 | RTCresetRemove();
76 |
77 | // If desired and valid, restore the time value, else use first valid time value
78 | if ((validTime) && (oldTime.reg != 0L))
79 | {
80 | RTC->MODE2.CLOCK.reg = oldTime.reg;
81 | }
82 | else
83 | {
84 | RTC->MODE2.CLOCK.reg = RTC_MODE2_CLOCK_YEAR(DEFAULT_YEAR - 2000) | RTC_MODE2_CLOCK_MONTH(DEFAULT_MONTH) | RTC_MODE2_CLOCK_DAY(DEFAULT_DAY) | RTC_MODE2_CLOCK_HOUR(DEFAULT_HOUR) | RTC_MODE2_CLOCK_MINUTE(DEFAULT_MINUTE) | RTC_MODE2_CLOCK_SECOND(DEFAULT_SECOND);
85 | }
86 |
87 | while (RTCisSyncing())
88 | ;
89 |
90 | return true;
91 | }
92 |
93 | void RTC_SAMD51::adjust(const DateTime &dt)
94 | {
95 | RTC_MODE2_CLOCK_Type newTime;
96 |
97 | newTime.bit.SECOND = dt.second();
98 | newTime.bit.MINUTE = dt.minute();
99 | newTime.bit.HOUR = dt.hour();
100 | newTime.bit.DAY = dt.day();
101 | newTime.bit.MONTH = dt.month();
102 | newTime.bit.YEAR = dt.year() - 2000;
103 |
104 | RTC->MODE2.CLOCK.reg = newTime.reg;
105 | while (RTCisSyncing())
106 | ;
107 | }
108 |
109 | DateTime RTC_SAMD51::now()
110 | {
111 | RTCreadRequest();
112 | uint8_t ss = RTC->MODE2.CLOCK.bit.SECOND;
113 | uint8_t mm = RTC->MODE2.CLOCK.bit.MINUTE;
114 | uint8_t hh = RTC->MODE2.CLOCK.bit.HOUR;
115 | uint8_t d = RTC->MODE2.CLOCK.bit.DAY;
116 | uint8_t m = RTC->MODE2.CLOCK.bit.MONTH;
117 | uint16_t y = RTC->MODE2.CLOCK.bit.YEAR;
118 |
119 | return DateTime(y, m, d, hh, mm, ss);
120 | }
121 |
122 | DateTime RTC_SAMD51::alarm(uint8_t id)
123 | {
124 | if (id >= 2)
125 | return DateTime();
126 | uint8_t ss = RTC->MODE2.Mode2Alarm[id].ALARM.bit.SECOND;
127 | uint8_t mm = RTC->MODE2.Mode2Alarm[id].ALARM.bit.MINUTE;
128 | uint8_t hh = RTC->MODE2.Mode2Alarm[id].ALARM.bit.HOUR;
129 | uint8_t d = RTC->MODE2.Mode2Alarm[id].ALARM.bit.DAY;
130 | uint8_t m = RTC->MODE2.Mode2Alarm[id].ALARM.bit.MONTH;
131 | uint16_t y = RTC->MODE2.Mode2Alarm[id].ALARM.bit.YEAR;
132 |
133 | return DateTime(y, m, d, hh, mm, ss);
134 | }
135 |
136 | void RTC_SAMD51::setAlarm(uint8_t id, const DateTime &dt)
137 | {
138 | if (id >= 2)
139 | return;
140 | RTC_MODE2_CLOCK_Type alarmTime;
141 |
142 | alarmTime.bit.SECOND = dt.second();
143 | alarmTime.bit.MINUTE = dt.minute();
144 | alarmTime.bit.HOUR = dt.hour();
145 | alarmTime.bit.DAY = dt.day();
146 | alarmTime.bit.MONTH = dt.month();
147 | alarmTime.bit.YEAR = dt.year() - 2000;
148 |
149 | RTC->MODE2.Mode2Alarm[id].ALARM.reg = alarmTime.reg;
150 | if (id == 0)
151 | {
152 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM0))
153 | ;
154 | }
155 | else
156 | {
157 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM1))
158 | ;
159 | }
160 | }
161 |
162 | void RTC_SAMD51::enableAlarm(uint8_t id, Alarm_Match match)
163 | {
164 | if (id >= 2)
165 | return;
166 | RTC->MODE2.Mode2Alarm[id].MASK.bit.SEL = match;
167 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM_Msk))
168 | ;
169 | }
170 |
171 | void RTC_SAMD51::disableAlarm(uint8_t id)
172 | {
173 | if (id >= 2)
174 | return;
175 | RTC->MODE2.Mode2Alarm[id].MASK.bit.SEL = 0x00;
176 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM_Msk))
177 | ;
178 | }
179 |
180 | void RTC_SAMD51::attachInterrupt(rtcCallBack callback)
181 | {
182 | RTC_callBack = callback;
183 | }
184 |
185 | void RTC_SAMD51::detachInterrupt()
186 | {
187 | RTC_callBack = NULL;
188 | }
189 |
190 | void RTC_SAMD51::standbyMode()
191 | {
192 | // Entering standby mode when connected
193 | // via the native USB port causes issues.
194 | SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
195 | __DSB();
196 | __WFI();
197 | }
198 |
199 | /* Attach peripheral clock to 32k oscillator and RTC*/
200 | void RTC_SAMD51::configureClock()
201 | {
202 | MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC | MCLK_APBAMASK_OSC32KCTRL;
203 | }
204 |
205 | /*
206 | * Private Utility Functions
207 | */
208 |
209 | /* Configure the 32768Hz Oscillator */
210 | void RTC_SAMD51::config32kOSC()
211 | {
212 | #ifdef CRYSTALLESS
213 | // This platform does not have external crystal.
214 | // Thus, we have to enable OSCULP32K to generate RTC clock.
215 | void *hw = (void *)OSC32KCTRL;
216 | uint16_t calib = 0;
217 |
218 | calib = ((Osc32kctrl *)hw)->OSCULP32K.reg;
219 | calib = (calib & OSC32KCTRL_OSCULP32K_CALIB_Msk) >> OSC32KCTRL_OSCULP32K_CALIB_Pos;
220 | //re-write calibrate
221 | ((Osc32kctrl *)hw)->OSCULP32K.reg &= ~OSC32KCTRL_OSCULP32K_WRTLOCK;
222 |
223 | ((Osc32kctrl *)hw)->OSCULP32K.reg |= calib;
224 | ((Osc32kctrl *)hw)->OSCULP32K.reg &= ~(OSC32KCTRL_OSCULP32K_EN32K);
225 | ((Osc32kctrl *)hw)->OSCULP32K.reg |= OSC32KCTRL_OSCULP32K_EN1K; //enable 1.024KHz OUPUT
226 |
227 | ((Osc32kctrl *)hw)->OSCULP32K.reg |= OSC32KCTRL_OSCULP32K_WRTLOCK;
228 |
229 | //Use 1.024KHz for RTC
230 | ((Osc32kctrl *)hw)->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL(OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K_Val);
231 | #else
232 | // This platform has external crystal and Arduino core has already enabled the XOSC32K oscillator.
233 | // But the Arduino core does not enable 1.024[kHz] output.
234 | // Thus all we have to do is just enable 1.024[kHz] output by setting XOSC32K.EN1k to 1.
235 | OSC32KCTRL->XOSC32K.bit.EN1K = 1;
236 | // Use 1.024[kHz] output for RTC.
237 | OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K_Val;
238 | #endif
239 | }
240 |
241 | /* Synchronise the CLOCK register for reading*/
242 | inline void RTC_SAMD51::RTCreadRequest()
243 | {
244 | RTC->MODE2.CTRLA.reg |= RTC_MODE2_CTRLA_CLOCKSYNC;
245 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_SWRST | RTC_MODE2_SYNCBUSY_ENABLE | RTC_MODE2_SYNCBUSY_CLOCKSYNC))
246 | ;
247 | }
248 |
249 | /* Wait for sync in write operations */
250 | inline bool RTC_SAMD51::RTCisSyncing(uint32_t flag)
251 | {
252 | return (RTC->MODE2.SYNCBUSY.reg & flag);
253 | }
254 |
255 | void RTC_SAMD51::RTCdisable()
256 | {
257 | RTC->MODE2.CTRLA.reg &= ~RTC_MODE2_CTRLA_ENABLE; // disable RTC
258 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_SWRST | RTC_MODE2_SYNCBUSY_ENABLE | RTC_MODE2_SYNCBUSY_CLOCKSYNC))
259 | ;
260 | }
261 |
262 | void RTC_SAMD51::RTCenable()
263 | {
264 | RTC->MODE2.CTRLA.reg |= RTC_MODE2_CTRLA_ENABLE; // enable RTC
265 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_SWRST | RTC_MODE2_SYNCBUSY_ENABLE | RTC_MODE2_SYNCBUSY_CLOCKSYNC))
266 | ;
267 | }
268 |
269 | void RTC_SAMD51::RTCreset()
270 | {
271 | RTC->MODE2.CTRLA.reg |= RTC_MODE2_CTRLA_SWRST; // software reset
272 | while (RTCisSyncing(RTC_MODE2_CTRLA_SWRST))
273 | ;
274 | }
275 |
276 | void RTC_SAMD51::RTCresetRemove()
277 | {
278 | RTC->MODE2.CTRLA.reg &= ~RTC_MODE2_CTRLA_SWRST; // software reset remove
279 | while (RTCisSyncing(RTC_MODE2_CTRLA_SWRST))
280 | ;
281 | }
282 |
283 | extern "C"
284 | {
285 | void RTC_Handler(void)
286 | {
287 | uint32_t flag = 0;
288 |
289 | if (RTC_callBack != NULL)
290 | {
291 |
292 | if (RTC->MODE2.INTFLAG.reg & RTC_MODE2_INTFLAG_ALARM0)
293 | flag |= 1;
294 | if (RTC->MODE2.INTFLAG.reg & RTC_MODE2_INTFLAG_ALARM1)
295 | flag |= 2;
296 | RTC_callBack(flag);
297 | }
298 | if (flag & 1)
299 | {
300 | RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0;
301 | }
302 | if (flag & 2)
303 | {
304 | RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM1;
305 | }
306 | }
307 | }
308 | #endif
--------------------------------------------------------------------------------
/src/RTC_SAMD51.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 | Author: Hongtai Liu (lht856@foxmail.com)
4 | Copyright (C) 2020 Seeed Technology Co.,Ltd.
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 | */
21 |
22 | #ifdef __SAMD51__
23 | #ifndef __RTC_SAMD51_H__
24 | #define __RTC_SAMD51_H__
25 | #include "DateTime.h"
26 |
27 |
28 | typedef void (*rtcCallBack)(uint32_t flag);
29 |
30 | // Default date & time after reset
31 | #define DEFAULT_YEAR 2000 // 2000..2063
32 | #define DEFAULT_MONTH 1 // 1..12
33 | #define DEFAULT_DAY 1 // 1..31
34 | #define DEFAULT_HOUR 0 // 1..23
35 | #define DEFAULT_MINUTE 0 // 0..59
36 | #define DEFAULT_SECOND 0 // 0..59
37 |
38 | class RTC_SAMD51
39 | {
40 | public:
41 | enum Alarm_Match : uint8_t // Should we have this enum or just use the identifiers from /component/rtc.h ?
42 | {
43 | MATCH_OFF = RTC_MODE2_MASK_SEL_OFF_Val, // Never
44 | MATCH_SS = RTC_MODE2_MASK_SEL_SS_Val, // Every Minute
45 | MATCH_MMSS = RTC_MODE2_MASK_SEL_MMSS_Val, // Every Hour
46 | MATCH_HHMMSS = RTC_MODE2_MASK_SEL_HHMMSS_Val, // Every Day
47 | MATCH_DHHMMSS = RTC_MODE2_MASK_SEL_DDHHMMSS_Val, // Every Month
48 | MATCH_MMDDHHMMSS = RTC_MODE2_MASK_SEL_MMDDHHMMSS_Val, // Every Year
49 | MATCH_YYMMDDHHMMSS = RTC_MODE2_MASK_SEL_YYMMDDHHMMSS_Val // Once, on a specific date and a specific time
50 | };
51 |
52 | boolean begin();
53 | void adjust(const DateTime &dt);
54 | DateTime now();
55 | void setAlarm(uint8_t id, const DateTime &dt);
56 | DateTime alarm(uint8_t id);
57 | void enableAlarm(uint8_t id, Alarm_Match match);
58 | void disableAlarm(uint8_t id);
59 | void attachInterrupt(rtcCallBack callback);
60 | void detachInterrupt();
61 | void standbyMode();
62 |
63 | private:
64 | void config32kOSC(void);
65 | void configureClock(void);
66 | void RTCreadRequest();
67 | bool RTCisSyncing(uint32_t flag = RTC_MODE2_SYNCBUSY_MASK_);
68 | void RTCdisable();
69 | void RTCenable();
70 | void RTCreset();
71 | void RTCresetRemove();
72 | };
73 | #endif
74 | #endif
--------------------------------------------------------------------------------