@@ -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+ """Get the IR channel for message transmission"""
206+ return self ._ir_channel
207+
208+ @ir_channel .setter
209+ def ir_channel (self , channel = 1 ):
210+ """
211+ Set the IR channel for RC Tx
212+
213+ :param channel: 1-4 indicating the selected IR channel on the reciever
214+ """
215+ check_chan = channel
216+ if check_chan > 4 :
217+ check_chan = 4
218+ elif check_chan < 1 :
219+ check_chan = 1
220+ # Internally: 0-3
221+ self ._ir_channel = int (check_chan ) - 1
222+
223+ @property
224+ def ir_address (self ):
225+ """IR Address space of 0x0 for default PoweredUp or 0x1 for extra space"""
226+ return self ._ir_address
227+
228+ def toggle_ir_toggle (self ):
229+ """Toggle the IR toggle bit"""
230+ # IYKYK, because the RC documents are not clear
231+ if self ._ir_toggle :
232+ self ._ir_toggle = 0x0
233+ else :
234+ self ._ir_toggle = 0x1
235+ return self ._ir_toggle
236+
237+ def send_ir_sop (self , port , mode ):
238+ """
239+ Send an IR message via Power Functions RC Protocol in Single Output PWM mode
240+
241+ PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm
242+
243+ Port B is blue
244+
245+ Valid values for mode are:
246+ 0x0: Float output
247+ 0x1: Forward/Clockwise at speed 1
248+ 0x2: Forward/Clockwise at speed 2
249+ 0x3: Forward/Clockwise at speed 3
250+ 0x4: Forward/Clockwise at speed 4
251+ 0x5: Forward/Clockwise at speed 5
252+ 0x6: Forward/Clockwise at speed 6
253+ 0x7: Forward/Clockwise at speed 7
254+ 0x8: Brake (then float v1.20)
255+ 0x9: Backwards/Counterclockwise at speed 7
256+ 0xA: Backwards/Counterclockwise at speed 6
257+ 0xB: Backwards/Counterclockwise at speed 5
258+ 0xC: Backwards/Counterclockwise at speed 4
259+ 0xD: Backwards/Counterclockwise at speed 3
260+ 0xE: Backwards/Counterclockwise at speed 2
261+ 0xF: Backwards/Counterclockwise at speed 1
262+
263+ :param port: 'A' or 'B'
264+ :param mode: 0-15 indicating the port's mode to set
265+ """
266+ escape_modeselect = 0x0
267+ escape = escape_modeselect
268+
269+ ir_mode_single_output = 0x4
270+ ir_mode = ir_mode_single_output
271+
272+ so_mode_pwm = 0x0
273+ so_mode = so_mode_pwm
274+
275+ output_port_a = 0x0
276+ output_port_b = 0x1
277+
278+ output_port = None
279+ if port == 'A' or port == 'a' :
280+ output_port = output_port_a
281+ elif port == 'B' or port == 'b' :
282+ output_port = output_port_b
283+ else :
284+ return False
285+
286+ ir_mode = ir_mode | (so_mode << 1 ) | output_port
287+
288+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
289+ nibble2 = (self ._ir_address << 3 ) | ir_mode
290+
291+ # Mode range checked here
292+ return self ._send_ir_nibbles (nibble1 , nibble2 , mode )
293+
294+ def send_ir_socstid (self , port , mode ):
295+ """
296+ Send an IR message via Power Functions RC Protocol in Single Output Clear/Set/Toggle/Increment/Decrement mode
297+
298+ PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm
299+
300+ Valid values for mode are:
301+ 0x0: Toggle full Clockwise/Forward (Stop to Clockwise, Clockwise to Stop, Counterclockwise to Clockwise)
302+ 0x1: Toggle direction
303+ 0x2: Increment numerical PWM
304+ 0x3: Decrement numerical PWM
305+ 0x4: Increment PWM
306+ 0x5: Decrement PWM
307+ 0x6: Full Clockwise/Forward
308+ 0x7: Full Counterclockwise/Backward
309+ 0x8: Toggle full (defaults to Forward, first)
310+ 0x9: Clear C1 (C1 to High)
311+ 0xA: Set C1 (C1 to Low)
312+ 0xB: Toggle C1
313+ 0xC: Clear C2 (C2 to High)
314+ 0xD: Set C2 (C2 to Low)
315+ 0xE: Toggle C2
316+ 0xF: Toggle full Counterclockwise/Backward (Stop to Clockwise, Counterclockwise to Stop, Clockwise to Counterclockwise)
317+
318+ :param port: 'A' or 'B'
319+ :param mode: 0-15 indicating the port's mode to set
320+ """
321+ escape_modeselect = 0x0
322+ escape = escape_modeselect
323+
324+ ir_mode_single_output = 0x4
325+ ir_mode = ir_mode_single_output
326+
327+ so_mode_cstid = 0x1
328+ so_mode = so_mode_cstid
329+
330+ output_port_a = 0x0
331+ output_port_b = 0x1
332+
333+ output_port = None
334+ if port == 'A' or port == 'a' :
335+ output_port = output_port_a
336+ elif port == 'B' or port == 'b' :
337+ output_port = output_port_b
338+ else :
339+ return False
340+
341+ ir_mode = ir_mode | (so_mode << 1 ) | output_port
342+
343+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
344+ nibble2 = (self ._ir_address << 3 ) | ir_mode
345+
346+ # Mode range checked here
347+ return self ._send_ir_nibbles (nibble1 , nibble2 , mode )
348+
349+ def send_ir_combo_pwm (self , port_b_mode , port_a_mode ):
350+ """
351+ Send an IR message via Power Functions RC Protocol in Combo PWM mode
352+
353+ PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm
354+
355+ Valid values for the modes are:
356+ 0x0 Float
357+ 0x1 PWM Forward step 1
358+ 0x2 PWM Forward step 2
359+ 0x3 PWM Forward step 3
360+ 0x4 PWM Forward step 4
361+ 0x5 PWM Forward step 5
362+ 0x6 PWM Forward step 6
363+ 0x7 PWM Forward step 7
364+ 0x8 Brake (then float v1.20)
365+ 0x9 PWM Backward step 7
366+ 0xA PWM Backward step 6
367+ 0xB PWM Backward step 5
368+ 0xC PWM Backward step 4
369+ 0xD PWM Backward step 3
370+ 0xE PWM Backward step 2
371+ 0xF PWM Backward step 1
372+
373+ :param port_b_mode: 0-15 indicating the command to send to port B
374+ :param port_a_mode: 0-15 indicating the command to send to port A
375+ """
376+ escape_combo_pwm = 0x1
377+ escape = escape_combo_pwm
378+
379+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
380+
381+ # Port modes are range checked here
382+ return self ._send_ir_nibbles (nibble1 , port_b_mode , port_a_mode )
383+
384+ def send_ir_combo_direct (self , port_b_output , port_a_output ):
385+ """
386+ Send an IR message via Power Functions RC Protocol in Combo Direct mode
387+
388+ PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm
389+
390+ Valid values for the output variables are:
391+ 0x0: Float output
392+ 0x1: Clockwise/Forward
393+ 0x2: Counterclockwise/Backwards
394+ 0x3: Brake then float
395+
396+ :param port_b_output: 0-3 indicating the output to send to port B
397+ :param port_a_output: 0-3 indicating the output to send to port A
398+ """
399+ escape_modeselect = 0x0
400+ escape = escape_modeselect
401+
402+ ir_mode_combo_direct = 0x1
403+ ir_mode = ir_mode_combo_direct
404+
405+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
406+ nibble2 = (self ._ir_address << 3 ) | ir_mode
407+
408+ if port_b_output > 0x3 or port_a_output > 0x3 :
409+ return False
410+ if port_b_output < 0x0 or port_a_output < 0x0 :
411+ return False
412+
413+ nibble3 = (port_b_output << 2 ) | port_a_output
414+
415+ return self ._send_ir_nibbles (nibble1 , nibble2 , nibble3 )
416+
417+ def send_ir_extended (self , mode ):
418+ """
419+ Send an IR message via Power Functions RC Protocol in Extended mode
420+
421+ PF IR RC Protocol documented at https://www.philohome.com/pf/pf.htm
422+
423+ Valid values for the mode are:
424+ 0x0: Brake Port A (timeout)
425+ 0x1: Increment Speed on Port A
426+ 0x2: Decrement Speed on Port A
427+
428+ 0x4: Toggle Forward/Clockwise/Float on Port B
429+
430+ 0x6: Toggle Address bit
431+ 0x7: Align toggle bit
432+
433+ :param mode: 0-2,4,6-7
434+ """
435+ escape_modeselect = 0x0
436+ escape = escape_modeselect
437+
438+ ir_mode_extended = 0x0
439+ ir_mode = ir_mode_extended
440+
441+ nibble1 = (self ._ir_toggle << 3 ) | (escape << 2 ) | self ._ir_channel
442+ nibble2 = (self ._ir_address << 3 ) | ir_mode
443+
444+ if mode < 0x0 or mode == 0x3 or mode == 0x5 or mode > 0x7 :
445+ return False
446+
447+ return self ._send_ir_nibbles (nibble1 , nibble2 , mode )
448+
449+ def send_ir_single_pin (self , port , pin , mode , timeout ):
450+ """
451+ Send an IR message via Power Functions RC Protocol in Single Pin mode
452+
453+ PF IR RC Protocol documented at 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 , nibble3 )
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