Due to high demand expect some shipping delays at this time, orders may not ship for 1-2 business days.
0

Variable tuple not surviving def call
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Variable tuple not surviving def call

by blakebr on Sat Oct 16, 2021 1:17 pm

Hello,

Why is Ky, in print(Ky) # What is going on?, being changed during the encoder.transmit(pulseout, IR_Command, nbits=32) call?
the print(Ky) results in >>> [0,0,0,0]
How do I prevent/avoid it?


Code: Select all | TOGGLE FULL SIZE
def skip_loop(loops):
    time.sleep(1)
    if not QTPy: LED.value = True
    for xx in range(loops):
        print(loops-xx, end=" ")
#        Kz = [0,0,0,0]
        Ky = [0xD0, 0x27, 0x30, 0x85] # SKIP30x
        IR_Command = Ky
        encoder.transmit(pulseout, IR_Command, nbits=32)
        print(Ky) # What is going on?
        time.sleep(0.5)
    print("")
    if not QTPy: LED.value = False

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Re: Variable tuple not surviving def call

by dastels on Sat Oct 16, 2021 1:29 pm

IR_Command *IS* Ky; it's just another name for the same list. So whatever is referred to by IR_Comamnd (and thus Ky) is being passed to transmit., which apparently changes it. What is encoder?

You could try making a copy of Ky (not just another name) and transmit the copy?
Code: Select all | TOGGLE FULL SIZE
IR_Command = Ky.copy()

Dave

dastels
 
Posts: 7972
Joined: Tue Oct 20, 2015 3:22 pm

Re: Variable tuple not surviving def call

by blakebr on Sat Oct 16, 2021 2:31 pm

Dave,

Thank you. .copy() is new to me.

Bruce

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Re: Variable tuple not surviving def call

by blakebr on Sat Oct 16, 2021 9:26 pm

Oops,

Encoder is a routine that encodes a 32 bit binary number into microsecond pairs that define the times that an IR LED running at 38kHz is modulated to emulate IR TV, TiVo, Blue Ray, etc commands.

My project receives an IR command then sends a series of commands. e.g. RCA input command translated into 7 TiVo skip 30 seconds commands. Reruns of Law & Order generally have 3-1/2 minutes of commercials at a time. One button push on the remote results in one big commercial skip. :-)

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Re: Variable tuple not surviving def call

by dastels on Sat Oct 16, 2021 11:05 pm

I was curious to be able to look into encoder to see what it's doing with the list it's passed.

Dave

dastels
 
Posts: 7972
Joined: Tue Oct 20, 2015 3:22 pm

Re: Variable tuple not surviving def call

by blakebr on Sun Oct 17, 2021 9:57 am

Dave,

Thank you for looking at my code. My full code is below.

In line 156 decoder is defined.
In line 162 encoder is defined.
In lines ~245 - ~250 the problem showed itself.
IR_Command is still clobbered in the encoder call.
.code() fixed part of my ignorance. (ignorance can be fixed through education, stupid is forever ;-)

My problem now is: Why are the variables defined as global in def key_codes(): not found as defined in def skip_loop(loops): SKIP30 shows as [0,0,0,0].

You may ask why is there a def reverse_bits(IN)? IR codes are written Most Significant Byte FIRST but sent Least Significant Bit FIRST. Gotta love programming.

Bruce

Code: Select all | TOGGLE FULL SIZE
'''
    IR Relay and translate by B.B.Blake 10/10/2021
'''
import array
import board
import digitalio
from   digitalio import DigitalInOut, Direction, Pull
import neopixel
import pulseio
import pwmio
import time
import microcontroller # Don't know why we need it.
#from   microcontroller import pin
#test = pin.GPIO6

import adafruit_esp32spi
from   adafruit_esp32spi import PWMOut
import adafruit_irremote

Pico, Itsy, QTPy, Fthr = False, False, False, False
bd    = board.board_id # Ask the AdaFruit OS what board we are using
print("\f" + bd, end=" ")
if(bd == "raspberry_pi_pico"):
    Pico = True
if(bd == "adafruit_itsybitsy_rp2040"):
    Itsy = True
if(bd == "adafruit_qtpy_rp2040"):
    QTPy = True
if(bd == "adafruit_feather_rp2040"):
    Fthr = True
if(bd == "arduino_nano_rp2040_connect_rp2040"):
    ANRC = True

