{"author": "chris007", "name": "BME680 Sensor Demo", "description": "Demo for the BME860 Sensor", "category": "Hardware", "revision": 1}
{"author": "chris007", "name": "BME680", "description": "Demo for the BME860 Sensor", "category": "Hardware", "revision": 1}
......@@ -6,6 +6,7 @@ import buttons
import max30001
import math
import struct
import itertools
WIDTH = 160
HEIGHT = 80
......@@ -26,6 +27,15 @@ COLOR_WRITE_FG = [255, 255, 255]
COLOR_WRITE_BG = [255, 0, 0]
current_mode = MODE_FINGER
modes = itertools.cycle(
[
({"bar", "pulse"}, {"text": "Top + Pulse", "posx": 0}),
({}, {"text": "off", "posx": 55}),
({"bar"}, {"text": "Top Only", "posx": 25}),
({"pulse"}, {"text": "Pulse Only", "posx": 5}),
]
)
led_mode = next(modes)[0]
history = []
filebuffer = bytearray()
write = 0
......@@ -36,6 +46,7 @@ pause_histogram = False
histogram_offset = 0
sensor = 0
disp = display.open()
last_sample_count = 1
leds.dim_top(1)
COLORS = [((23 + (15 * i)) % 360, 1.0, 1.0) for i in range(11)]
......@@ -48,7 +59,8 @@ beta = 3
def update_history(datasets):
global history, moving_average, alpha, beta
global history, moving_average, alpha, beta, last_sample_count
last_sample_count = len(datasets)
for val in datasets:
history.append(val - moving_average)
moving_average = (alpha * moving_average + beta * val) / (alpha + beta)
......@@ -60,6 +72,7 @@ def update_history(datasets):
# variables for pulse detection
pulse = -1
samples_since_last_pulse = 0
last_pulse_blink = 0
q_threshold = -1
r_threshold = 1
q_spike = -ECG_RATE
......@@ -177,14 +190,28 @@ def close_sensor():
def toggle_mode():
global current_mode
global current_mode, disp, pause_screen
if write > 0:
pause_screen = utime.time_ms() + 500
disp.clear(COLOR_BACKGROUND)
disp.print("Locked", posx=30, posy=30, fg=COLOR_TEXT)
disp.update()
return
close_sensor()
current_mode = MODE_USB if current_mode == MODE_FINGER else MODE_FINGER
open_sensor()
def toggle_bias():
global bias
global bias, disp, pause_screen
if write > 0:
pause_screen = utime.time_ms() + 500
disp.clear(COLOR_BACKGROUND)
disp.print("Locked", posx=30, posy=30, fg=COLOR_TEXT)
disp.update()
return
close_sensor()
bias = not bias
open_sensor()
......@@ -209,19 +236,61 @@ def toggle_write():
def toggle_pause():
global pause_histogram, histogram_offset, history
global pause_histogram, histogram_offset, history, leds
if pause_histogram:
pause_histogram = False
history = []
else:
pause_histogram = True
histogram_offset = 0
leds.clear()
def toggle_leds():
global led_mode, disp, pause_screen, leds, modes
led_mode, display_args = next(modes)
pause_screen = utime.time_ms() + 250
disp.clear(COLOR_BACKGROUND)
disp.print("LEDs", posx=50, posy=20, fg=COLOR_TEXT)
disp.print(**display_args, posy=40, fg=COLOR_TEXT)
disp.update()
leds.clear()
def draw_leds(vmin, vmax):
# vmin should be in [0, -1]
# vmax should be in [0, 1]
global pulse, samples_since_last_pulse, last_pulse_blink
# stop blinking
if not bool(led_mode):
return
# update led bar
if "bar" in led_mode:
for i in reversed(range(6)):
leds.prep_hsv(
5 + i, COLORS[5 + i] if vmin <= 0 and i <= vmin * -6 else (0, 0, 0)
)
for i in reversed(range(6)):
leds.prep_hsv(
i, COLORS[i] if vmax >= 0 and 5 - i <= vmax * 6 else (0, 0, 0)
)
# blink red on pulse
if (
"pulse" in led_mode
and pulse > 0
and samples_since_last_pulse < last_pulse_blink
):
for i in range(4):
leds.prep(11 + i, (255, 0, 0))
elif "pulse" in led_mode:
for i in range(4):
leds.prep(11 + i, (0, 0, 0))
last_pulse_blink = samples_since_last_pulse
def draw_leds(val):
# val should be in [0, 11]
for i in range(11):
leds.prep_hsv(10 - i, COLORS[10 - i] if i < val else (0, 0, 0))
leds.update()
......@@ -273,7 +342,10 @@ def draw_histogram():
fg=COLOR_TEXT,
)
else:
draw_leds((max(history[-5:]) * scale + SCALE_FACTOR) * 11 / (SCALE_FACTOR * 2))
led_range = last_sample_count if last_sample_count > 5 else 5
draw_leds(
min(history[-led_range:]) / value_max, max(history[-led_range:]) / value_max
)
if pulse < 0:
disp.print(
current_mode + ("+Bias" if bias else ""),
......@@ -308,10 +380,17 @@ def main():
# show button layout
disp.clear(COLOR_BACKGROUND)
disp.print(" BUTTONS ", posx=0, posy=0, fg=COLOR_TEXT)
disp.print("Finger/USB>", posx=0, posy=20, fg=COLOR_MODE_FINGER)
disp.print(" Bias >", posx=0, posy=40, fg=COLOR_MODE_USB)
disp.print("< Write Log", posx=0, posy=60, fg=COLOR_WRITE_BG)
disp.print(" BUTTONS ", posx=0, posy=0, fg=COLOR_TEXT, font=display.FONT20)
disp.line(0, 20, 159, 20, col=COLOR_LINE)
disp.print(
" Pause >", posx=0, posy=28, fg=COLOR_MODE_FINGER, font=display.FONT16
)
disp.print(
" Mode/Bias >", posx=0, posy=44, fg=COLOR_MODE_USB, font=display.FONT16
)
disp.print(
"< LED/WriteLog", posx=0, posy=64, fg=COLOR_WRITE_BG, font=display.FONT16
)
disp.update()
utime.sleep(3)
......@@ -324,64 +403,96 @@ def main():
buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT
)
# TOP RIGHT
# down
if button_pressed["TOP_RIGHT"] == 0 and v & buttons.TOP_RIGHT != 0:
button_pressed["TOP_RIGHT"] = utime.time_ms()
toggle_pause()
# up
if button_pressed["TOP_RIGHT"] > 0 and v & buttons.TOP_RIGHT == 0:
duration = utime.time_ms() - button_pressed["TOP_RIGHT"]
button_pressed["TOP_RIGHT"] = 0
# BOTTOM LEFT
#
# on pause = shift view left
# long = toggle write
# short = toggle leds
# down, and still pressed
if (
button_pressed["BOTTOM_LEFT"] > 0
and v & buttons.BOTTOM_LEFT != 0
and not pause_histogram
):
duration = utime.time_ms() - button_pressed["BOTTOM_LEFT"]
if duration > 1000:
button_pressed["BOTTOM_LEFT"] = -1
toggle_write()
if button_pressed["BOTTOM_LEFT"] == 0 and v & buttons.BOTTOM_LEFT != 0:
# register down event
elif button_pressed["BOTTOM_LEFT"] == 0 and v & buttons.BOTTOM_LEFT != 0:
button_pressed["BOTTOM_LEFT"] = utime.time_ms()
# register up event but event already called
if button_pressed["BOTTOM_LEFT"] == -1 and v & buttons.BOTTOM_LEFT == 0:
button_pressed["BOTTOM_LEFT"] = 0
# register normal up event
elif button_pressed["BOTTOM_LEFT"] > 0 and v & buttons.BOTTOM_LEFT == 0:
duration = utime.time_ms() - button_pressed["BOTTOM_LEFT"]
button_pressed["BOTTOM_LEFT"] = 0
if not pause_histogram:
toggle_write()
toggle_leds()
else:
l = len(history)
histogram_offset += ECG_RATE / 2
if l - histogram_offset < WIDTH:
histogram_offset = l - WIDTH
if button_pressed["BOTTOM_LEFT"] > 0 and v & buttons.BOTTOM_LEFT == 0:
duration = utime.time_ms() - button_pressed["BOTTOM_LEFT"]
button_pressed["BOTTOM_LEFT"] = 0
# BOTTOM RIGHT
if button_pressed["BOTTOM_RIGHT"] == 0 and v & buttons.BOTTOM_RIGHT != 0:
button_pressed["BOTTOM_RIGHT"] = utime.time_ms()
if not pause_histogram:
toggle_bias()
else:
histogram_offset -= ECG_RATE / 2
histogram_offset -= histogram_offset % (ECG_RATE / 2)
if histogram_offset < 0:
histogram_offset = 0
if button_pressed["BOTTOM_RIGHT"] > 0 and v & buttons.BOTTOM_RIGHT == 0:
duration = utime.time_ms() - button_pressed["BOTTOM_RIGHT"]
button_pressed["BOTTOM_RIGHT"] = 0
# TOP RIGHT
#
# on pause = shift view right
# long = toggle bias
# short = toggle mode (finger/usb)
# down, and still pressed
if button_pressed["TOP_RIGHT"] > 0 and v & buttons.TOP_RIGHT != 0:
duration = utime.time_ms() - button_pressed["TOP_RIGHT"]
if (
button_pressed["BOTTOM_RIGHT"] > 0
and v & buttons.BOTTOM_RIGHT != 0
and not pause_histogram
):
duration = utime.time_ms() - button_pressed["BOTTOM_RIGHT"]
if duration > 1000:
button_pressed["TOP_RIGHT"] = -1
toggle_pause()
button_pressed["BOTTOM_RIGHT"] = -1
toggle_bias()
# register down event
elif button_pressed["TOP_RIGHT"] == 0 and v & buttons.TOP_RIGHT != 0:
button_pressed["TOP_RIGHT"] = utime.time_ms()
elif button_pressed["BOTTOM_RIGHT"] == 0 and v & buttons.BOTTOM_RIGHT != 0:
button_pressed["BOTTOM_RIGHT"] = utime.time_ms()
# register up event but event already called
if button_pressed["TOP_RIGHT"] == -1 and v & buttons.TOP_RIGHT == 0:
button_pressed["TOP_RIGHT"] = 0
if button_pressed["BOTTOM_RIGHT"] == -1 and v & buttons.BOTTOM_RIGHT == 0:
button_pressed["BOTTOM_RIGHT"] = 0
# register normal up event
elif button_pressed["TOP_RIGHT"] > 0 and v & buttons.TOP_RIGHT == 0:
duration = utime.time_ms() - button_pressed["TOP_RIGHT"]
button_pressed["TOP_RIGHT"] = 0
elif button_pressed["BOTTOM_RIGHT"] > 0 and v & buttons.BOTTOM_RIGHT == 0:
duration = utime.time_ms() - button_pressed["BOTTOM_RIGHT"]
button_pressed["BOTTOM_RIGHT"] = 0
if pause_histogram:
toggle_pause()
histogram_offset -= ECG_RATE / 2
histogram_offset -= histogram_offset % (ECG_RATE / 2)
if histogram_offset < 0:
histogram_offset = 0
else:
toggle_mode()
if __name__ == "__main__":
main()
try:
main()
except KeyboardInterrupt as e:
sensor.close()
raise e
......@@ -87,6 +87,8 @@ static const mp_rom_map_elem_t interrupt_module_globals_table[] = {
MP_OBJ_NEW_SMALL_INT(EPIC_INT_RTC_ALARM) },
{ MP_ROM_QSTR(MP_QSTR_BHI160_ACCELEROMETER),
MP_OBJ_NEW_SMALL_INT(EPIC_INT_BHI160_ACCELEROMETER) },
{ MP_ROM_QSTR(MP_QSTR_BHI160_MAGNETOMETER),
MP_OBJ_NEW_SMALL_INT(EPIC_INT_BHI160_MAGNETOMETER) },
{ MP_ROM_QSTR(MP_QSTR_BHI160_ORIENTATION),
MP_OBJ_NEW_SMALL_INT(EPIC_INT_BHI160_ORIENTATION) },
{ MP_ROM_QSTR(MP_QSTR_BHI160_GYROSCOPE),
......
......@@ -188,6 +188,32 @@ static mp_obj_t mp_os_urandom(mp_obj_t size_in)
}
static MP_DEFINE_CONST_FUN_OBJ_1(urandom_obj, mp_os_urandom);
enum usb_config_device {
USB_DEVICE_NONE,
USB_DEVICE_FLASH,
USB_DEVICE_SERIAL,
};
static mp_obj_t mp_os_usbconfig(mp_obj_t dev)
{
int device = mp_obj_get_int(dev);
switch (device) {
case USB_DEVICE_NONE:
epic_usb_shutdown();
break;
case USB_DEVICE_FLASH:
epic_usb_storage();
break;
case USB_DEVICE_SERIAL:
epic_usb_cdcacm();
break;
default:
mp_raise_ValueError("Invalid parameter");
}
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(usbconfig_obj, mp_os_usbconfig);
static const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_os) },
{ MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&exit_obj) },
......@@ -199,6 +225,11 @@ static const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&rename_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_battery), MP_ROM_PTR(&read_battery_obj) },
{ MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&urandom_obj) },
{ MP_ROM_QSTR(MP_QSTR_usbconfig), MP_ROM_PTR(&usbconfig_obj) },
{ MP_ROM_QSTR(MP_QSTR_USB_SERIAL), MP_ROM_INT(USB_DEVICE_SERIAL) },
{ MP_ROM_QSTR(MP_QSTR_USB_FLASH), MP_ROM_INT(USB_DEVICE_FLASH) },
{ MP_ROM_QSTR(MP_QSTR_USB_NONE), MP_ROM_INT(USB_DEVICE_NONE) },
};
static MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
......
......@@ -127,3 +127,23 @@ class BHI160Orientation(BHI160):
def convert(self, sample):
return self.convert_data_vector(sample)
class BHI160Magnetometer(BHI160):
def __init__(
self, sample_rate=4, dynamic_range=1, callback=None, sample_buffer_len=200
):
self.sample_rate = sample_rate
self.dynamic_range = dynamic_range
self.callback = callback
self.sample_buffer_len = sample_buffer_len
self.sensor_id = 1
self.interrupt_id = interrupt.BHI160_MAGNETOMETER
self._callback = callback
self.enable_sensor()
def convert_single(self, value):
return 1000 * value / 32768.0
def convert(self, sample):
return self.convert_data_vector(sample)
......@@ -74,7 +74,7 @@ class Display:
:param text: Text to print
:param fg: Foreground color (expects RGB triple)
:param bg: Background color (expects RGB triple)
:param bg: Background color (expects RGB triple) or None for transparent background
:param posx: X-Position of the first character, 0 <= posx <= 159
:param posy: Y-Position of the first character, 0 <= posy <= 79
:param font: 0 <= font <= 4 (currently) selects a font
......@@ -95,9 +95,13 @@ class Display:
d.clear()
d.print('Hello Earth!', font=display.FONT24)
d.update()
.. versionchanged:: 1.11
Added transparent background printing.
"""
fg = fg or color.WHITE
bg = bg or color.BLACK
bg = bg or fg
sys_display.print_adv(text, posx, posy, fg, bg, font)
return self
......
......@@ -159,6 +159,9 @@ class Menu:
Exit the event-loop. This should be called from inside an ``on_*`` hook.
.. versionadded:: 1.9
.. versionchanged:: 1.11
Fixed this function not working properly.
"""
raise _ExitMenuException()
......@@ -282,6 +285,8 @@ class Menu:
self.idx = (self.idx + 1) % len(self.entries)
try:
self.on_scroll(self.entries[self.idx], self.idx)
except _ExitMenuException:
raise
except Exception as e:
print("Exception during menu.on_scroll():")
sys.print_exception(e)
......@@ -291,6 +296,8 @@ class Menu:
self.idx = (self.idx + len(self.entries) - 1) % len(self.entries)
try:
self.on_scroll(self.entries[self.idx], self.idx)
except _ExitMenuException:
raise
except Exception as e:
print("Exception during menu.on_scroll():")
sys.print_exception(e)
......@@ -298,6 +305,8 @@ class Menu:
try:
self.on_select(self.entries[self.idx], self.idx)
self.select_time = utime.time_ms()
except _ExitMenuException:
raise
except Exception as e:
print("Menu crashed!")
sys.print_exception(e)
......
......@@ -48,6 +48,8 @@ Q(ticks_add)
Q(ticks_diff)
Q(localtime)
Q(mktime)
Q(monotonic)
Q(monotonic_ms)
Q(time)
Q(time_ms)
Q(set_time)
......@@ -61,6 +63,7 @@ Q(set_callback)
Q(enable_callback)
Q(disable_callback)
Q(BHI160_ACCELEROMETER)
Q(BHI160_MAGNETOMETER)
Q(BHI160_ORIENTATION)
Q(BHI160_GYROSCOPE)
Q(RTC_ALARM)
......@@ -140,6 +143,10 @@ Q(mkdir)
Q(rename)
Q(read_battery)
Q(urandom)
Q(usbconfig)
Q(USB_FLASH)
Q(USB_SERIAL)
Q(USB_NONE)
/* gpio */
Q(gpio)
......
......@@ -51,6 +51,22 @@ static mp_obj_t time_time_ms(void)
}
MP_DEFINE_CONST_FUN_OBJ_0(time_time_ms_obj, time_time_ms);
static mp_obj_t time_monotonic(void)
{
mp_int_t seconds;
seconds = epic_rtc_get_monotonic_seconds();
return mp_obj_new_int(seconds);
}
MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_obj, time_monotonic);
static mp_obj_t time_monotonic_ms(void)
{
uint64_t milliseconds;
milliseconds = epic_rtc_get_monotonic_milliseconds();
return mp_obj_new_int_from_ull(milliseconds);
}
MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ms_obj, time_monotonic_ms);
static mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args)
{
mp_int_t seconds;
......@@ -130,6 +146,9 @@ static const mp_rom_map_elem_t time_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
{ MP_ROM_QSTR(MP_QSTR_time_ms), MP_ROM_PTR(&time_time_ms_obj) },
{ MP_ROM_QSTR(MP_QSTR_monotonic), MP_ROM_PTR(&time_monotonic_obj) },
{ MP_ROM_QSTR(MP_QSTR_monotonic_ms),
MP_ROM_PTR(&time_monotonic_ms_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_time), MP_ROM_PTR(&time_set_time_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_unix_time),
MP_ROM_PTR(&time_set_unix_time_obj) },
......