Skip to content
Merged
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
334 changes: 334 additions & 0 deletions buildhat/colordistance.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ def __init__(self, port):
self.mode(6)
self.avg_reads = 4
self._old_color = None
self._ir_channel = 0x0
self._ir_address = 0x0
self._ir_toggle = 0x0

def segment_color(self, r, g, b):
"""Return the color name from HSV
Expand Down Expand Up @@ -197,6 +200,337 @@ def wait_for_new_color(self):
self.callback(None)
return self._old_color

@property
def ir_channel(self):
"""Get the IR channel for message transmission"""
return self._ir_channel

@ir_channel.setter
def ir_channel(self, channel=1):
"""
Set the IR channel for RC Tx

:param channel: 1-4 indicating the selected IR channel on the reciever
"""
check_chan = channel
if check_chan > 4:
check_chan = 4
elif check_chan < 1:
check_chan = 1
# Internally: 0-3
self._ir_channel = int(check_chan) - 1

@property
def ir_address(self):
"""IR Address space of 0x0 for default PoweredUp or 0x1 for extra space"""
return self._ir_address

def toggle_ir_toggle(self):
"""Toggle the IR toggle bit"""
# IYKYK, because the RC documents are not clear
if self._ir_toggle:
self._ir_toggle = 0x0
else:
self._ir_toggle = 0x1
return self._ir_toggle

def send_ir_sop(self, port, mode):
"""
Send an IR message via Power Functions RC Protocol in Single Output PWM mode

PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm

Port B is blue

Valid values for mode are:
0x0: Float output
0x1: Forward/Clockwise at speed 1
0x2: Forward/Clockwise at speed 2
0x3: Forward/Clockwise at speed 3
0x4: Forward/Clockwise at speed 4
0x5: Forward/Clockwise at speed 5
0x6: Forward/Clockwise at speed 6
0x7: Forward/Clockwise at speed 7
0x8: Brake (then float v1.20)
0x9: Backwards/Counterclockwise at speed 7
0xA: Backwards/Counterclockwise at speed 6
0xB: Backwards/Counterclockwise at speed 5
0xC: Backwards/Counterclockwise at speed 4
0xD: Backwards/Counterclockwise at speed 3
0xE: Backwards/Counterclockwise at speed 2
0xF: Backwards/Counterclockwise at speed 1

:param port: 'A' or 'B'
:param mode: 0-15 indicating the port's mode to set
"""
escape_modeselect = 0x0
escape = escape_modeselect

ir_mode_single_output = 0x4
ir_mode = ir_mode_single_output

so_mode_pwm = 0x0
so_mode = so_mode_pwm

output_port_a = 0x0
output_port_b = 0x1

output_port = None
if port == 'A' or port == 'a':
output_port = output_port_a
elif port == 'B' or port == 'b':
output_port = output_port_b
else:
return False

ir_mode = ir_mode | (so_mode << 1) | output_port

nibble1 = (self._ir_toggle << 3) | (escape << 2) | self._ir_channel
nibble2 = (self._ir_address << 3) | ir_mode

# Mode range checked here
return self._send_ir_nibbles(nibble1, nibble2, mode)

def send_ir_socstid(self, port, mode):
"""
Send an IR message via Power Functions RC Protocol in Single Output Clear/Set/Toggle/Increment/Decrement mode

PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm

Valid values for mode are:
0x0: Toggle full Clockwise/Forward (Stop to Clockwise, Clockwise to Stop, Counterclockwise to Clockwise)
0x1: Toggle direction
0x2: Increment numerical PWM
0x3: Decrement numerical PWM
0x4: Increment PWM
0x5: Decrement PWM
0x6: Full Clockwise/Forward
0x7: Full Counterclockwise/Backward
0x8: Toggle full (defaults to Forward, first)
0x9: Clear C1 (C1 to High)
0xA: Set C1 (C1 to Low)
0xB: Toggle C1
0xC: Clear C2 (C2 to High)
0xD: Set C2 (C2 to Low)
0xE: Toggle C2
0xF: Toggle full Counterclockwise/Backward (Stop to Clockwise, Counterclockwise to Stop, Clockwise to Counterclockwise)

:param port: 'A' or 'B'
:param mode: 0-15 indicating the port's mode to set
"""
escape_modeselect = 0x0
escape = escape_modeselect

ir_mode_single_output = 0x4
ir_mode = ir_mode_single_output

so_mode_cstid = 0x1
so_mode = so_mode_cstid

output_port_a = 0x0
output_port_b = 0x1

output_port = None
if port == 'A' or port == 'a':
output_port = output_port_a
elif port == 'B' or port == 'b':
output_port = output_port_b
else:
return False

ir_mode = ir_mode | (so_mode << 1) | output_port

nibble1 = (self._ir_toggle << 3) | (escape << 2) | self._ir_channel
nibble2 = (self._ir_address << 3) | ir_mode

# Mode range checked here
return self._send_ir_nibbles(nibble1, nibble2, mode)

def send_ir_combo_pwm(self, port_b_mode, port_a_mode):
"""
Send an IR message via Power Functions RC Protocol in Combo PWM mode

PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm

