# SEm/escapeLab/safe

(Difference between revisions)

# Opening the safe

The safe is opened by turning an encoder to the first value, then clicking on the button, and so on, until the 4 values have been reached. Once the final position has been reached, the rotating lever allows to open the safe.

This can be tested with the sequence [1, 2, 3, 4] which doesn't open the safe but displays a smiley.

# Verifying the codes

The numbers of the test sequence can be verified by their Hamming code. Calculating the Hamming code is similar to a vector by matrix multiplication, where the product is implemented by an AND function and the sum by a XOR.

$\begin{bmatrix} h_3 & h_2 & h_1 & h_0 \end{bmatrix} = \begin{bmatrix} d_7 & d_6 & d_5 & d_4 & d_3 & d_2 & d_1 & d_0 \end{bmatrix} \cdot \begin{bmatrix} 0 & 0 & 1 & 1 \\ 0 & 1 & 0 & 1 \\ 0 & 1 & 1 & 0 \\ 0 & 1 & 1 & 1 \\ 1 & 0 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 0 \end{bmatrix}$

As an example, data value 3 has Hamming code 7:

$\begin{bmatrix} 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \end{bmatrix} \cdot \begin{bmatrix} 0 & 0 & 1 & 1 \\ 0 & 1 & 0 & 1 \\ 0 & 1 & 1 & 0 \\ 0 & 1 & 1 & 1 \\ 1 & 0 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 0 \end{bmatrix} = \begin{bmatrix} 0 & 1 & 1 & 1 \end{bmatrix}$

The tasks have the follwing Hamming codes:

• task 1 : 7
• task 2 : 5
• task 3 : 1
• task 4 : 2

# Testing the opening of the safe

The following code is programmed in the safe's microcontroller, except for the opening_sequence. It allows to find out how the unlocking system works.

# http://microbit-micropython.readthedocs.io/
from microbit import *

# -----------------------------------------------------------------------------
# Constants
#
opening_sequence = [4, 3, 2, 1]
test_sequence = [1, 2, 3, 4]
positon_min = 0
positon_max = 9

safe_open_button = button_a
encoder_button = button_b
encoder_pin_high = pin8
encoder_pin_low = pin12
encoder_up = [0, 2, 3, 1]
open_safe_pin = pin16

timer_period = 10

indent = '  '
count_to_display_units = 100
encoder_button_pressed_images = [
Image("00000:00000:00900:00000:00000"),
Image("00000:00900:09590:00900:00000"),
Image("00900:09590:95559:09590:00900"),
Image("09590:95559:55555:95559:09590"),
Image("95559:55555:55555:55555:95559")
]
encoder_button_pressed_display_interval = 200
empty_display = Image("00000:00000:00000:00000:00000")
sequence_display_scroll_time = 1000
sequence_item_display_interval = 1000
test_sequence_found_image = Image.HAPPY
test_sequence_found_display_interval = 1000
safe_open_sequence_found_image = Image.FABULOUS
open_safe_sampling_period = 100

software_version = '2.0'

# -----------------------------------------------------------------------------
# Functions
#
def update_position(position, encoder_previous_value):
#                                                        read encoder value
encoder_value = \
#                                                           update position
has_changed = False
if encoder_value == encoder_up[2]:
if encoder_previous_value == encoder_up[1]:
if position < positon_max:
position = position + 1
else:
position = positon_min
has_changed = True
if encoder_previous_value == encoder_up[-1]:
if position > positon_min:
position = position - 1
else:
position = positon_max
has_changed = True

return(position, encoder_value, has_changed)

def display_scroll(position):
if position >= 10:
display.scroll(str(position), wait=False)
else:
display.show(str(position % 10), wait=False)

def display_units(position):
display.show(str(position % 10), wait=False)

def print_sequence(sequence):
uart.write(indent + 'Accumulated sequence:')
for index in range(len(sequence)):
uart.write(' ' + str(sequence[index]))
uart.write("\n\r")

#                                                            update history
new_history = history
if value != history[-1]:
new_history = history[1:] + [value]
#                                             print sequence on serial port
print_sequence(new_history)
#                                                         display animation
#for index in range(len(encoder_button_pressed_images)):
#    display.show(encoder_button_pressed_images[index])
#    sleep(encoder_button_pressed_display_interval)
display.show(
encoder_button_pressed_images,
delay=encoder_button_pressed_display_interval
)
#                                                     show last digit again
display_units(value)

return(new_history)

def display_sequence(sequence, position):
#                                             print sequence on serial port
print_sequence(sequence)
#                                                   display sequence values
for index in range(len(sequence)):
display.clear()
sleep(sequence_item_display_interval)
if sequence[index] >= 10:
display_scroll(sequence[index])
sleep(sequence_display_scroll_time)
display_units(sequence[index])
sleep(sequence_item_display_interval)
display.clear()
sleep(sequence_item_display_interval)
#                                            show last position digit again
display_units(position)

def display_test_sequence_found(sequence, position):
#                                             print sequence on serial port
print_sequence(sequence)
#                                                         display animation
display.clear()
sleep(test_sequence_found_display_interval)
display.show(test_sequence_found_image)
sleep(test_sequence_found_display_interval)
#                                            show last position digit again
display_units(position)

def open_safe():
display.show(safe_open_sequence_found_image)
open_safe_pin.write_digital(1)
while safe_open_button.is_pressed():
sleep(open_safe_sampling_period)
open_safe_pin.write_digital(0)
display.clear()

# -----------------------------------------------------------------------------
# Main loop
#
encoder_pin_low.set_pull(1)
encoder_pin_high.set_pull(1)
encoder_value = 1
encoder_position = 0
display_units(encoder_position)
activity_counter = 0
history = [0, 0, 0, 0]
uart.init(baudrate=115200, bits=8, parity=None, stop=2, tx=pin1, rx=pin2)
uart.write("\n\r")
uart.write('Safe controller V ' + software_version + "\n\r")

while True:
#                                             sleep to next sampling moment
time_to_next_action = timer_period - (running_time() % timer_period)
sleep(time_to_next_action)
(encoder_position, encoder_value, has_changed) = \
update_position(encoder_position, encoder_value)
#                                                            update display
if has_changed:
display_scroll(encoder_position)
activity_counter = 1
if activity_counter > 0:
if activity_counter < count_to_display_units:
activity_counter = activity_counter + 1
else:
display_units(encoder_position)
activity_counter = 0
#                                                      check encoder button
if encoder_button.is_pressed():
history = add_to_history(encoder_position, history)
#                                               check history and open safe
if safe_open_button.is_pressed():
if history == opening_sequence:
uart.write("Safe opening sequence found.\n\r")
open_safe()
elif history == test_sequence:
uart.write("Test sequence found.\n\r")
display_test_sequence_found(history, encoder_position)
else:
uart.write("Wrong sequence!\n\r")
display_sequence(history, encoder_position)
open_safe()