while(not Pico and not Itsy and not QTPy and not Fthr and not ANRC):
    print("Board Not Supported.")
    time.sleep(15)
    pass
print("Board Supported.")

if(Pico == True):
    IR_RX            = board.GP2  # Pin connected to  IR receiver.
    IR_PWR           = board.GP1
    IR_PWR           = DigitalInOut(IR_PWR)
    IR_PWR.direction = Direction.OUTPUT
    IR_PWR.value     = True

    IR_TX            = board.GP26

    R_LED            = DigitalInOut(board.GP6)
    R_LED.direction  = Direction.OUTPUT
    B_LED            = DigitalInOut(board.GP7)
    B_LED.direction  = Direction.OUTPUT
    G_LED            = DigitalInOut(board.GP8)
    G_LED.direction  = Direction.OUTPUT
    R_LED.value, B_LED.value, G_LED.value = True,  True,  True
    time.sleep(0.5)
    R_LED.value, B_LED.value, G_LED.value = False, False, False

if(Itsy == True):
    IR_RX            = board.RX  # Pin connected to  IR receiver.
    IR_PWR           = board.D5
    IR_PWR           = DigitalInOut(IR_PWR)
    IR_PWR.direction = Direction.OUTPUT
    IR_PWR.value     = True

    RED   = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE  = (0, 0, 255)
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)
    IR_TX            = board.TX

    PIXEL_PIN0       = board.NEOPIXEL # NeoPixel #0
    PIXELS_NUM0      = 1              # NeoPixel #0
    PIXEL_BRIGHT0    = 0.25           # NeoPixel #0
    PIXEL_ORDER0     = neopixel.GRB   # NeoPixel #0
    status_light0    = neopixel.NeoPixel(PIXEL_PIN0, PIXELS_NUM0, brightness=PIXEL_BRIGHT0, auto_write=True,  pixel_order=PIXEL_ORDER0)
    status_light0[0] = WHITE
    PIXEL_PIN1       = board.D7       # NeoPixel #1
    PIXELS_NUM1      = 1              # NeoPixel #1
    PIXEL_BRIGHT1    = 0.25           # NeoPixel #1
    PIXEL_ORDER1     = neopixel.RGB   # NeoPixel #1  (In, +5, Gnd, Out]-flat side to Right [RGB]
    status_light1    = neopixel.NeoPixel(PIXEL_PIN1, PIXELS_NUM1, brightness=PIXEL_BRIGHT1, auto_write=True,  pixel_order=PIXEL_ORDER1)
    status_light1[0] = WHITE

if(QTPy):
    RED   = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE  = (0, 0, 255)
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)

#  Use SDA to provide +3.3 to Receiver, Use SCK to provide GND to Receiver
    IR_RX            = board.RX  # Pin connected to  IR receiver.
    IR_PWR           = board.SDA
    IR_PWR           = DigitalInOut(IR_PWR)
    IR_PWR.direction = Direction.OUTPUT
    IR_PWR.value     = True # 3.3 volts
    IR_LOW           = board.SCK
    IR_LOW           = DigitalInOut(IR_LOW)
    IR_LOW.direction = Direction.OUTPUT
    IR_LOW.value     = False # 0 volts

    IR_TX            = board.TX

    PIXEL_PIN0       = board.NEOPIXEL # NeoPixel #0
    PIXELS_NUM0      = 1              # NeoPixel #0
    PIXEL_BRIGHT0    = 0.25           # NeoPixel #0
    PIXEL_ORDER0     = neopixel.GRB   # NeoPixel #0
    status_light0    = neopixel.NeoPixel(PIXEL_PIN0, PIXELS_NUM0, brightness=PIXEL_BRIGHT0, auto_write=True,  pixel_order=PIXEL_ORDER0)
    status_light0[0] = WHITE

    pass

if(Fthr):
    pass

if not QTPy: LED              = DigitalInOut(board.LED)
if not QTPy: LED.direction    = Direction.OUTPUT

# Fuzzy pulse comparison function:
def fuzzy_pulse_compare(pulse1, pulse2, fuzzyness=0.2):
    if(Pico): R_LED.value, G_LED.value, B_LED.value = False, False, False
    if(Itsy): status_light0.fill(BLACK)
    if(Itsy): status_light1.fill(BLACK)
    if(QTPy): status_light0.fill(BLACK)
