@@ -25,6 +25,9 @@ def __init__(self, port):
2525 self .mode (6 )
2626 self .avg_reads = 4
2727 self ._old_color = None
28+ self ._ir_channel = 0x0
29+ self ._ir_address = 0x0
30+ self ._ir_toggle = 0x0
2831
2932 def segment_color (self , r , g , b ):
3033 """Return the color name from HSV
@@ -197,6 +200,337 @@ def wait_for_new_color(self):
197200 self .callback (None )
198201 return self ._old_color
199202
203+ @property
204+ def ir_channel (self ):
205+ return self ._ir_channel
206+
207+ @ir_channel .setter
208+ def ir_channel (self , channel = 1 ):
209+ """
210+ Set the IR channel for RC Tx
211+
212+ :param channel: 1-4 indicating the selected IR channel on the reciever
213+ """
214+ check_chan = channel
215+ if check_chan > 4 :
216+ check_chan = 4
217+ elif check_chan < 1 :
218+ check_chan = 1
219+ # Internally: 0-3
220+ self ._ir_channel = int (check_chan )- 1
221+
222+ @property
223+ def ir_address (self ):
224+ """
225+ IR Address space of 0x0 for default PoweredUp or 0x1 for extra space
226+ """
227+ return self ._ir_address
228+
229+ def toggle_ir_toggle (self ):
230+ """
231+ Toggle the IR toggle bit
232+
233+ """
234+ # IYKYK, because the RC documents are not clear
235+ if self ._ir_toggle :
236+ self ._ir_toggle = 0x0
237+ else :
238+ self ._ir_toggle = 0x1
239+ return self ._ir_toggle
240+
241+ def send_ir_sop (self , port , mode ):
242+ """
243+ Send an IR message via Power Functions RC Protocol in Single Output PWM mode
244+ https://www.philohome.com/pf/pf.htm
245+
246+ Port B is blue
247+
248+ Valid values for mode are:
249+ 0x0: Float output
250+ 0x1: Forward/Clockwise at speed 1
251+ 0x2: Forward/Clockwise at speed 2
252+ 0x3: Forward/Clockwise at speed 3
253+ 0x4: Forward/Clockwise at speed 4
254+ 0x5: Forward/Clockwise at speed 5
255+ 0x6: Forward/Clockwise at speed 6
256+ 0x7: Forward/Clockwise at speed 7
257+ 0x8: Brake (then float v1.20)
258+ 0x9: Backwards/Counterclockwise at speed 7
259+ 0xA: Backwards/Counterclockwise at speed 6
260+ 0xB: Backwards/Counterclockwise at speed 5
261+ 0xC: Backwards/Counterclockwise at speed 4
262+ 0xD: Backwards/Counterclockwise at speed 3
263+ 0xE: Backwards/Counterclockwise at speed 2
264+ 0xF: Backwards/Counterclockwise at speed 1
265+
266+ :param port: 'A' or 'B'
267+ :param mode: 0-15 indicating the port's mode to set
268+ """
269+ escape_modeselect = 0x0
270+ escape = escape_modeselect
271+
272+ ir_mode_single_output = 0x4
273+ ir_mode = ir_mode_single_output
274+
275+ so_mode_pwm = 0x0
276+ so_mode = so_mode_pwm
277+
278+ output_port_a = 0x0
279+ output_port_b = 0x1
280+
281+ output_port = None
282+ if port == 'A' or port == 'a' :
283+ output_port = output_port_a
284+ elif port == 'B' or port == 'b' :
285+ output_port = output_port_b
286+ else :
287+ return False
288+
289+ ir_mode = ir_mode | (so_mode << 1 ) | output_port
290+
291+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
292+ nibble2 = (self ._ir_address << 3 ) | ir_mode
293+
294+ # Mode range checked here
295+ return self ._send_ir_nibbles (nibble1 , nibble2 , mode )
296+
297+ def send_ir_socstid (self , port , mode ):
298+ """
299+ Send an IR message via Power Functions RC Protocol in Single Output Clear/Set/Toggle/Increment/Decrement mode
300+ https://www.philohome.com/pf/pf.htm
301+
302+ Valid values for mode are:
303+ 0x0: Toggle full Clockwise/Forward (Stop to Clockwise, Clockwise to Stop, Counterclockwise to Clockwise)
304+ 0x1: Toggle direction
305+ 0x2: Increment numerical PWM
306+ 0x3: Decrement numerical PWM
307+ 0x4: Increment PWM
308+ 0x5: Decrement PWM
309+ 0x6: Full Clockwise/Forward
310+ 0x7: Full Counterclockwise/Backward
311+ 0x8: Toggle full (defaults to Forward, first)
312+ 0x9: Clear C1 (C1 to High)
313+ 0xA: Set C1 (C1 to Low)
314+ 0xB: Toggle C1
315+ 0xC: Clear C2 (C2 to High)
316+ 0xD: Set C2 (C2 to Low)
317+ 0xE: Toggle C2
318+ 0xF: Toggle full Counterclockwise/Backward (Stop to Clockwise, Counterclockwise to Stop, Clockwise to Counterclockwise)
319+
320+ :param port: 'A' or 'B'
321+ :param mode: 0-15 indicating the port's mode to set
322+ """
323+
324+ escape_modeselect = 0x0
325+ escape = escape_modeselect
326+
327+ ir_mode_single_output = 0x4
328+ ir_mode = ir_mode_single_output
329+
330+ so_mode_cstid = 0x1
331+ so_mode = so_mode_cstid
332+
333+ output_port_a = 0x0
334+ output_port_b = 0x1
335+
336+ output_port = None
337+ if port == 'A' or port == 'a' :
338+ output_port = output_port_a
339+ elif port == 'B' or port == 'b' :
340+ output_port = output_port_b
341+ else :
342+ return False
343+
344+ ir_mode = ir_mode | (so_mode << 1 ) | output_port
345+
346+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
347+ nibble2 = (self ._ir_address << 3 ) | ir_mode
348+
349+ # Mode range checked here
350+ return self ._send_ir_nibbles (nibble1 , nibble2 , mode )
351+
352+ def send_ir_combo_pwm (self , port_b_mode , port_a_mode ):
353+ """
354+ Send an IR message via Power Functions RC Protocol in Combo PWM mode
355+ https://www.philohome.com/pf/pf.htm
356+
357+ Valid values for the modes are:
358+ 0x0 Float
359+ 0x1 PWM Forward step 1
360+ 0x2 PWM Forward step 2
361+ 0x3 PWM Forward step 3
362+ 0x4 PWM Forward step 4
363+ 0x5 PWM Forward step 5
364+ 0x6 PWM Forward step 6
365+ 0x7 PWM Forward step 7
366+ 0x8 Brake (then float v1.20)
367+ 0x9 PWM Backward step 7
368+ 0xA PWM Backward step 6
369+ 0xB PWM Backward step 5
370+ 0xC PWM Backward step 4
371+ 0xD PWM Backward step 3
372+ 0xE PWM Backward step 2
373+ 0xF PWM Backward step 1
374+
375+ :param port_b_mode: 0-15 indicating the command to send to port B
376+ :param port_a_mode: 0-15 indicating the command to send to port A
377+ """
378+
379+ escape_combo_pwm = 0x1
380+ escape = escape_combo_pwm
381+
382+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
383+
384+ # Port modes are range checked here
385+ return self ._send_ir_nibbles (nibble1 , port_b_mode , port_a_mode )
386+
387+ def send_ir_combo_direct (self , port_b_output , port_a_output ):
388+ """
389+ Send an IR message via Power Functions RC Protocol in Combo Direct mode
390+ https://www.philohome.com/pf/pf.htm
391+
392+ Valid values for the output variables are:
393+ 0x0: Float output
394+ 0x1: Clockwise/Forward
395+ 0x2: Counterclockwise/Backwards
396+ 0x3: Brake then float
397+
398+ :param port_b_output: 0-3 indicating the output to send to port B
399+ :param port_a_output: 0-3 indicating the output to send to port A
400+ """
401+ escape_modeselect = 0x0
402+ escape = escape_modeselect
403+
404+ ir_mode_combo_direct = 0x1
405+ ir_mode = ir_mode_combo_direct
406+
407+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
408+ nibble2 = (self ._ir_address << 3 ) | ir_mode
409+
410+ if port_b_output > 0x3 or port_a_output > 0x3 :
411+ return False
412+ if port_b_output < 0x0 or port_a_output < 0x0 :
413+ return False
414+
415+ nibble3 = (port_b_output << 2 ) | port_a_output
416+
417+ return self ._send_ir_nibbles (nibble1 , nibble2 , nibble3 )
418+
419+ def send_ir_extended (self , mode ):
420+ """
421+ Send an IR message via Power Functions RC Protocol in Extended mode
422+ https://www.philohome.com/pf/pf.htm
423+
424+ Valid values for the mode are:
425+ 0x0: Brake Port A (timeout)
426+ 0x1: Increment Speed on Port A
427+ 0x2: Decrement Speed on Port A
428+
429+ 0x4: Toggle Forward/Clockwise/Float on Port B
430+
431+ 0x6: Toggle Address bit
432+ 0x7: Align toggle bit
433+
434+ :param mode: 0-2,4,6-7
435+ """
436+ escape_modeselect = 0x0
437+ escape = escape_modeselect
438+
439+ ir_mode_extended = 0x0
440+ ir_mode = ir_mode_extended
441+
442+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
443+ nibble2 = (self ._ir_address << 3 ) | ir_mode
444+
445+ if mode < 0x0 or mode == 0x3 or mode == 0x5 or mode > 0x7 :
446+ return False
447+
448+ return self ._send_ir_nibbles (nibble1 , nibble2 , mode )
449+
450+ def send_ir_single_pin (self , port , pin , mode , timeout ):
451+ """
452+ Send an IR message via Power Functions RC Protocol in Single Pin mode
453+ https://www.philohome.com/pf/pf.htm
454+
455+ Valid values for the mode are:
456+ 0x0: No-op
457+ 0x1: Clear
458+ 0x2: Set
459+ 0x3: Toggle
460+
461+ Note: The unlabeled IR receiver (vs the one labeled V2) has a "firmware bug in Single Pin mode"
462+ https://www.philohome.com/pfrec/pfrec.htm
463+
464+ :param port: 'A' or 'B'
465+ :param pin: 1 or 2
466+ :param mode: 0-3 indicating the pin's mode to set
467+ :param timeout: True or False
468+ """
469+ escape_mode = 0x0
470+ escape = escape_mode
471+
472+ ir_mode_single_continuous = 0x2
473+ ir_mode_single_timeout = 0x3
474+ ir_mode = None
475+ if timeout :
476+ ir_mode = ir_mode_single_timeout
477+ else :
478+ ir_mode = ir_mode_single_continuous
479+
480+ output_port_a = 0x0
481+ output_port_b = 0x1
482+
483+ output_port = None
484+ if port == 'A' or port == 'a' :
485+ output_port = output_port_a
486+ elif port == 'B' or port == 'b' :
487+ output_port = output_port_b
488+ else :
489+ return False
490+
491+ if pin != 1 and pin != 2 :
492+ return False
493+ pin_value = pin - 1
494+
495+ if mode > 0x3 or mode < 0x0 :
496+ return False
497+
498+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
499+ nibble2 = (self ._ir_address << 3 ) | ir_mode
500+ nibble3 = (output_port << 3 ) | (pin_value << 3 ) | mode
501+
502+ return self ._send_ir_nibbles (nibble1 , nibble2 , mode )
503+
504+ def _send_ir_nibbles (self , nibble1 , nibble2 , nibble3 ):
505+
506+ # M7 IR Tx SI = N/A
507+ # format count=1 type=1 chars=5 dp=0
508+ # RAW: 00000000 0000FFFF PCT: 00000000 00000064 SI: 00000000 0000FFFF
509+
510+ mode = 7
511+ self .mode (mode )
512+
513+ # The upper bits of data[2] are ignored
514+ if nibble1 > 0xF or nibble2 > 0xF or nibble3 > 0xF :
515+ return False
516+ if nibble1 < 0x0 or nibble2 < 0x0 or nibble3 < 0x0 :
517+ return False
518+
519+ byte_two = (nibble2 << 4 ) | nibble3
520+
521+ data = bytearray (3 )
522+ data [0 ] = (0xc << 4 ) | mode
523+ data [1 ] = byte_two
524+ data [2 ] = nibble1
525+
526+ # print(" ".join('{:04b}'.format(nibble1)))
527+ # print(" ".join('{:04b}'.format(nibble2)))
528+ # print(" ".join('{:04b}'.format(nibble3)))
529+ # print(" ".join('{:08b}'.format(n) for n in data))
530+
531+ self ._write1 (data )
532+ return True
533+
200534 def on (self ):
201535 """Turn on the sensor and LED"""
202536 self .reverse ()
0 commit comments