Skip to content
This repository has been archived by the owner on Oct 27, 2024. It is now read-only.

Commit

Permalink
Merge pull request #79 from matthias-bs/feature-rp2040
Browse files Browse the repository at this point in the history
Feature rp2040
  • Loading branch information
matthias-bs authored Oct 7, 2023
2 parents e1bf769 + c95faa2 commit 7efbdde
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 49 deletions.
99 changes: 63 additions & 36 deletions BresserWeatherSensorTTN.ino
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,8 @@
#include "logging.h"

#ifdef ARDUINO_ARCH_RP2040
//#include "pico.h"
#include "src/pico_rtc/pico_rtc_utils.h"
#include "hardware/rtc.h"
#include "hardware/structs/vreg_and_chip_reset.h" // for reset reason detection
#include "hardware/regs/vreg_and_chip_reset.h" // for reset reason detection
#include <hardware/rtc.h>
#endif

#ifdef RAINDATA_EN
Expand Down Expand Up @@ -618,11 +615,18 @@ const cMyLoRaWAN::lmic_pinmap myPinMap = {
RTC_DATA_ATTR uint8_t rtcSavedExtraInfo[EXTRA_INFO_MEM_SIZE]; //!< extra Session Info data
#endif

// TODO:
// RP2040: move to Preferences
RTC_DATA_ATTR bool runtimeExpired = false; //!< flag indicating if runtime has expired at least once
RTC_DATA_ATTR bool longSleep; //!< last sleep interval; 0 - normal / 1 - long
RTC_DATA_ATTR time_t rtcLastClockSync = 0; //!< timestamp of last RTC synchonization to network time
// Variables which must retain their values after deep sleep
#if defined(ESP32)
// Stored in RTC RAM
RTC_DATA_ATTR bool runtimeExpired = false; //!< flag indicating if runtime has expired at least once
RTC_DATA_ATTR bool longSleep; //!< last sleep interval; 0 - normal / 1 - long
RTC_DATA_ATTR time_t rtcLastClockSync = 0; //!< timestamp of last RTC synchonization to network time
#else
// Save to/restored from Watchdog SCRATCH registers
bool runtimeExpired; //!< flag indicating if runtime has expired at least once
bool longSleep; //!< last sleep interval; 0 - normal / 1 - long
time_t rtcLastClockSync; //!< timestamp of last RTC synchonization to network time
#endif

#ifdef ESP32
#ifdef ADC_EN
Expand Down Expand Up @@ -764,8 +768,23 @@ ESP32Time rtc;
/// Arduino setup
void setup() {
#if defined(ARDUINO_ARCH_RP2040)
// see pico-sdk/src/rp2_common/hardware_rtc/rtc.c
rtc_init();
// see pico-sdk/src/rp2_common/hardware_rtc/rtc.c
rtc_init();

// Restore variables and RTC after reset
time_t time_saved = watchdog_hw->scratch[0];
datetime_t dt;
epoch_to_datetime(&time_saved, &dt);

// Set HW clock (only used in sleep mode)
rtc_set_datetime(&dt);

// Set SW clock
rtc.setTime(time_saved);

runtimeExpired = ((watchdog_hw->scratch[1] & 1) == 1);
longSleep = ((watchdog_hw->scratch[1] & 2) == 2);
rtcLastClockSync = watchdog_hw->scratch[2];
#endif

// set baud rate
Expand All @@ -776,6 +795,9 @@ void setup() {
// wait for serial to be ready - or timeout if USB is not connected
delay(500);

#if defined(ARDUINO_ARCH_RP2040)
log_i("Time saved: %lu", time_saved);
#endif
preferences.begin("BWS-TTN", false);
prefs.ws_timeout = preferences.getUChar("ws_timeout", WEATHERSENSOR_TIMEOUT);
log_d("Preferences: weathersensor_timeout: %u s", prefs.ws_timeout);
Expand Down Expand Up @@ -1263,11 +1285,10 @@ cMyLoRaWAN::GetAbpProvisioningInfo(AbpProvisioningInfo *pAbpInfo) {
return false;
}
#if defined(ARDUINO_ARCH_RP2040)
if ((vreg_and_chip_reset_hw->chip_reset &
(VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS |
VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS)) != 0) {
// Last reset was power-on/brown-out detection or RUN pin reset;
// we assume that stored session info is no longer valid and clear it.
if (!watchdog_caused_reboot()) {
// Last reset was not caused by the watchdog, i.e. SW reset via restart().
// Consequently, a power-on/brown-out detection or RUN pin reset occurred.
// We assume that stored session info is no longer valid and clear it.
// A new join will be faster than trying with stale session info and
// running into a timeout.
log_d("HW reset detected, deleting session info.");
Expand Down Expand Up @@ -1332,16 +1353,8 @@ void prepareSleep(void) {
// to next non-fractional multiple of sleep_interval past the hour
if (rtcLastClockSync) {
struct tm timeinfo;
//#ifdef ESP32
time_t t_now = rtc.getLocalEpoch();
localtime_r(&t_now, &timeinfo);
//#else
// FIXME Is this needed?
// datetime_t t_now;
// rtc_get_datetime(&t_now);
// datetime_to_tm(t_now, timeinfo);
//#endif

time_t t_now = rtc.getLocalEpoch();
localtime_r(&t_now, &timeinfo);

sleep_interval = sleep_interval - ((timeinfo.tm_min * 60) % sleep_interval + timeinfo.tm_sec);
}
Expand All @@ -1351,19 +1364,33 @@ void prepareSleep(void) {
sleep_interval += 20; // Added extra 20-secs of sleep to allow for slow ESP32 RTC timers
ESP.deepSleep(sleep_interval * 1000000LL);
#else
// Set RTC to an arbitrary, but valid time
datetime_t dt = {
.year = 2023,
.month = 10,
.day = 06,
.dotw = 5, // 0 is Sunday, so 5 is Friday
.hour = 17,
.min = 15,
.sec = 00
};
time_t t_now = rtc.getLocalEpoch();
datetime_t dt;
epoch_to_datetime(&t_now, &dt);
rtc_set_datetime(&dt);
sleep_us(64);
pico_sleep(sleep_interval);

// Save variables to be retained after reset
watchdog_hw->scratch[2] = rtcLastClockSync;

if (runtimeExpired) {
watchdog_hw->scratch[1] |= 1;
} else {
watchdog_hw->scratch[1] &= ~1;
}
if (longSleep) {
watchdog_hw->scratch[1] |= 2;
} else {
watchdog_hw->scratch[1] &= ~2;
}

// Save the current time, because RTC will be reset (SIC!)
rtc_get_datetime(&dt);
time_t now = datetime_to_epoch(&dt, NULL);
watchdog_hw->scratch[0] = now;
log_i("Now: %lu", now);

rp2040.restart();
#endif
}
Expand Down
102 changes: 89 additions & 13 deletions src/pico_rtc/pico_rtc_utils.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
///////////////////////////////////////////////////////////////////////////////
// pico_rtc_utils.cpp
//
// RTC utility functions for RP2040
//
// Sleep/wakeup scheme based on
// https://github.com/lyusupov/SoftRF/tree/master/software/firmware/source/libraries/RP2040_Sleep
// by Linar Yusupov
//
// Using code from pico-extras:
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/pico_sleep/include/pico/sleep.h
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/pico_sleep/sleep.c
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/hardware_rosc/include/hardware/rosc.h
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/hardware_rosc/rosc.c
//
// created: 10/2023
//
//
// MIT License
//
// Copyright (c) 2023 Matthias Prinke
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//
// History:
//
// 20231006 Created
//
// ToDo:
// -
//
///////////////////////////////////////////////////////////////////////////////
#if defined(ARDUINO_ARCH_RP2040)

#include "pico_rtc_utils.h"
Expand Down Expand Up @@ -29,34 +78,61 @@ datetime_t *tm_to_datetime(struct tm *ti, datetime_t *dt)
}

void print_dt(datetime_t dt) {
printf("%4d-%02d-%02d %02d:%02d:%02d\n", dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec);
log_i("%4d-%02d-%02d %02d:%02d:%02d", dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec);
}

void print_tm(struct tm ti) {
printf("%4d-%02d-%02d %02d:%02d:%02d\n", ti.tm_year+1900, ti.tm_mon+1, ti.tm_mday, ti.tm_hour, ti.tm_min, ti.tm_sec);
log_i("%4d-%02d-%02d %02d:%02d:%02d", ti.tm_year+1900, ti.tm_mon+1, ti.tm_mday, ti.tm_hour, ti.tm_min, ti.tm_sec);
}

time_t datetime_to_epoch(datetime_t *dt, time_t *epoch) {
struct tm ti;
datetime_to_tm(dt, &ti);

// Apply daylight saving time according to timezone and date
ti.tm_isdst = -1;

// Convert to epoch
time_t _epoch = mktime(&ti);

if (epoch) {
*epoch = _epoch;
}

return _epoch;
}

datetime_t *epoch_to_datetime(time_t *epoch, datetime_t *dt) {
struct tm ti;

// Apply daylight saving time according to timezone and date
ti.tm_isdst = -1;

// Convert epoch to struct tm
localtime_r(epoch, &ti);

// Convert struct tm to datetime_t
tm_to_datetime(&ti, dt);

return dt;
}

// Sleep for <duration> seconds
void pico_sleep(unsigned duration) {
datetime_t dt;
rtc_get_datetime(&dt);
printf("RTC time:\n");
log_i("RTC time:");
print_dt(dt);

struct tm ti;
datetime_to_tm(&dt, &ti);

// Convert to epoch
time_t now = mktime(&ti);
time_t now;
datetime_to_epoch(&dt, &now);

// Add sleep_duration
time_t wakeup = now + duration;

// Convert epoch to struct tm
localtime_r(&wakeup, &ti);
epoch_to_datetime(&wakeup, &dt);

// Convert struct tm to datetime_t
tm_to_datetime(&ti, &dt);
printf("Wakeup time:\n");
log_i("Wakeup time:");
print_dt(dt);

Serial.flush();
Expand Down
54 changes: 54 additions & 0 deletions src/pico_rtc/pico_rtc_utils.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,68 @@
///////////////////////////////////////////////////////////////////////////////
// pico_rtc_utils.h
//
// RTC utility functions for RP2040
//
// Sleep/wakeup scheme based on
// https://github.com/lyusupov/SoftRF/tree/master/software/firmware/source/libraries/RP2040_Sleep
// by Linar Yusupov
//
// Using code from pico-extras:
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/pico_sleep/include/pico/sleep.h
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/pico_sleep/sleep.c
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/hardware_rosc/include/hardware/rosc.h
// https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/hardware_rosc/rosc.c
//
// created: 10/2023
//
//
// MIT License
//
// Copyright (c) 2023 Matthias Prinke
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//
// History:
//
// 20231006 Created
//
// ToDo:
// -
//
///////////////////////////////////////////////////////////////////////////////
#if defined(ARDUINO_ARCH_RP2040)
#include <Arduino.h>
#include <time.h>
#include <pico/stdlib.h>
#include <hardware/rtc.h>
#include "pico_sleep.h"
#include "pico_rosc.h"
#include "../../logging.h"

#ifndef PICO_RTC_UTILS_H
#define PICO_RTC_UTILS_H

struct tm *datetime_to_tm(datetime_t *dt, struct tm *ti);
datetime_t *tm_to_datetime(struct tm *ti, datetime_t *dt);
time_t datetime_to_epoch(datetime_t *dt, time_t *epoch);
datetime_t *epoch_to_datetime(time_t *epoch, datetime_t *dt);

void print_dt(datetime_t dt);
void print_tm(struct tm ti);
Expand Down

0 comments on commit 7efbdde

Please sign in to comment.