#    print(len(pulse1), len(pulse2))
    if len(pulse1) != len(pulse2):
#        print("Pulse Lengths don't match.")
        if(Pico): B_LED.value = True
        if(Itsy): status_light0.fill(BLUE)
        if(Itsy): status_light1.fill(BLUE)
        if(QTPy): status_light0.fill(BLUE)
        return False
    for i in range(len(pulse1)):
        threshold = (int(pulse1[i]) * fuzzyness)
        if abs(pulse1[i] - pulse2[i]) > threshold:
#            print(abs(pulse1[i] - pulse2[i]), i)
            if(Pico): R_LED.value = True
            if(Itsy): status_light0.fill(RED)
            if(Itsy): status_light1.fill(RED)
            if(QTPy): status_light0.fill(RED)
            return False
    if(Pico): G_LED.value = True
    if(Itsy): status_light0.fill(GREEN)
    if(Itsy): status_light1.fill(GREEN)
    if(QTPy): status_light0.fill(GREEN)
    return True

freq = 38000
duty = 32768

# Create pulse INPUT and IR decoder.
pulses  = pulseio.PulseIn(IR_RX, maxlen=200, idle_state=True)
#pulseout = pulseio.PulseOut(IR_TX, frequency=freq, duty_cycle=duty) Duplicate
decoder = adafruit_irremote.GenericDecode()

# Create a 'pwmio' OUTPUT, to send infrared signals on the IR transmitter @ 38KHz
pwm = pwmio.PWMOut(IR_TX, frequency=freq, duty_cycle=duty)
pulseout = pulseio.PulseOut(pwm)
# Create an encoder that will take numbers and turn them into NEC IR pulses
encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], zero=[562,  562], one=[562, 1687], trail=562, debug=False)
#encoder = adafruit_irremote.GenericTransmit((9500, 4500), (562, 1687), (562, 562), 562)
print("#"*80)

def make_fingerprint(data, nbits=32):
    header=[9500, 4500]
    zero=[562,  562]
    one=[562, 1687]
    trail=562
    debug=False

    bits_to_send = len(data) * 8
    if nbits is not None and nbits < bits_to_send:
        bits_to_send = nbits

    durations = array.array(
        "H", [0] * (2 + bits_to_send * 2 + (0 if trail is None else 1))
    )
    durations[0] = header[0]
    durations[1] = header[1]
    if trail is not None:
        durations[-1] = trail
    out = 2
    bit_count = 0
    for byte_index, _ in enumerate(data):
        byte_count = byte_index  # bbb
#            for i in range(7, -1, -1):
#                if (data[byte_index] & 1 << i) > 0:
    for j in range(byte_count, -1, -1): # bbb
        for i in range(7, -1, -1): # bbb
            bit = data[j] & 1 # bbb
            data[j] = data[j] >> 1 # bbb
            if(bit): # bbb

                durations[out] = one[0]
                durations[out + 1] = one[1]
            else:
                durations[out] = zero[0]
                durations[out + 1] = zero[1]
            out += 2
            bit_count += 1
            if bit_count >= bits_to_send:
                break

    if debug:
        print(durations)
    return(durations)

def key_codes():
    global Skip_1, Skip_2, Skip_3, Skip_4, Skip_5, Skip_6, Skip_7, Skip_8, Skip_9, Skip_10, SKIP30, INPUT, OK
    global AdaF_1, AdaF_2, AdaF_3, AdaF_4, AdaF_5, AdaF_6, AdaF_7, AdaF_8, AdaF_9, AdaF_10, AdaF_ES
    Skip_1  = [0xBA, 0x45, 0xFF, 0x00]
    Skip_2  = [0xB9, 0x46, 0xFF, 0x00]
    Skip_3  = [0xB8, 0x47, 0xFF, 0x00]
    Skip_4  = [0xBB, 0x44, 0xFF, 0x00]
    Skip_5  = [0xBF, 0x40, 0xFF, 0x00]
    Skip_6  = [0xBC, 0x43, 0xFF, 0x00]
    Skip_7  = [0xF8, 0x07, 0xFF, 0x00]
    Skip_8  = [0xEA, 0x15, 0xFF, 0x00]
    Skip_9  = [0xF6, 0x09, 0xFF, 0x00]
    Skip_10 = [0xE6, 0x19, 0xFF, 0x00]

    SKIP30  = [0xD0, 0x27, 0x30, 0x85] # SKIP30
    INPUT   = [0xF4, 0x0B, 0xFB, 0x04] # INPUT
    OK      = [0xE3, 0x1C, 0xFF, 0x00]

    AdaF_1  = [0xEF, 0x10, 0xBF, 0x00]
    AdaF_2  = [0xEE, 0x11, 0xBF, 0x00]
    AdaF_3  = [0xED, 0x12, 0xBF, 0x00]
    AdaF_4  = [0xEB, 0x14, 0xBF, 0x00]
    AdaF_5  = [0xEA, 0x15, 0xBF, 0x00]
    AdaF_6  = [0xE9, 0x16, 0xBF, 0x00]
    AdaF_7  = [0xE7, 0x18, 0xBF, 0x00]
    AdaF_8  = [0xE6, 0x19, 0xBF, 0x00]
    AdaF_9  = [0xE5, 0x1A, 0xBF, 0x00]
    AdaF_10 = [0xF3, 0x0C, 0xBF, 0x00]
    AdaF_ES = [0xF6, 0x09, 0xBF, 0x00]

