SEm/escapeLab/safe
|
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.
As an example, data value 3 has Hamming code 7:
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 = [0, 0, 0, 0] test_sequence = [12, 4, 15, 8] positon_min = 0 positon_max = 99 safe_open_button = button_a encoder_button = button_b encoder_pin_high = pin8 encoder_pin_low = pin12 open_safe_pin = pin16 rotating_right = True rotating_left = not rotating_right count_to_display_units = 200 sequence_item_display_interval = 1000 test_sequence_found_image = Image.HAPPY safe_open_sequence_found_image = Image.FABULOUS open_safe_duration = 2000 # ----------------------------------------------------------------------------- # Functions # def get_encoder_value(): encoder_value = \ 2*encoder_pin_high.read_digital() + \ encoder_pin_low.read_digital() return(encoder_value) def update_position(position, encoder_previous_value, encoder_value): encoder_up = [1, 3, 0, 2] if encoder_value == encoder_up[encoder_previous_value]: position = position + 1 else: position = position - 1 if position < positon_min: position = positon_max if position > positon_max: position = positon_min return(position) def display_binary(position): no_intensity = '0' max_intensity = '9' bits_per_line = 4 # prepare bits 3:0 hex_line_0 = "" for index in range(bits_per_line): if position % 2 > 0: hex_line_0 = max_intensity + hex_line_0 else: hex_line_0 = no_intensity + hex_line_0 position = int(position/2) hex_line_0 = '0' + hex_line_0 # prepare bits 7:4 hex_line_1 = "" for index in range(bits_per_line): if position % 2 > 0: hex_line_1 = max_intensity + hex_line_1 else: hex_line_1 = no_intensity + hex_line_1 position = int(position/2) hex_line_1 = '0' + hex_line_1 # display image display.show(Image( "00000:" + hex_line_1 + ":00000:" + hex_line_0 + ":00000" )) def display_tens(position): if position > 9: display.show(str(int(position/10)), wait=False) else: display.show(str(position % 10), wait=False) def display_units(position): display.show(str(position % 10), wait=False) def display_sequence(sequence): for index in range(len(sequence)): if sequence[index] > 9: display.scroll(str(int(sequence[index]/10))) display_units(sequence[index]) sleep(sequence_item_display_interval) def add_to_history(value, history): new_history = history[1:] + [value] return(new_history) def open_safe(): open_safe_pin.write_digital(1) sleep(open_safe_duration) open_safe_pin.write_digital(0) # ----------------------------------------------------------------------------- # Main loop # encoder_value = get_encoder_value() previous_encoder_value = encoder_value encoder_position = 0 previous_encoder_position = encoder_position display_units(encoder_position) activity_counter = 0 history = [0, 0, 0, 0] rotating_direction = rotating_right previous_rotating_direction = rotating_direction while True: # read encoder encoder_value = get_encoder_value() # update position if previous_encoder_value != encoder_value: encoder_position = update_position( encoder_position, previous_encoder_value, encoder_value ) if encoder_position > previous_encoder_position: rotating_direction = rotating_right else: rotating_direction = rotating_left if rotating_direction != previous_rotating_direction: history = add_to_history(previous_encoder_position, history) display_binary(encoder_position) previous_encoder_value = encoder_value previous_encoder_position = encoder_position previous_rotating_direction = rotating_direction activity_counter = 0 # display history if encoder_button.is_pressed(): display_sequence(history) # check history and open safe if safe_open_button.is_pressed(): if add_to_history(encoder_position, history) == opening_sequence: display.show(safe_open_sequence_found_image) open_safe() elif add_to_history(encoder_position, history) == test_sequence: display.show(test_sequence_found_image) else: display_sequence(test_sequence)