]>
vault307.fbx.one Git - micorpython_ir.git/blob - ir_tx/__init__.py
1 # __init__.py Nonblocking IR blaster
2 # Runs on Pyboard D or Pyboard 1.x (not Pyboard Lite), ESP32 and RP2
4 # Released under the MIT License (MIT). See LICENSE.
6 # Copyright (c) 2020-2021 Peter Hinch
7 from sys
import platform
8 ESP32
= platform
== 'esp32' # Loboris not supported owing to RMT
9 RP2
= platform
== 'rp2'
11 from machine
import Pin
, PWM
14 from .rp2_rmt
import RP2_RMT
16 from pyb
import Pin
, Timer
# Pyboard does not support machine.PWM
18 from micropython
import const
19 from array
import array
20 from time
import ticks_us
, ticks_diff
22 # micropython.alloc_emergency_exception_buf(100)
26 STOP
= const(0) # End of data
28 # IR abstract base class. Array holds periods in μs between toggling 36/38KHz
29 # carrier on or off. Physical transmission occurs in an ISR context controlled
30 # by timer 2 and timer 5. See TRANSMITTER.md for details of operation.
32 _active_high
= True # Hardware turns IRLED on if pin goes high.
33 _space
= 0 # Duty ratio that causes IRLED to be off
34 timeit
= False # Print timing info
39 raise ValueError('Cannot set active low on ESP32')
40 cls
._active
_high
= False
43 def __init__(self
, pin
, cfreq
, asize
, duty
, verbose
):
45 self
._rmt
= RMT(0, pin
=pin
, clock_div
=80, tx_carrier
= (cfreq
, duty
, 1))
47 elif RP2
: # PIO-based RMT-like device
48 self
._rmt
= RP2_RMT(pin_pulse
=None, carrier
=(pin
, cfreq
, duty
)) # 1μs resolution
50 if not IR
._active
_high
:
52 tim
= Timer(2, freq
=cfreq
) # Timer 2/pin produces 36/38/40KHz carrier
53 self
._ch
= tim
.channel(1, Timer
.PWM
, pin
=pin
)
54 self
._ch
.pulse_width_percent(self
._space
) # Turn off IR LED
55 # Pyboard: 0 <= pulse_width_percent <= 100
57 self
._tim
= Timer(5) # Timer 5 controls carrier on/off times
58 self
._tcb
= self
._cb
# Pre-allocate
59 self
._arr
= array('H', 0 for _
in range(asize
)) # on/off times (μs)
60 self
._mva
= memoryview(self
._arr
)
62 self
.verbose
= verbose
63 self
.carrier
= False # Notional carrier state while encoding biphase
64 self
.aptr
= 0 # Index into array
66 def _cb(self
, t
): # T5 callback, generate a carrier mark or space
71 self
._ch
.pulse_width_percent(self
._space
) # Turn off IR LED.
73 self
._ch
.pulse_width_percent(self
._space
if p
& 1 else self
._duty
)
74 self
._tim
.init(prescaler
=84, period
=v
, callback
=self
._tcb
)
78 # Before populating array, zero pointer, set notional carrier state (off).
79 def transmit(self
, addr
, data
, toggle
=0, validate
=False): # NEC: toggle is unused
82 if addr
> self
.valid
[0] or addr
< 0:
83 raise ValueError('Address out of range', addr
)
84 if data
> self
.valid
[1] or data
< 0:
85 raise ValueError('Data out of range', data
)
86 if toggle
> self
.valid
[2] or toggle
< 0:
87 raise ValueError('Toggle out of range', toggle
)
88 self
.aptr
= 0 # Inital conditions for tx: index into array
90 self
.tx(addr
, data
, toggle
) # Subclass populates ._arr
91 self
.trigger() # Initiate transmission
93 dt
= ticks_diff(ticks_us(), t
)
94 print('Time = {}μs'.format(dt
))
97 def trigger(self
): # Used by NEC to initiate a repeat frame
99 self
._rmt
.write_pulses(tuple(self
._mva
[0 : self
.aptr
]))
102 self
._rmt
.send(self
._arr
)
105 self
.aptr
= 0 # Reset pointer
106 self
._cb
(self
._tim
) # Initiate physical transmission.
108 def append(self
, *times
): # Append one or more time peiods to ._arr
110 self
._arr
[self
.aptr
] = t
112 self
.carrier
= not self
.carrier
# Keep track of carrier state
113 self
.verbose
and print('append', t
, 'carrier', self
.carrier
)
115 def add(self
, t
): # Increase last time value (for biphase)
117 self
.verbose
and print('add', t
)
118 # .carrier unaffected
119 self
._arr
[self
.aptr
- 1] += t
122 # Given an iterable (e.g. list or tuple) of times, emit it as an IR stream.
125 def __init__(self
, pin
, freq
=38000, verbose
=False): # NEC specifies 38KHz
126 super().__init
__(pin
, freq
, 68, 33, verbose
) # Measured duty ratio 33%
129 for x
, t
in enumerate(lst
):