def skip_loop(loops):
    time.sleep(1)
    if not QTPy: LED.value = True
    for xx in range(loops):
        print(loops-xx, end=" ")
#        print( SKIP30 ) # [0xD0, 0x27, 0x30, 0x85] # SKIP30
###        IR_Command = [0xD0, 0x27, 0x30, 0x85] # SKIP30
        Ky = SKIP30
        IR_Command = Ky.copy()
        print(SKIP30, IR_Command, Ky, 1)
        encoder.transmit(pulseout, reverse_bits(IR_Command), nbits=32)
        print(SKIP30, IR_Command, Ky, 2)
        time.sleep(0.5)
    print("")
    if not QTPy: LED.value = False

def reverse_bits(IN):
    OUT = [0,0,0,0]
    Ks = IN
    for y in range(8): # Reverse the bits.
        for x in range(4): # Bytes 1 thru 4
            Bit     = (Ks[x] & 1)
            Ks[x]   = (Ks[x] >> 1)
            OUT[3-x] = ((OUT[3-x] << 1) + Bit)
    return(OUT)
#####################################################################
ion = False
while ion:
    time.sleep(0.3)
    pulses.clear()
    time.sleep(0.4)
    pulses.resume()
    time.sleep(0.3)
    pulse1 = decoder.read_pulses(pulses)
    print("IR Code Received")
    print(len(pulse1))
    print(pulse1)
    print("#"*80)

while not ion:
#   Loop waiting to receive pulses.
    while True:
        key_codes()
        time.sleep(0.1)
        pulses.clear()
        time.sleep(0.1)
        pulses.resume()
        time.sleep(0.1)
        print('IR listener started...')
        # Wait for an IR Code to be detected.
        detected = decoder.read_pulses(pulses)
#        print(detected)
        print('got an IR Code...')
        # Got an IR Code, now compare.
        if fuzzy_pulse_compare(make_fingerprint(INPUT), detected, 0.5):
            print('Received correct INPUT TiVo/RCA remote control press!')
            print('Send Command to turn off the Source Select menu on the TV screen.')
            time.sleep(0.5)
            IR_Command = [0xF4, 0x0B, 0xFB, 0x04] # INPUT
            encoder.transmit(pulseout, reverse_bits(IR_Command), nbits=32)
            skip_loop(7)
        elif fuzzy_pulse_compare(make_fingerprint(OK), detected, 0.5):
            print('Received correct OK Black remote control press!')
            pass
        elif fuzzy_pulse_compare(make_fingerprint(SKIP30), detected, 0.5):
            print('Received correct SKIP30 TiVo remote control press!')
            pass
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_1), detected, 0.5)):
            print('Received Skip_1 Black remote control press!')
            skip_loop(1)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_2), detected, 0.5)):
            print('Received Skip_2 Black remote control press!')
            skip_loop(2)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_3), detected, 0.5)):
            print('Received Skip_3 Black remote control press!')
            skip_loop(3)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_4), detected, 0.5)):
            print('Received Skip_4 Black remote control press!')
            skip_loop(4)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_5), detected, 0.5)):
            print('Received Skip_5 Black remote control press!')
            skip_loop(5)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_6), detected, 0.5)):
            print('Received Skip_6 Black remote control press!')
            skip_loop(6)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_7), detected, 0.5)):
            print('Received Skip_7 Black remote control press!')
            skip_loop(7)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_8), detected, 0.5)):
            print('Received Skip_8 Black remote control press!')
            skip_loop(8)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_9), detected, 0.5)):
            print('Received Skip_9 Black remote control press!')
            skip_loop(9)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_10), detected, 0.5)):
            print('Received Skip_10 Black remote control press!')
            skip_loop(10)
        time.sleep(0.1)
        pulses.clear()
        time.sleep(0.1)
        pulses.resume()
        time.sleep(0.1)
        print("#"*80)

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Re: Variable tuple not surviving def call

