예제 #1
0
 def __init__(self, pin, cfreq, asize, duty, verbose):
     if ESP32:
         self._rmt = RMT(0,
                         pin=pin,
                         clock_div=80,
                         carrier_freq=cfreq,
                         carrier_duty_percent=duty)  # 1μs resolution
     elif RP2:  # PIO-based RMT-like device
         self._rmt = RP2_RMT(pin_pulse=None,
                             carrier=(pin, cfreq, duty))  # 1μs resolution
     else:  # Pyboard
         if not IR._active_high:
             duty = 100 - duty
         tim = Timer(2,
                     freq=cfreq)  # Timer 2/pin produces 36/38/40KHz carrier
         self._ch = tim.channel(1, Timer.PWM, pin=pin)
         self._ch.pulse_width_percent(self._space)  # Turn off IR LED
         # Pyboard: 0 <= pulse_width_percent <= 100
         self._duty = duty
         self._tim = Timer(5)  # Timer 5 controls carrier on/off times
     self._tcb = self._cb  # Pre-allocate
     self._arr = array('H', 0 for _ in range(asize))  # on/off times (μs)
     self._mva = memoryview(self._arr)
     # Subclass interface
     self.verbose = verbose
     self.carrier = False  # Notional carrier state while encoding biphase
     self.aptr = 0  # Index into array
예제 #2
0
class Pixels:
    def __init__(self, pin, pixel_count, rmt_channel=1):
        self.rmt = RMT(rmt_channel, pin, clock_div=4)
        # pixels stores the data sent out via RMT
        self.pixels = [self.encode_pixel(0, 0, 0)] * pixel_count
        # colors is only used for __getitem__
        self.colors = [(0, 0, 0)] * pixel_count

    def encode_pixel(self, r, g, b):
        i_24 = (g & 0xFF) << 16 | (r & 0xFF) << 8 | (b & 0xFF)
        # This can probably be faster or better or something. #VersionZeroPointZero.
        bits = '{0:024b}'.format(i_24)
        bits = map(lambda i: D_ZERO if i == '0' else D_ONE, bits)
        return tuple(clocks for bit in bits for clocks in bit)

    def set(self, pixel, r, g, b):
        self.colors[pixel] = (r, g, b)
        self.pixels[pixel] = self.encode_pixel(r, g, b)

    def write(self):
        # The bus should be idle low ( I think... )
        # So we finish low and start high.
        pulses = tuple()
        for pixel in self.pixels:
            pulses += pixel
        pulses = pulses[:-1] + (T_RST,) # The last low should be long.
        self.rmt.write_pulses(pulses, start=1)

    # pixels[0] = (r, g, b)
    def __setitem__(self, pixel_index, pixel_set):
        self.set(pixel_index, *pixel_set)

    def __getitem__(self, pixel_index):
        return self.colors[pixel_index]
예제 #3
0
 def __init__(self, pin, fname, reps=5):
     self._pin = pin
     self._reps = reps
     with open(fname, 'r') as f:
         self._data = ujson.load(f)
     # Time to wait between nonblocking transmissions. A conservative value in ms.
     self._latency = (reps + 2) * max(
         (sum(x) for x in self._data.values())) // 1000
     gc.collect()
     if ESP32:
         self._rmt = RMT(0, pin=pin, clock_div=80)  # 1μs resolution
     elif RP2:  # PIO-based RMT-like device
         self._rmt = RP2_RMT(pin_pulse=pin)  # 1μs resolution
         # Array size: length of longest entry + 1 for STOP
         asize = max([len(x) for x in self._data.values()]) + 1
         self._arr = array('H',
                           (0 for _ in range(asize)))  # on/off times (μs)
     else:  # Pyboard
         self._tim = Timer(5)  # Timer 5 controls carrier on/off times
         self._tcb = self._cb  # Pre-allocate
         asize = reps * max([len(x) for x in self._data.values()
                             ]) + 1  # Array size
         self._arr = array('H',
                           (0 for _ in range(asize)))  # on/off times (μs)
         self._aptr = 0  # Index into array
예제 #4
0
 def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3):
     self.rmt = RMT(rmt_channel, pin=pin, clock_div=4)
     # pixels stores the data sent out via RMT
     self.channels = pixel_channels
     single_pixel = (0, ) * pixel_channels
     self.pixels = [D_ZERO * (pixel_channels * CHANNEL_WIDTH)] * pixel_count
     # colors is only used for __getitem__
     self.colors = [single_pixel] * pixel_count
