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/ import radio 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 radio_channel = 6 radio_address = 0xFC000000 software_version = '2.0' # ----------------------------------------------------------------------------- # Functions # def update_position(position, encoder_previous_value): # read encoder value encoder_value = \ 2*encoder_pin_high.read_digital() + \ encoder_pin_low.read_digital() # 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") def add_to_history(value, history): # 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") radio.on() radio.config(channel=radio_channel, address=radio_address) while True: # sleep to next sampling moment time_to_next_action = timer_period - (running_time() % timer_period) sleep(time_to_next_action) # read encoder (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) new_message = radio.receive() if new_message == 'Sesame': open_safe()