by dastels on Sun Oct 17, 2021 10:26 am

Question: why are you defining the global keycode constants in a function and calling it within loop? It seems to me that you could just have those global "variable" assignments at the top level (i.e. before and outside any function).

Oddly, I don't see encoder.transmit modifying the data list passed to it.

Dave

dastels
 
Posts: 7972
Joined: Tue Oct 20, 2015 3:22 pm

Re: Variable tuple not surviving def call

by blakebr on Sun Oct 17, 2021 11:14 am

Dave,

Code fragment:
Code: Select all | TOGGLE FULL SIZE
def skip_loop(loops):
    time.sleep(1)
    if not QTPy: LED.value = True
    for xx in range(loops):
        print(loops-xx, end=" ")
#        print( SKIP30 ) # [0xD0, 0x27, 0x30, 0x85] # SKIP30
###        IR_Command = [0xD0, 0x27, 0x30, 0x85] # SKIP30
        Ky = [0xD0, 0x27, 0x30, 0x85]
        IR_Command = Ky.copy()
        print(SKIP30, IR_Command, Ky, 1)
        encoder.transmit(pulseout, reverse_bits(IR_Command), nbits=32)
        print(SKIP30, IR_Command, Ky, 2)
        time.sleep(0.5)
    print("")
    if not QTPy: LED.value = False


Output:
Code: Select all | TOGGLE FULL SIZE
2 [0, 0, 0, 0] [208, 39, 48, 133] [208, 39, 48, 133] 1
[0, 0, 0, 0] [0, 0, 0, 0] [208, 39, 48, 133] 2
1 [0, 0, 0, 0] [208, 39, 48, 133] [208, 39, 48, 133] 1
[0, 0, 0, 0] [0, 0, 0, 0] [208, 39, 48, 133] 2

IR_Command is blown away after encoder. I am very confused why the result is not the same in your test.

I have the IR codes in a def because they are being blown away.

Bruce

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Re: Variable tuple not surviving def call

by blakebr on Sun Oct 17, 2021 11:18 am

Dave,

Please note SKIP30 is defined in my def call but shows as [0,0,0,0] in the print statements.
When I moved SKIP30 and the others into main line code they showed as [0,0,0,0] in the def skip_loop.
The only way I get the proper value of SKIP30 is to hard code it.

Bruce

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Re: Variable tuple not surviving def call

by dastels on Sun Oct 17, 2021 1:01 pm

What you're saying makes sense... but what's happening doesn't.. yet.

Dave

dastels
 
Posts: 7972
Joined: Tue Oct 20, 2015 3:22 pm

Re: Variable tuple not surviving def call

by dastels on Sun Oct 17, 2021 1:04 pm

The problem might be in reverse_bits.

Try replacing
Code: Select all | TOGGLE FULL SIZE
 Ks = IN

with
Code: Select all | TOGGLE FULL SIZE
 Ks = IN.copy()

Dave

dastels
 
Posts: 7972
Joined: Tue Oct 20, 2015 3:22 pm

Re: Variable tuple not surviving def call

by blakebr on Sun Oct 17, 2021 2:06 pm

Dave,

That fixed the first problem. Thank you!

Let me look at my code and try and figure out why If I define SKIP30 at the top of my code it does not appear in my while True: loop.
I must use def key_codes: each loop.

Bruce

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Re: Variable tuple not surviving def call

by blakebr on Sun Oct 17, 2021 2:19 pm

Dave,

Found it! The problem was in def make_fingerprint(data, nbits-32):
.copy() fixed the problem there too.

Bruce

blakebr
 
Posts: 174
Joined: Tue Apr 17, 2012 6:23 pm

Please be positive and constructive with your questions and comments.