예제 #5
0
 def __init__(self, pwm_pin, freq=5000, duty=512):
     for idx in range(len(PWM.RMT_channels)):
         if not PWM.RMT_channels[idx]:  # find free channel
             PWM.RMT_channels[idx] = True
             # mark used cnannel
             self.RMT_channel = idx  # keep the channel number
             self.RMT_obj = RMT(idx, pin=pwm_pin, clock_div=80)
             self.pwm_duty = 512
             self.pwm_freq = 5000
             self.init(freq, duty)
             break
     else:
         raise RuntimeError('No RMT channel available.')
예제 #6
0
def send_command(add, com, comn=None):
    ''' Sends command on IR input is address and command '''
    # RMT(channel=0, pin=4, source_freq=80000000, clock_div=24, carrier_freq=38222, carrier_duty_percent=50)
    remote = RMT(0, pin=Pin(4), clock_div=24, carrier_freq=38222)

    lst = list()
    add_leadpulse(lst)

    send_byte(add, lst)
    send_byte(~add, lst)
    send_byte(com, lst)
    
    
    # I identified some keys on Yamaha remote did not send exact invert of command, instead some bits were peculiar.
    # This deviated from NEC protocol, but work around was simple.
    # If peculiar code is present that's sent, otherwise inverted code is sent.
    if comn is None:
        send_byte(~com, lst)
    else:
        send_byte(comn, lst)

    add_endpulse(lst)

    remote.write_pulses(lst, start=1)
    remote.wait_done()
    del lst
    # Without deinit and reinitializing remote after every use, second use of remote will hang it.
    # This issue may have been resolved in MicroPython 1.13 or later. Not tested.
    # However using below command is a workaround that works :)
    remote.deinit()
예제 #7
0
class PWM():
    # free RMT channel table
    RMT_channels = [False, False, False, False, False, False, False, False]

    def __init__(self, pwm_pin, freq=5000, duty=512):
        for idx in range(len(PWM.RMT_channels)):
            if not PWM.RMT_channels[idx]:  # find free channel
                PWM.RMT_channels[idx] = True
                # mark used cnannel
                self.RMT_channel = idx  # keep the channel number
                self.RMT_obj = RMT(idx, pin=pwm_pin, clock_div=80)
                self.pwm_duty = 512
                self.pwm_freq = 5000
                self.init(freq, duty)
                break
        else:
            raise RuntimeError('No RMT channel available.')

    def run(self):
        period = 1000000 / (self.pwm_freq)
        up_time = round(period * (self.pwm_duty / 1023))
        down_time = round(period) - up_time
        self.RMT_obj.loop(False)
        self.RMT_obj.write_pulses((up_time, down_time), start=1)
        self.RMT_obj.loop(True)
        # MicroPython 1.13 requires loop() running before write_pulses()
        # MicroPython 1.12 would report error if loop() runs before any write_pulses()
        self.RMT_obj.write_pulses((up_time, down_time), start=1)

    def freq(self, new_freq):
        self.pwm_freq = new_freq if new_freq > 15 else 16
        self.run()

    def duty(self, new_duty):
        self.pwm_duty = new_duty if new_duty < 1023 else 1023
        self.run()

    def deinit(self):
        self.RMT_obj.deinit()
        PWM.RMT_channels[self.RMT_channel] = False

    def init(self, freq=5000, duty=512):
        self.freq(freq)
        self.duty(duty)
예제 #8
0
 def __init__(self, pin, fname, reps=5):
     self._pin = pin
     self._reps = reps
     try:
         with open(fname, 'r') as f:
             self._data = ujson.load(f)
     except OSError:
         print("Can't open file '{}' for reading.".format(fname))
         return
     gc.collect()
     if ESP32:
         self._rmt = RMT(0, pin=pin, clock_div=80)  # 1μs resolution
     else:  # Pyboard
         self._tim = Timer(5)  # Timer 5 controls carrier on/off times
         self._tcb = self._cb  # Pre-allocate
         asize = reps * max([len(x) for x in self._data.values()
                             ]) + 1  # Array size
         self._arr = array('H', 0
                           for _ in range(asize))  # on/off times (μs)
         self._aptr = 0  # Index into array
