Skip to content
Snippets Groups Projects
Commit 5fd10101 authored by rahix's avatar rahix
Browse files

Merge 'ECG pause mode'

With >1s press on the TOP_RIGHT button you can pause the screen update.
You can then scroll through the increases 4s buffer with BUTTON_LEFT and
BOTTOM_RIGHT. Another press on TOP_RIGHT brings you back into the normal
mode.  The logging operation doesn't get interrupted when pausing the
screen.

See merge request !257
parents 625ae264 ea5a30d9
No related branches found
No related tags found
1 merge request!257feat(ecg-app): add pause-mode
Pipeline #3517 passed
import os import os
import display import display
import utime import utime
import buttons import buttons
import max30001 import max30001
import math import math
import struct import struct
WIDTH = 160 WIDTH = 160
HEIGHT = 80 HEIGHT = 80
OFFSET = 50 OFFSET_Y = 49
ECG_RATE = 128 ECG_RATE = 128
HISTORY_MAX = ECG_RATE * 2 HISTORY_MAX = ECG_RATE * 4
DRAW_AFTER_SAMPLES = 5 DRAW_AFTER_SAMPLES = 5
SCALE_FACTOR = 30 SCALE_FACTOR = 30
MODE_USB = "USB" MODE_USB = "USB"
MODE_FINGER = "Finger" MODE_FINGER = "Finger"
FILEBUFFERBLOCK = 4096 FILEBUFFERBLOCK = 4096
COLOR_BACKGROUND = [0, 0, 0] COLOR_BACKGROUND = [0, 0, 0]
COLOR_LINE = [255, 255, 255] COLOR_LINE = [255, 255, 255]
COLOR_TEXT = [255, 255, 255] COLOR_TEXT = [255, 255, 255]
COLOR_MODE_FINGER = [0, 255, 0] COLOR_MODE_FINGER = [0, 255, 0]
COLOR_MODE_USB = [0, 0, 255] COLOR_MODE_USB = [0, 0, 255]
COLOR_WRITE_FG = [255, 255, 255] COLOR_WRITE_FG = [255, 255, 255]
COLOR_WRITE_BG = [255, 0, 0] COLOR_WRITE_BG = [255, 0, 0]
current_mode = MODE_FINGER current_mode = MODE_FINGER
history = [] history = []
filebuffer = bytearray() filebuffer = bytearray()
write = 0 write = 0
bias = True bias = True
update_screen = 0 update_screen = 0
pause_screen = 0 pause_screen = 0
sensor = 0 pause_histogram = False
disp = display.open() histogram_offset = 0
sensor = 0
disp = display.open()
def callback_ecg(datasets):
global update_screen, history, filebuffer, write
if len(datasets) > 0: def callback_ecg(datasets):
for value in datasets: global update_screen, history, filebuffer, write
history.append(value) update_screen += len(datasets)
update_screen += len(datasets)
if len(history) > HISTORY_MAX: # update histogram datalist
r = len(history) - HISTORY_MAX if pause_histogram == False:
for i in range(r): if len(datasets) > 0:
history.pop(0) for value in datasets:
history.append(value)
# buffer for writes if len(history) > HISTORY_MAX:
if write > 0: r = len(history) - HISTORY_MAX
if len(datasets) > 0: for i in range(r):
for value in datasets: history.pop(0)
filebuffer.extend(struct.pack("h", value))
if len(filebuffer) >= FILEBUFFERBLOCK: # buffer for writes
write_filebuffer() if write > 0:
if len(datasets) > 0:
# don't update on every callback for value in datasets:
if update_screen >= DRAW_AFTER_SAMPLES: filebuffer.extend(struct.pack("h", value))
# print("history: %i, filebuffer: %i" % (len(history), len(filebuffer))) if len(filebuffer) >= FILEBUFFERBLOCK:
draw_histogram() write_filebuffer()
update_screen = 0
# don't update on every callback
if update_screen >= DRAW_AFTER_SAMPLES:
def write_filebuffer(): draw_histogram()
global write, filebuffer
# write to file
chars = "" def write_filebuffer():
lt = utime.localtime(write) global write, filebuffer
filename = "/ecg-%04d-%02d-%02d_%02d%02d%02d.log" % ( # write to file
lt[0], chars = ""
lt[1], lt = utime.localtime(write)
lt[2], filename = "/ecg-%04d-%02d-%02d_%02d%02d%02d.log" % (
lt[3], lt[0],
lt[4], lt[1],
lt[5], lt[2],
) lt[3],
lt[4],
# write stuff to disk lt[5],
# print("Write %i bytes to %s" % (len(filebuffer), filename)) )
try:
f = open(filename, "ab") # write stuff to disk
f.write(filebuffer) try:
f.close() f = open(filename, "ab")
except OSError as e: f.write(filebuffer)
print("Please check the file or filesystem", e) f.close()
write = 0 except OSError as e:
pause_screen = -1 print("Please check the file or filesystem", e)
disp.clear(COLOR_BACKGROUND) write = 0
disp.print("IO Error", posy=0, fg=COLOR_TEXT) pause_screen = -1
disp.print("Please check", posy=20, fg=COLOR_TEXT) disp.clear(COLOR_BACKGROUND)
disp.print("your", posy=40, fg=COLOR_TEXT) disp.print("IO Error", posy=0, fg=COLOR_TEXT)
disp.print("filesystem", posy=60, fg=COLOR_TEXT) disp.print("Please check", posy=20, fg=COLOR_TEXT)
disp.update() disp.print("your", posy=40, fg=COLOR_TEXT)
close_sensor() disp.print("filesystem", posy=60, fg=COLOR_TEXT)
except: disp.update()
print("Unexpected error, stop writeing logfile") close_sensor()
write = 0 except:
print("Unexpected error, stop writeing logfile")
filebuffer = bytearray() write = 0
return
filebuffer = bytearray()
return
def open_sensor():
global sensor
sensor = max30001.MAX30001( def open_sensor():
usb=(False if current_mode == MODE_FINGER else True), global sensor
bias=bias, sensor = max30001.MAX30001(
sample_rate=ECG_RATE, usb=(False if current_mode == MODE_FINGER else True),
callback=callback_ecg, bias=bias,
) sample_rate=ECG_RATE,
callback=callback_ecg,
)
def close_sensor():
global sensor
sensor.close() def close_sensor():
global sensor
sensor.close()
def toggle_mode():
global current_mode
close_sensor() def toggle_mode():
current_mode = MODE_USB if current_mode == MODE_FINGER else MODE_FINGER global current_mode
open_sensor() close_sensor()
current_mode = MODE_USB if current_mode == MODE_FINGER else MODE_FINGER
open_sensor()
def toggle_bias():
global bias
close_sensor() def toggle_bias():
bias = False if bias == True else True global bias
open_sensor() close_sensor()
return bias = False if bias == True else True
open_sensor()
return
def toggle_write():
global write, disp, pause_screen
pause_screen = utime.time_ms() + 1000 def toggle_write():
disp.clear(COLOR_BACKGROUND) global write, disp, pause_screen
if write > 0: pause_screen = utime.time_ms() + 1000
write_filebuffer() disp.clear(COLOR_BACKGROUND)
write = 0 if write > 0:
disp.print("Stop", posx=50, posy=20, fg=COLOR_TEXT) write_filebuffer()
disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) write = 0
else: disp.print("Stop", posx=50, posy=20, fg=COLOR_TEXT)
filebuffer = bytearray() disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT)
write = utime.time() else:
disp.print("Start", posx=45, posy=20, fg=COLOR_TEXT) filebuffer = bytearray()
disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) write = utime.time()
disp.print("Start", posx=45, posy=20, fg=COLOR_TEXT)
disp.update() disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT)
return
disp.update()
return
def draw_histogram():
global disp, history, current_mode, bias, write, pause_screen
def toggle_pause():
# skip rendering due to message beeing shown global pause_histogram, histogram_offset, history
if pause_screen == -1: if pause_histogram == True:
return pause_histogram = False
elif pause_screen > 0: history = []
t = utime.time_ms() else:
if t > pause_screen: pause_histogram = True
pause_screen = 0 histogram_offset = 0
else:
return
def draw_histogram():
disp.clear(COLOR_BACKGROUND) global disp, history, current_mode, bias, write, pause_screen, update_screen
# get max value and calc scale # skip rendering due to message beeing shown
value_max = 0 if pause_screen == -1:
for value in history: return
if abs(value) > value_max: elif pause_screen > 0:
value_max = abs(value) t = utime.time_ms()
scale = SCALE_FACTOR / (value_max if value_max > 0 else 1) if t > pause_screen:
pause_screen = 0
# draw histogram else:
old = False return
x = 0
samples = len(history) disp.clear(COLOR_BACKGROUND)
for i, value in enumerate(history):
if old == False: # offset in pause_histogram mode
old = (x, int(value * scale) + OFFSET) samples = len(history)
x += 1 s_start = samples - (histogram_offset + (ECG_RATE * 2))
continue s_end = samples - (histogram_offset + 1)
elif i > samples - WIDTH: s_draw = s_end - (WIDTH - 1)
disp.line(old[0], old[1], x, int(value * scale) + OFFSET, col=COLOR_LINE)
old = (x, int(value * scale) + OFFSET) # get max value and calc scale
x += 1 value_max = 0
for i, value in enumerate(history):
# draw text: mode/bias/write if i >= s_start and i <= s_end and abs(value) > value_max:
disp.print( value_max = abs(value)
current_mode + ("+Bias" if bias else ""), scale = SCALE_FACTOR / (value_max if value_max > 0 else 1)
posx=0,
posy=0, # draw histogram
fg=(COLOR_MODE_FINGER if current_mode == MODE_FINGER else COLOR_MODE_USB), old = False
) x = 0
for i, value in enumerate(history):
# announce writing ecg log if old == False:
if write > 0: old = value
t = utime.time() x += 1
if write > 0 and t % 2 == 0: continue
disp.print("LOG", posx=0, posy=60, fg=COLOR_WRITE_FG, bg=COLOR_WRITE_BG) elif i > s_start and i > s_draw and i < s_end:
disp.update() oldy = int(old * scale)
if oldy < -SCALE_FACTOR:
oldy = -SCALE_FACTOR
def main(): elif oldy > SCALE_FACTOR:
# show button layout oldy = SCALE_FACTOR
disp.clear(COLOR_BACKGROUND)
disp.print(" BUTTONS ", posx=0, posy=0, fg=COLOR_TEXT) disp.line(
disp.print("Finger/USB>", posx=0, posy=20, fg=COLOR_MODE_FINGER) x - 1, oldy + OFFSET_Y, x, int(value * scale) + OFFSET_Y, col=COLOR_LINE
disp.print(" Bias >", posx=0, posy=40, fg=COLOR_MODE_USB) )
disp.print("< Write Log", posx=0, posy=60, fg=COLOR_WRITE_BG) old = value
disp.update() x += 1
utime.sleep(3)
# draw text: mode/bias/write
# start ecg if pause_histogram == True:
open_sensor() disp.print(
while True: "Pause"
button_pressed = False + (
while True: " -%0.1fs" % (histogram_offset / ECG_RATE)
v = buttons.read( if histogram_offset > 0
buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT else ""
) ),
if v == 0: posx=0,
button_pressed = False posy=0,
fg=COLOR_TEXT,
if not button_pressed and v & buttons.BOTTOM_LEFT != 0: )
button_pressed = True else:
toggle_write() disp.print(
current_mode + ("+Bias" if bias else ""),
elif not button_pressed and v & buttons.BOTTOM_RIGHT != 0: posx=0,
button_pressed = True posy=0,
toggle_bias() fg=(COLOR_MODE_FINGER if current_mode == MODE_FINGER else COLOR_MODE_USB),
)
elif not button_pressed and v & buttons.TOP_RIGHT != 0:
button_pressed = True # announce writing ecg log
toggle_mode() if write > 0:
t = utime.time()
pass if write > 0 and t % 2 == 0:
disp.print("LOG", posx=0, posy=60, fg=COLOR_WRITE_FG, bg=COLOR_WRITE_BG)
if __name__ == "__main__": disp.update()
main() update_screen = 0
def main():
global pause_histogram, histogram_offset
# 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.update()
utime.sleep(3)
# start ecg
open_sensor()
while True:
button_pressed = {"BOTTOM_LEFT": 0, "BOTTOM_RIGHT": 0, "TOP_RIGHT": 0}
while True:
v = buttons.read(
buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT
)
# BUTTOM LEFT
if button_pressed["BOTTOM_LEFT"] == 0 and v & buttons.BOTTOM_LEFT != 0:
button_pressed["BOTTOM_LEFT"] = utime.time_ms()
if pause_histogram == False:
toggle_write()
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
# BUTTOM RIGHT
if button_pressed["BOTTOM_RIGHT"] == 0 and v & buttons.BOTTOM_RIGHT != 0:
button_pressed["BOTTOM_RIGHT"] = utime.time_ms()
if pause_histogram == False:
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
# 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 duration > 1000:
button_pressed["TOP_RIGHT"] = -1
toggle_pause()
# register down event
elif button_pressed["TOP_RIGHT"] == 0 and v & buttons.TOP_RIGHT != 0:
button_pressed["TOP_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
# 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
if pause_histogram == True:
toggle_pause()
else:
toggle_mode()
pass
if __name__ == "__main__":
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment