SEm/escapeLab/safe

From FSI
Jump to: navigation, search

Contents

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/
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()
Personal tools
Namespaces
Variants
Actions
Navigation
Modules / Projects
Browse
Toolbox