예제 #9
0
 def __init__(self, pin, freq=50, duty=0, verbose=False, channel=-1):
     if channel in [i for i in range(RMT_MAX_CHAN)]:
         self._chanRMT = channel
         self._pin = RMT(channel, pin=Pin(pin), clock_div=RMT_CLOCK_DIV)
         self.__setRMTDuty(duty)
         self._pin.loop(True)
     else:
         self._chanRMT = -1
         self._pin = PWM(Pin(pin))
         self._pin.init(freq=freq, duty=duty)
     self._verbose = verbose
     if self._verbose:
         self.__logFrequency()
예제 #10
0
 def __init__(self, pin, cfreq, asize, duty, verbose):
     if ESP32:
         self._pwm = PWM(pin[0])  # Continuous 36/38/40KHz carrier
         self._pwm.deinit()
         # ESP32: 0 <= duty <= 1023
         self._pwm.init(freq=cfreq, duty=round(duty * 10.23))
         self._rmt = RMT(0, pin=pin[1], clock_div=80)  # 1μs resolution
     else:  # Pyboard
         if not IR._active_high:
             duty = 100 - duty
         tim = Timer(2,
                     freq=cfreq)  # Timer 2/pin produces 36/38/40KHz carrier
         self._ch = tim.channel(1, Timer.PWM, pin=pin)
         self._ch.pulse_width_percent(self._space)  # Turn off IR LED
         # Pyboard: 0 <= pulse_width_percent <= 100
         self._duty = duty
         self._tim = Timer(5)  # Timer 5 controls carrier on/off times
     self._tcb = self._cb  # Pre-allocate
     self._arr = array('H', 0 for _ in range(asize))  # on/off times (μs)
     self._mva = memoryview(self._arr)
     # Subclass interface
     self.verbose = verbose
     self.carrier = False  # Notional carrier state while encoding biphase
     self.aptr = 0  # Index into array
예제 #11
0
 def __init__(self, pin: Pin, rmt: RMT = None, rmt_number: int = 0, carrier_freq: int = 38000) -> None:
     self.pin = pin
     if rmt is None:
         rmt = RMT(rmt_number, pin=self.pin, clock_div=80, carrier_freq=carrier_freq)
     self.rmt = rmt
     self.reset()
예제 #12
0
 def __init__(self, pin, pixel_count, rmt_channel=1):
     self.rmt = RMT(rmt_channel, pin, clock_div=4)
     # pixels stores the data sent out via RMT
     self.pixels = [self.encode_pixel(0, 0, 0)] * pixel_count
     # colors is only used for __getitem__
     self.colors = [(0, 0, 0)] * pixel_count
예제 #13
0
def STCP_puls():
    stcp.off()
    sleep_us(20)
    stcp.on()


def refresh():
    return r.write_pulses((1, ), start=1)


spi = SPI(2,
          baudrate=115200,
          polarity=1,
          phase=1,
          bits=8,
          firstbit=1,
          sck=Pin(18),
          mosi=Pin(23),
          miso=Pin(19))
spi.init(baudrate=115200)
en = Pin(22, Pin.OUT, 0)
stcp = Pin(21, Pin.OUT, 0)
r = RMT(0, pin=Pin(17), clock_div=8)
while True:
    print("write")
    spi.write(bytes([0b10000000]))
    # STCP_puls()
    refresh()
    sleep_ms(500)
    break