Valid values for the modes are:
0x0 Float
0x1 PWM Forward step 1
0x2 PWM Forward step 2
0x3 PWM Forward step 3
0x4 PWM Forward step 4
0x5 PWM Forward step 5
0x6 PWM Forward step 6
0x7 PWM Forward step 7
0x8 Brake (then float v1.20)
0x9 PWM Backward step 7
0xA PWM Backward step 6
0xB PWM Backward step 5
0xC PWM Backward step 4
0xD PWM Backward step 3
0xE PWM Backward step 2
0xF PWM Backward step 1

:param port_b_mode: 0-15 indicating the command to send to port B
:param port_a_mode: 0-15 indicating the command to send to port A
"""
escape_combo_pwm = 0x1
escape = escape_combo_pwm

nibble1 = (self._ir_toggle << 3) | (escape << 2) | self._ir_channel

# Port modes are range checked here
return self._send_ir_nibbles(nibble1, port_b_mode, port_a_mode)

def send_ir_combo_direct(self, port_b_output, port_a_output):
"""
Send an IR message via Power Functions RC Protocol in Combo Direct mode

PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm

Valid values for the output variables are:
0x0: Float output
0x1: Clockwise/Forward
0x2: Counterclockwise/Backwards
0x3: Brake then float

:param port_b_output: 0-3 indicating the output to send to port B
:param port_a_output: 0-3 indicating the output to send to port A
"""
escape_modeselect = 0x0
escape = escape_modeselect

ir_mode_combo_direct = 0x1
ir_mode = ir_mode_combo_direct

nibble1 = (self._ir_toggle << 3) | (escape << 2) | self._ir_channel
nibble2 = (self._ir_address << 3) | ir_mode

if port_b_output > 0x3 or port_a_output > 0x3:
return False
if port_b_output < 0x0 or port_a_output < 0x0:
return False

nibble3 = (port_b_output << 2) | port_a_output

return self._send_ir_nibbles(nibble1, nibble2, nibble3)

def send_ir_extended(self, mode):
"""
Send an IR message via Power Functions RC Protocol in Extended mode

PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm

Valid values for the mode are:
0x0: Brake Port A (timeout)
0x1: Increment Speed on Port A
0x2: Decrement Speed on Port A

0x4: Toggle Forward/Clockwise/Float on Port B

0x6: Toggle Address bit
0x7: Align toggle bit

:param mode: 0-2,4,6-7
"""
escape_modeselect = 0x0
escape = escape_modeselect

ir_mode_extended = 0x0
ir_mode = ir_mode_extended

nibble1 = (self._ir_toggle << 3) | (escape << 2) | self._ir_channel
nibble2 = (self._ir_address << 3) | ir_mode

if mode < 0x0 or mode == 0x3 or mode == 0x5 or mode > 0x7:
return False

return self._send_ir_nibbles(nibble1, nibble2, mode)

def send_ir_single_pin(self, port, pin, mode, timeout):
"""
Send an IR message via Power Functions RC Protocol in Single Pin mode

PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm

Valid values for the mode are:
0x0: No-op
0x1: Clear
0x2: Set
0x3: Toggle

Note: The unlabeled IR receiver (vs the one labeled V2) has a "firmware bug in Single Pin mode"
https://www.philohome.com/pfrec/pfrec.htm

:param port: 'A' or 'B'
:param pin: 1 or 2
:param mode: 0-3 indicating the pin's mode to set
:param timeout: True or False
"""
escape_mode = 0x0
escape = escape_mode

ir_mode_single_continuous = 0x2
ir_mode_single_timeout = 0x3
ir_mode = None
if timeout:
ir_mode = ir_mode_single_timeout
else:
ir_mode = ir_mode_single_continuous

output_port_a = 0x0
output_port_b = 0x1

output_port = None
if port == 'A' or port == 'a':
output_port = output_port_a
elif port == 'B' or port == 'b':
output_port = output_port_b
else:
return False

if pin != 1 and pin != 2:
return False
pin_value = pin - 1

if mode > 0x3 or mode < 0x0:
return False

nibble1 = (self._ir_toggle << 3) | (escape << 2) | self._ir_channel
nibble2 = (self._ir_address << 3) | ir_mode
nibble3 = (output_port << 3) | (pin_value << 3) | mode

return self._send_ir_nibbles(nibble1, nibble2, nibble3)

def _send_ir_nibbles(self, nibble1, nibble2, nibble3):

# M7 IR Tx SI = N/A
# format count=1 type=1 chars=5 dp=0
# RAW: 00000000 0000FFFF PCT: 00000000 00000064 SI: 00000000 0000FFFF

mode = 7
self.mode(mode)

# The upper bits of data[2] are ignored
if nibble1 > 0xF or nibble2 > 0xF or nibble3 > 0xF:
return False
if nibble1 < 0x0 or nibble2 < 0x0 or nibble3 < 0x0:
return False

byte_two = (nibble2 << 4) | nibble3

data = bytearray(3)
data[0] = (0xc << 4) | mode
data[1] = byte_two
data[2] = nibble1

# print(" ".join('{:04b}'.format(nibble1)))
# print(" ".join('{:04b}'.format(nibble2)))
# print(" ".join('{:04b}'.format(nibble3)))
# print(" ".join('{:08b}'.format(n) for n in data))

self._write1(data)
return True

def on(self):
"""Turn on the sensor and LED"""
self.reverse()