Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added firmware/images/error_laser.bmp
Binary file not shown.
Binary file added firmware/images/error_magnetic.bmp
Binary file not shown.
Binary file added firmware/images/error_movement.bmp
Binary file not shown.
80 changes: 48 additions & 32 deletions firmware/measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,40 +117,56 @@ async def take_reading(devices: hardware.HardwareBase,
disp: display.DisplayBase) -> bool:
# take a reading
try:
mag, grav, distance = await get_raw_measurement(devices, disp, True)
if cfg.calib is None:
raise NotCalibrated()
# noinspection PyTypeChecker
azimuth, inclination, _ = cfg.calib.get_angles(mag, grav)
distance += cfg.laser_cal
logger.debug(f"Distance: {distance}m")
if cfg.anomaly_strictness is not None:
try:
mag, grav, distance = await get_raw_measurement(devices, disp, True)
if cfg.calib is None:
raise NotCalibrated()
# noinspection PyTypeChecker
cfg.calib.raise_if_anomaly(mag, grav, cfg.anomaly_strictness)
except tuple(ERROR_MESSAGES.keys()) as exc:
for key in ERROR_MESSAGES.keys():
if isinstance(exc, key):
disp.show_big_info(ERROR_MESSAGES[key])
logger.info(f"Measurement error: {repr(exc)}")
if not isinstance(exc, asyncio.TimeoutError):
# don't wibble the laser if it's timed out, it'll just get more confused
devices.flash_laser(5,0.1)
devices.beep_sad()
await asyncio.sleep(0)
return False
else:
leg = Leg(azimuth, inclination, distance)
readings.store_reading(leg, cfg)
devices.bt.disto.send_data(azimuth, inclination, distance)
if readings.triple_shot():
devices.flash_laser(2,0.2)
devices.beep_happy()
azimuth, inclination, _ = cfg.calib.get_angles(mag, grav)
distance += cfg.laser_cal
logger.debug(f"Distance: {distance}m")
if cfg.anomaly_strictness is not None:
# noinspection PyTypeChecker
cfg.calib.raise_if_anomaly(mag, grav, cfg.anomaly_strictness)
except tuple(ERROR_MESSAGES.keys()) as exc:
for key in ERROR_MESSAGES.keys():
if isinstance(exc, key):
# spic17: for error messages happening often during measurement display bitmaps instead of text
# because this saves a lot of memory and thus significantly reduces
# the number of out of memory exceptions
if (key == MagneticAnomalyError) or (key == DipAnomalyError):
disp.show_bitmap_info('error_magnetic')
elif (key == GravityAnomalyError):
disp.show_bitmap_info('error_movement')
elif (key == LaserError):
disp.show_bitmap_info('error_laser')
else:
# all other error messages
disp.show_big_info(ERROR_MESSAGES[key])
logger.info(f"Measurement error: {repr(exc)}")
if not isinstance(exc, asyncio.TimeoutError):
# don't wibble the laser if it's timed out, it'll just get more confused
devices.flash_laser(5,0.1)
devices.beep_sad()
await asyncio.sleep(0)
return False
else:
devices.beep_bip()
await asyncio.sleep(0)
return True


leg = Leg(azimuth, inclination, distance)
readings.store_reading(leg, cfg)
devices.bt.disto.send_data(azimuth, inclination, distance)
if readings.triple_shot():
devices.flash_laser(2,0.2)
devices.beep_happy()
else:
devices.beep_bip()
await asyncio.sleep(0)
return True
except MemoryError:
# spic17: better not do anything not strictly neccessary in these delicate moments after a memory error
# TODO: do something more drastic here after maybe 3 occurences (reboot?)
# because the device may not be able to recover otherwise?
return False

async def take_multiple_readings(devices, disp, fname, prelude, reminder):
devices.laser_enable(True)
disp.show_info(prelude)
Expand Down
52 changes: 39 additions & 13 deletions firmware/versions/display128x64.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,26 @@ def __init__(self, oled: BusDisplay, config: Config):

@staticmethod
def create_big_text_group(big_text: Sequence[str], index_txt):
measurement_group = displayio.Group()
azimuth = label.Label(font_20, text=big_text[0], color=0xffffff, x=1, y=9)
inclination = label.Label(font_20, text=big_text[1], color=0xffffff, x=1, y=31)
distance = label.Label(font_20, text=big_text[2], color=0xffffff, x=1, y=53)
reading_index = label.Label(terminalio.FONT, text=index_txt, color=0xffffff)
reading_index.anchored_position = (127, 32)
reading_index.anchor_point = (1.0, 0.5)
measurement_group.append(azimuth)
measurement_group.append(inclination)
measurement_group.append(distance)
measurement_group.append(reading_index)
# spic17: watchout for memory exceptions here.
try:
measurement_group = displayio.Group()
azimuth = label.Label(font_20, text=big_text[0], color=0xffffff, x=1, y=9)
inclination = label.Label(font_20, text=big_text[1], color=0xffffff, x=1, y=31)
distance = label.Label(font_20, text=big_text[2], color=0xffffff, x=1, y=53)
reading_index = label.Label(terminalio.FONT, text=index_txt, color=0xffffff)
reading_index.anchored_position = (127, 32)
reading_index.anchor_point = (1.0, 0.5)
measurement_group.append(azimuth)
measurement_group.append(inclination)
measurement_group.append(distance)
measurement_group.append(reading_index)
except MemoryError:
# Out of memory error. Catch and display nothing. Oftentimes we will recover afterwards
# (this seems purely a matter of garbage collection mechanisms, which seem not very
# predictable in this embedded system)
# Maybe use 'BitmapLabel' for optimization?
# Maybe call check_mem to try invoking garbage collection?
measurement_group = displayio.Group()
return measurement_group

def _set_group_with_icons(self, group):
Expand Down Expand Up @@ -153,8 +162,25 @@ def show_info(self, text, clean=False):

def show_big_info(self, text):
group = self.create_big_text_group(text.splitlines(), "")
self.show_group(group)

logger.debug("show_big_info tvo")
try:
self.show_group(group)
except MemoryError:
# spic17: do nothing when memory is spent. We may still recover when gc occurs.
pass

def show_bitmap_info(self, bitmap_name):
group = displayio.Group()
info_bmp = bitmaps[bitmap_name]
info_tile = displayio.TileGrid(info_bmp, pixel_shader=palette, x=0, y=0)
group.append(info_tile)
try:
self._set_group_with_icons(group)
self.refresh()
except MemoryError:
# spic17: do nothing. Doing anything here may lead to an outer memory error.
# hopefully, we recover - otherwise we are off no worse than when crashing directly.
pass
def show_group(self, group: Optional[displayio.Group]):
self.oled.root_group = group
self.refresh()
Expand Down