예제 #14
0
class IR:
    _active_high = True  # Hardware turns IRLED on if pin goes high.
    _space = 0  # Duty ratio that causes IRLED to be off
    timeit = False  # Print timing info

    @classmethod
    def active_low(cls):
        if ESP32:
            raise ValueError('Cannot set active low on ESP32')
        cls._active_high = False
        cls._space = 100

    def __init__(self, pin, cfreq, asize, duty, verbose):
        if ESP32:
            self._rmt = RMT(0,
                            pin=pin,
                            clock_div=80,
                            carrier_freq=cfreq,
                            carrier_duty_percent=duty)  # 1μs resolution
        elif RP2:  # PIO-based RMT-like device
            self._rmt = RP2_RMT(pin_pulse=None,
                                carrier=(pin, cfreq, duty))  # 1μs resolution
        else:  # Pyboard
            if not IR._active_high:
                duty = 100 - duty
            tim = Timer(2,
                        freq=cfreq)  # Timer 2/pin produces 36/38/40KHz carrier
            self._ch = tim.channel(1, Timer.PWM, pin=pin)
            self._ch.pulse_width_percent(self._space)  # Turn off IR LED
            # Pyboard: 0 <= pulse_width_percent <= 100
            self._duty = duty
            self._tim = Timer(5)  # Timer 5 controls carrier on/off times
        self._tcb = self._cb  # Pre-allocate
        self._arr = array('H', 0 for _ in range(asize))  # on/off times (μs)
        self._mva = memoryview(self._arr)
        # Subclass interface
        self.verbose = verbose
        self.carrier = False  # Notional carrier state while encoding biphase
        self.aptr = 0  # Index into array

    def _cb(self, t):  # T5 callback, generate a carrier mark or space
        t.deinit()
        p = self.aptr
        v = self._arr[p]
        if v == STOP:
            self._ch.pulse_width_percent(self._space)  # Turn off IR LED.
            return
        self._ch.pulse_width_percent(self._space if p & 1 else self._duty)
        self._tim.init(prescaler=84, period=v, callback=self._tcb)
        self.aptr += 1

    # Public interface
    # Before populating array, zero pointer, set notional carrier state (off).
    def transmit(self,
                 addr,
                 data,
                 toggle=0,
                 validate=False):  # NEC: toggle is unused
        t = ticks_us()
        if validate:
            if addr > self.valid[0] or addr < 0:
                raise ValueError('Address out of range', addr)
            if data > self.valid[1] or data < 0:
                raise ValueError('Data out of range', data)
            if toggle > self.valid[2] or toggle < 0:
                raise ValueError('Toggle out of range', toggle)
        self.aptr = 0  # Inital conditions for tx: index into array
        self.carrier = False
        self.tx(addr, data, toggle)  # Subclass populates ._arr
        self.trigger()  # Initiate transmission
        if self.timeit:
            dt = ticks_diff(ticks_us(), t)
            print('Time = {}μs'.format(dt))

    # Subclass interface
    def trigger(self):  # Used by NEC to initiate a repeat frame
        if ESP32:
            self._rmt.write_pulses(tuple(self._mva[0:self.aptr]), start=1)
        elif RP2:
            self.append(STOP)
            self._rmt.send(self._arr)
        else:
            self.append(STOP)
            self.aptr = 0  # Reset pointer
            self._cb(self._tim)  # Initiate physical transmission.

    def append(self, *times):  # Append one or more time peiods to ._arr
        for t in times:
            self._arr[self.aptr] = t
            self.aptr += 1
            self.carrier = not self.carrier  # Keep track of carrier state
            self.verbose and print('append', t, 'carrier', self.carrier)

    def add(self, t):  # Increase last time value (for biphase)
        assert t > 0
        self.verbose and print('add', t)
        # .carrier unaffected
        self._arr[self.aptr - 1] += t
예제 #15
0
 def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3):
     self.rmt = RMT(rmt_channel, pin=pin, clock_div=4)
     self.pixelPulseLen = CHANNEL_WIDTH * pixel_channels * 2
     # pixels stores the data sent out via RMT
     self.pixels = D_ZERO * (pixel_channels * CHANNEL_WIDTH *
                             pixel_count) + (T_RST, )
