-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
184 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
from pimoroni import ShiftRegister, PWMLED | ||
from machine import Pin, I2C, RTC | ||
from wakeup import get_shift_state, reset_shift_state | ||
from micropython import const | ||
import pcf85063a | ||
import ntptime | ||
import time | ||
|
||
BLACK = const(0) | ||
WHITE = const(1) | ||
|
||
GREEN = const(2) | ||
BLUE = const(3) | ||
RED = const(4) | ||
YELLOW = const(5) | ||
ORANGE = const(6) | ||
TAUPE = const(7) | ||
|
||
SR_CLOCK = const(8) | ||
SR_LATCH = const(9) | ||
SR_OUT = const(10) | ||
|
||
LED_A = const(11) | ||
LED_B = const(12) | ||
LED_C = const(13) | ||
LED_D = const(14) | ||
LED_E = const(15) | ||
|
||
LED_BUSY = const(6) | ||
LED_WIFI = const(7) | ||
|
||
HOLD_VSYS_EN = const(2) | ||
|
||
RTC_ALARM = const(2) | ||
EXTERNAL_TRIGGER = const(1) | ||
EINK_BUSY = const(0) | ||
|
||
SHIFT_STATE = get_shift_state() | ||
|
||
reset_shift_state() | ||
|
||
i2c = I2C(0) | ||
rtc = pcf85063a.PCF85063A(i2c) | ||
i2c.writeto_mem(0x51, 0x00, b'\x00') # ensure rtc is running (this should be default?) | ||
rtc.enable_timer_interrupt(False) | ||
|
||
vsys = Pin(HOLD_VSYS_EN) | ||
vsys.on() | ||
|
||
|
||
def woken_by_rtc(): | ||
mask = (1 << RTC_ALARM) | ||
return bool(sr.read() & mask) or bool(SHIFT_STATE & mask) | ||
|
||
|
||
def woken_by_ext_trigger(): | ||
mask = (1 << EXTERNAL_TRIGGER) | ||
return bool(sr.read() & mask) or bool(SHIFT_STATE & mask) | ||
|
||
|
||
def woken_by_button(): | ||
return bool(sr.read() & 0b11111000) or bool(SHIFT_STATE & 0b11111000) | ||
|
||
|
||
def pico_rtc_to_pcf(): | ||
# Set the PCF85063A to the time stored by Pico W's RTC | ||
year, month, day, dow, hour, minute, second, _ = RTC().datetime() | ||
rtc.datetime((year, month, day, hour, minute, second, dow)) | ||
|
||
|
||
def pcf_to_pico_rtc(): | ||
# Set Pico W's RTC to the time stored by the PCF85063A | ||
t = rtc.datetime() | ||
# BUG ERRNO 22, EINVAL, when date read from RTC is invalid for the Pico's RTC. | ||
try: | ||
RTC().datetime((t[0], t[1], t[2], t[6], t[3], t[4], t[5], 0)) | ||
return True | ||
except OSError: | ||
return False | ||
|
||
|
||
def sleep_for(minutes): | ||
year, month, day, hour, minute, second, dow = rtc.datetime() | ||
|
||
# if the time is very close to the end of the minute, advance to the next minute | ||
# this aims to fix the edge case where the board goes to sleep right as the RTC triggers, thus never waking up | ||
if second >= 55: | ||
minute += 1 | ||
|
||
# Can't sleep beyond a month, so clamp the sleep to a 28 day maximum | ||
minutes = min(minutes, 40320) | ||
|
||
# Calculate the future alarm date; first, turn the current time into seconds since epoch | ||
sec_since_epoch = time.mktime((year, month, day, hour, minute, second, dow, 0)) | ||
|
||
# Add the required minutes to this | ||
sec_since_epoch += minutes * 60 | ||
|
||
# And convert it back into a more useful tuple | ||
(ayear, amonth, aday, ahour, aminute, asecond, adow, adoy) = time.localtime(sec_since_epoch) | ||
|
||
# And now set the alarm as before, now including the day | ||
rtc.clear_alarm_flag() | ||
rtc.set_alarm(0, aminute, ahour, aday) | ||
rtc.enable_alarm_interrupt(True) | ||
|
||
turn_off() | ||
|
||
# Simulate sleep while on USB power | ||
while minutes > 0: | ||
time.sleep(60) | ||
minutes -= 1 | ||
|
||
|
||
def turn_off(): | ||
time.sleep(0.1) | ||
vsys.off() | ||
|
||
|
||
def set_time(): | ||
# Set both Pico W's RTC and PCF85063A to NTP time | ||
ntptime.settime() | ||
pico_rtc_to_pcf() | ||
|
||
|
||
class Button: | ||
def __init__(self, sr, idx, led, debounce=50): | ||
self.sr = sr | ||
self.startup_state = bool(SHIFT_STATE & (1 << idx)) | ||
self.led = PWMLED(led) | ||
self.led.off() | ||
self._idx = idx | ||
self._debounce_time = debounce | ||
self._changed = time.ticks_ms() | ||
self._last_value = None | ||
|
||
def led_on(self): | ||
self.led.on() | ||
|
||
def led_off(self): | ||
self.led.off() | ||
|
||
def led_brightness(self, brightness): | ||
self.led.brightness(brightness) | ||
|
||
def led_toggle(self): | ||
self.led.toggle() | ||
|
||
def read(self): | ||
if self.startup_state: | ||
self.startup_state = False | ||
return True | ||
|
||
value = self.raw() | ||
if value != self._last_value and time.ticks_ms() - self._changed > self._debounce_time: | ||
self._last_value = value | ||
self._changed = time.ticks_ms() | ||
return value | ||
return False | ||
|
||
def raw(self): | ||
if self.startup_state: | ||
self.startup_state = False | ||
return True | ||
return self.sr[self._idx] == 1 | ||
|
||
@property | ||
def is_pressed(self): | ||
return self.raw() | ||
|
||
|
||
sr = ShiftRegister(SR_CLOCK, SR_LATCH, SR_OUT) | ||
|
||
button_a = Button(sr, 7, LED_A) | ||
button_b = Button(sr, 6, LED_B) | ||
button_c = Button(sr, 5, LED_C) | ||
button_d = Button(sr, 4, LED_D) | ||
button_e = Button(sr, 3, LED_E) | ||
|
||
led_busy = PWMLED(LED_BUSY) | ||
led_wifi = PWMLED(LED_WIFI) |