예제 #16
0
class Pixels:
    @micropython.native
    def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3):
        self.rmt = RMT(rmt_channel, pin=pin, clock_div=4)
        self.pixelPulseLen = CHANNEL_WIDTH * pixel_channels * 2
        # pixels stores the data sent out via RMT
        self.pixels = D_ZERO * (pixel_channels * CHANNEL_WIDTH *
                                pixel_count) + (T_RST, )
        # colors is only used for __getitem__

    @micropython.viper
    def write(self):
        # The bus should be idle low ( I think... )
        # So we finish low and start high.
        #pulses = tuple()
        #print("Before write: ")
        #print(self.pixels)
        #startTime=time.ticks_us()
        self.rmt.write_pulses(self.pixels, start=1)
        #self.rmt.write_pulses(self.pixelByteArr, start=1)
        #stopTime=time.ticks_us()
        #print ("RMT write took: " + str(stopTime-startTime))
        #print("after write; ")
        #print(self.pixels)

    #@micropython.viper
    def __setitem__(self, pixel_index, colors):
        #startTime=time.ticks_us()
        # pixels[0] = (r, g, b)
        pulseIndex = int(0)
        pxl = bytearray(self.pixelPulseLen)
        #print("comparing")
        for color in colors:
            #print("Color: " + str(color))
            colorInt = int(color)
            for bits in range(CHANNEL_WIDTH):
                #print(bin(colorInt))
                bit = colorInt & 128
                #print("Bit" + str(bit))
                if bit:
                    #print("1", end="")
                    pxl[pulseIndex] = T_1H
                    pxl[pulseIndex + 1] = T_1L
                else:
                    #print("0", end="")
                    pxl[pulseIndex] = T_0H
                    pxl[pulseIndex + 1] = T_0L
                colorInt = colorInt << 1
                pulseIndex += 2
        #print("")
        pxlTup = tuple(pxl)
        pulseIndex = int(pixel_index * self.pixelPulseLen)
        #self.insertPxl(pulseIndex, pxlTup)

        #print(pxlTup)
        #ref_pixel = tuple(clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit)
        #cnt=0
        #while(cnt < len(ref_pixel)):
        #if ref_pixel[cnt] == 16 and ref_pixel[cnt+1] == 9 : print("1", end="")
        #elif ref_pixel[cnt] == 8 and ref_pixel[cnt+1] == 17 : print("0", end="")
        #else: print("x")
        #cnt +=2
        #print("")

        #clocks for bit in (
        #D_ONE if ((channel >> bit) & 1)
        #else D_ZERO
        #for channel in colors
        #    for bit in range(CHANNEL_WIDTH - 1, -1, -1)):
        #        for clocks in bit:

        #for color in colors:
        #    colorInt=int(color)
        #    for bits in range(CHANNEL_WIDTH):
        #        bit = colorInt & 1
        #        if bit == 1:
        #            pxl = pxl + D_ONE
        #        else:
        #            pxl = pxl + D_ZERO
        #        colorInt = colorInt >> 1
        #self.insertPxl(pulseIndex, pxl)
        #self.pixels = self.pixels[:pulseIndex] + pxl + self.pixels[(pulseIndex+self.pixelPulseLen):]

        #self_pixels = self_pixels[:pulseIndex] + tuple(clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) + self_pixels[(pulseIndex+self.pixelPulseLen):]
        self.pixels = self.pixels[:pulseIndex] + tuple(
            clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO
                               for channel in colors
                               for bit in range(CHANNEL_WIDTH - 1, -1, -1))
            for clocks in bit) + self.pixels[(pulseIndex +
                                              self.pixelPulseLen):]
        #self.pixels = self_pixels
        #pixelLst = list(self.pixels)
        #pixelLst[pulseIndex:(pulseIndex+self.pixelPulseLen)] = list(clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit)
        #self.pixels = tuple(pixelLst)
        #stopTime=time.ticks_us()
        #print ("__setitem__ took: " + str(stopTime-startTime))
        #print("after ´__setitems__")
        #print(self.pixels)

    @micropython.native
    def insertPxl(self, index, pxl):
        self.pixels = self.pixels[:index] + pxl + self.pixels[
            (index + self.pixelPulseLen):]
예제 #17
0
class Pixels:
    def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3):
        self.rmt = RMT(rmt_channel, pin=pin, clock_div=4)
        # pixels stores the data sent out via RMT
        self.channels = pixel_channels
        single_pixel = (0, ) * pixel_channels
        self.pixels = [D_ZERO * (pixel_channels * CHANNEL_WIDTH)] * pixel_count
        # colors is only used for __getitem__
        self.colors = [single_pixel] * pixel_count

    def write(self):
        # The bus should be idle low ( I think... )
        # So we finish low and start high.
        pulses = tuple()
        for pixel in self.pixels:
            pulses += pixel
        pulses = pulses[:-1] + (T_RST, )  # The last low should be long.
        self.rmt.write_pulses(pulses, start=1)

    def __setitem__(self, pixel_index, colors):
        self_colors = self.colors
        self_pixels = self.pixels
        if isinstance(pixel_index, int):
            # pixels[0] = (r, g, b)
            self_colors[pixel_index] = tuple(colors)
            self_pixels[pixel_index] = tuple(
                clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO
                                   for channel in colors
                                   for bit in range(CHANNEL_WIDTH - 1, -1, -1))
                for clocks in bit)
        elif isinstance(pixel_index, slice):
            start = 0 if pixel_index.start is None else pixel_index.start
            stop = len(
                self.pixels) if pixel_index.stop is None else pixel_index.stop
            step = 1 if pixel_index.step is None else pixel_index.step
            # Assume that if the first colors element is an int, then its not a sequence
            # Otherwise always assume its a sequence of colors
            if isinstance(colors[0], int):
                # pixels[:] = (r,g,b)
                for index in range(start, stop, step):
                    self_colors[index] = tuple(colors)
                    self_pixels[index] = tuple(
                        clocks
                        for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO
                                    for channel in colors
                                    for bit in range(CHANNEL_WIDTH -
                                                     1, -1, -1))
                        for clocks in bit)
            else:
                # pixels[:] = [(r,g,b), ...]
                # Assume its a sequence, make it a list so we know the length
                if not isinstance(colors, list):
                    colors = list(colors)
                color_length = len(colors)
                for index in range(start, stop, step):
                    color = colors[(index - start) % color_length]
                    self_colors[index] = tuple(color)
                    self_pixels[index] = tuple(
                        clocks
                        for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO
                                    for channel in color
                                    for bit in range(CHANNEL_WIDTH -
                                                     1, -1, -1))
                        for clocks in bit)
        else:
            raise TypeError('Unsupported pixel_index {} ({})'.format(
                pixel_index, type(pixel_index)))

    def __getitem__(self, pixel_index):
        # slice instances are passed through
        return self.colors[pixel_index]
예제 #18
0
sendtime=bytearray(8)
# second counter 0-59
second=bytearray(1)
# TX bits for one minute
minute=bytearray(59)
# index for writing to minute[]
index=bytearray(1)
# 1-second timer
timer=Timer(3)

# last day NTP was set
ntpday=0

led=Pin(2,Pin.OUT)
antena=Pin(15,Pin.OUT)
ask=RMT(0,pin=antena,carrier_freq=0,clock_div=1) # 80 MHz
ask.loop(True)

if disp:
  import ssd1306
  i2c = I2C(scl=Pin(4), sda=Pin(5))
  oled = ssd1306.SSD1306_I2C(128, 64, i2c, 0x3c)
  oled.fill(0)
  oled.text("DCF77", 0, 0)
  oled.show()

weekdaystr = ["MO","TU","WE","TH","FR","SA","SU"]

# desired carrier frequency
freq=77500
# tuning paramters - adjust with scope
예제 #19
0
class TX:
    timeit = False  # Print timing info
    _active_high = True

    @classmethod
    def active_low(cls):
        if ESP32:
            raise ValueError('Cannot set active low on ESP32')
        cls._active_high = False

    def __init__(self, pin, fname, reps=5):
        self._pin = pin
        self._reps = reps
        try:
            with open(fname, 'r') as f:
                self._data = ujson.load(f)
        except OSError:
            print("Can't open file '{}' for reading.".format(fname))
            return
        gc.collect()
        if ESP32:
            self._rmt = RMT(0, pin=pin, clock_div=80)  # 1μs resolution
        else:  # Pyboard
            self._tim = Timer(5)  # Timer 5 controls carrier on/off times
            self._tcb = self._cb  # Pre-allocate
            asize = reps * max([len(x) for x in self._data.values()
                                ]) + 1  # Array size
            self._arr = array('H', 0
                              for _ in range(asize))  # on/off times (μs)
            self._aptr = 0  # Index into array

    def _cb(self, t):  # T5 callback, generate a carrier mark or space
        t.deinit()
        p = self._aptr
        v = self._arr[p]
        if v == STOP:
            self._pin(self._active_high ^ 1)
            return
        self._pin(p & 1 ^ self._active_high)
        self._tim.init(prescaler=84, period=v, callback=self._tcb)
        self._aptr += 1

    def __getitem__(self, key):
        if key in self._data:
            return self._data[key]
        print('Key "{}" does not exist'.format(key))

    def keys(self):
        return self._data.keys()

    def show(self, key):
        res = self[key]
        if res is not None:
            for x, t in enumerate(res):
                print('{:3d} {:6d}'.format(x, t))

    # Nonblocking transmit
    def __call__(self, key):
        gc.collect()
        lst = self[key]
        if lst is not None:
            lst = lst * self._reps
            if ESP32:
                self._rmt.write_pulses(lst, start=1)  # Active high
            else:
                for x, t in enumerate(lst):
                    self._arr[x] = t
                x += 1
                self._arr[x] = STOP
                self._aptr = 0  # Reset pointer
                self._cb(self._tim)  # Initiate physical transmission.

    # Blocking transmit: proved necessary on Pyboard Lite
    @micropython.native
    def send(self, key):
        gc.collect()
        pin = self._pin
        q = self._active_high ^ 1  # Pin inactive state
        lst = self[key]
        if lst is not None:
            for _ in range(self._reps):
                pin(q)
                for t in lst:
                    pin(pin() ^ 1)
                    sleep_us(t)
        pin(q)
예제 #20
0
class TX:
    _active_high = True

    @classmethod
    def active_low(cls):
        if ESP32:
            raise ValueError('Cannot set active low on ESP32')
        cls._active_high = False

    def __init__(self, pin, fname, reps=5):
        self._pin = pin
        self._reps = reps
        with open(fname, 'r') as f:
            self._data = ujson.load(f)
        # Time to wait between nonblocking transmissions. A conservative value in ms.
        self._latency = (reps + 2) * max(
            (sum(x) for x in self._data.values())) // 1000
        gc.collect()
        if ESP32:
            self._rmt = RMT(0, pin=pin, clock_div=80)  # 1μs resolution
        elif RP2:  # PIO-based RMT-like device
            self._rmt = RP2_RMT(pin_pulse=pin)  # 1μs resolution
            # Array size: length of longest entry + 1 for STOP
            asize = max([len(x) for x in self._data.values()]) + 1
            self._arr = array('H',
                              (0 for _ in range(asize)))  # on/off times (μs)
        else:  # Pyboard
            self._tim = Timer(5)  # Timer 5 controls carrier on/off times
            self._tcb = self._cb  # Pre-allocate
            asize = reps * max([len(x) for x in self._data.values()
                                ]) + 1  # Array size
            self._arr = array('H',
                              (0 for _ in range(asize)))  # on/off times (μs)
            self._aptr = 0  # Index into array

    def _cb(self, t):  # T5 callback, generate a carrier mark or space
        t.deinit()
        p = self._aptr
        v = self._arr[p]
        if v == STOP:
            self._pin(self._active_high ^ 1)
            return
        self._pin(p & 1 ^ self._active_high)
        self._tim.init(prescaler=84, period=v, callback=self._tcb)
        self._aptr += 1

    def __getitem__(self, key):
        return self._data[key]

    def keys(self):
        return self._data.keys()

    def show(self, key):
        res = self[key]
        if res is not None:
            for x, t in enumerate(res):
                print('{:3d} {:6d}'.format(x, t))

    def latency(self):
        return self._latency

    # Nonblocking transmit
    def __call__(self, key):
        gc.collect()
        lst = self[key]
        if lst is not None:
            if ESP32:
                # TODO use RMT.loop() cancelled by a soft timer to do reps.
                # This would save RAM. RMT.loop() is now fixed. I remain
                # unconvinced because of the huge latency of soft timers on
                # boards with SPIRAM. It would save ram if a half-word array
                # could be passed. But it can't (as of 9th March 2021).
                self._rmt.write_pulses(lst * self._reps,
                                       start=1)  # Active high
            elif RP2:
                for x, t in enumerate(lst):
                    self._arr[x] = t
                self._arr[x + 1] = STOP
                self._rmt.send(self._arr, self._reps)
            else:
                x = 0
                for _ in range(self._reps):
                    for t in lst:
                        self._arr[x] = t
                        x += 1
                self._arr[x] = STOP
                self._aptr = 0  # Reset pointer
                self._cb(self._tim)  # Initiate physical transmission.

    # Blocking transmit: proved necessary on Pyboard Lite
    @micropython.native
    def send(self, key):
        gc.collect()
        pin = self._pin
        q = self._active_high ^ 1  # Pin inactive state
        lst = self[key]
        if lst is not None:
            for _ in range(self._reps):
                pin(q)
                for t in lst:
                    pin(pin() ^ 1)
                    sleep_us(t)
        pin(q)