Hello,
A couple questions.
Does CircuitPython do a full compile then execute that code?
Or does it compile a token file and then interpret that file?
Or is it a straight-up interpreter?
Are the comments included in the intermediate or final code?
Why am I asking these questions???
1) I am getting different results when I use the adafruit_irremote.py vs the adafruit_irremote.mpy library.
2) I have gotten different results depending if I include an unused intrinsic library or not.
I want to be able to reliably reproduce my results before I ask more questions or provide examples.
Bruce
CircuitPython Interpreter vs compiler .py vs .mpy
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- blakebr
- Posts: 985
- Joined: Tue Apr 17, 2012 6:23 pm
- dastels
- Posts: 15819
- Joined: Tue Oct 20, 2015 3:22 pm
Re: CircuitPython Interpreter vs compiler .py vs .mpy
CircuitPython compiles to bytecode, which is what the MPY files are. They are simply bytecompiled ahead of time, saving the time and ram required at runtime (and in the constrained environment of the MCU).
Comments are skipped when the python source is tokenized. I.e. they are not present in the bytecompiled code.
What sort of different results?
Dave
Comments are skipped when the python source is tokenized. I.e. they are not present in the bytecompiled code.
What sort of different results?
Dave
- blakebr
- Posts: 985
- Joined: Tue Apr 17, 2012 6:23 pm
Re: CircuitPython Interpreter vs compiler .py vs .mpy
Dave,
The short answer: Send an IR code for SKIP30 via the encode routine to adafruit_irremote…. With .mpy I get the SKIP30 codes sent by IR modulation. With .py I get a consistent undefined code. I can get you the exact codes tomorrow.
This does not make sense at all. The .py routine should give the same results as the .mpy with the same inputs.
Are the imports compiled into the executable code or are they appended/prepended?
Bruce
The short answer: Send an IR code for SKIP30 via the encode routine to adafruit_irremote…. With .mpy I get the SKIP30 codes sent by IR modulation. With .py I get a consistent undefined code. I can get you the exact codes tomorrow.
This does not make sense at all. The .py routine should give the same results as the .mpy with the same inputs.
Are the imports compiled into the executable code or are they appended/prepended?
Bruce
- dastels
- Posts: 15819
- Joined: Tue Oct 20, 2015 3:22 pm
Re: CircuitPython Interpreter vs compiler .py vs .mpy
No executable code. Imported MPY files just get loaded. PY files get byte-compiled when it's loaded and the byte code is stored in ram (in both cases).
That is odd. they should be identical once loaded.
Dave
That is odd. they should be identical once loaded.
Dave
- blakebr
- Posts: 985
- Joined: Tue Apr 17, 2012 6:23 pm
Re: CircuitPython Interpreter vs compiler .py vs .mpy
Dave,
That is what I thought. I replaced the transistor, the transmit IR LED, the jumper wire, and the resistors. My last things was to replace the .py files with .mpy files. That is when it worked. The only examples are ones showing receiving IR codes. None transmitting codes. This could be why.
I moved from 6.3.0 .mpy to .py when I was moving from 6.3.0 to 7.0.0. Now I will move to the 7.0.0 .mpy.
Bruce
That is what I thought. I replaced the transistor, the transmit IR LED, the jumper wire, and the resistors. My last things was to replace the .py files with .mpy files. That is when it worked. The only examples are ones showing receiving IR codes. None transmitting codes. This could be why.
I moved from 6.3.0 .mpy to .py when I was moving from 6.3.0 to 7.0.0. Now I will move to the 7.0.0 .mpy.
Bruce
- blakebr
- Posts: 985
- Joined: Tue Apr 17, 2012 6:23 pm
Re: CircuitPython Interpreter vs compiler .py vs .mpy
David,
OK, I have tested this in every way I can think of:
Raspberry Pi Pico RP2040:
Using .mpy works fine with import microcontroller
Using .mpy works fine without import microcontroller
Using .py works fine with import microcontroller
Using .py works fine without import microcontroller
AdaFruit QY Py RP2040:
Using .mpy works fine with import microcontroller
Using .mpy works fine without import microcontroller
Using .py works fine with import microcontroller
Using .py works fine without import microcontroller
AdaFruit Feather RP2040:
Not built yet.
AdaFruit ItsyBitsy RP2040:
Using .mpy works fine with import microcontroller
Using .mpy works fine without import microcontroller
Using .py works fine without import microcontroller
Using .py BAD with import microcontroller ##########################
During previous troubleshooting microcontroller had to be imported to make it work. {shrug}
After 4 calls to transmit the SKIP30 codes the device stops. No error messages. Ctrl-C does not work. Ctrl-D does not work. RESET Button gets control back. Removing power gets control back. If I let it set about 45 seconds it disconnects and reconnects to my Windows 10 machine and the alert box says "USB device not recognized". Push RESET and we are back.
Transmitting the wrong code from the ItsyBitsy has not come back with the .py libraries after testing with the ,mpy libraries. Confused!
When I am using the .mpy lib I am using the entire library; except on the Raspberry Pi Pico, it has only the three listed next. The .py lib only has adafruit_esp32spi, adafruit_irremote, and neopixel.
Bruce
OK, I have tested this in every way I can think of:
Raspberry Pi Pico RP2040:
Using .mpy works fine with import microcontroller
Using .mpy works fine without import microcontroller
Using .py works fine with import microcontroller
Using .py works fine without import microcontroller
AdaFruit QY Py RP2040:
Using .mpy works fine with import microcontroller
Using .mpy works fine without import microcontroller
Using .py works fine with import microcontroller
Using .py works fine without import microcontroller
AdaFruit Feather RP2040:
Not built yet.
AdaFruit ItsyBitsy RP2040:
Using .mpy works fine with import microcontroller
Using .mpy works fine without import microcontroller
Using .py works fine without import microcontroller
Using .py BAD with import microcontroller ##########################
During previous troubleshooting microcontroller had to be imported to make it work. {shrug}
After 4 calls to transmit the SKIP30 codes the device stops. No error messages. Ctrl-C does not work. Ctrl-D does not work. RESET Button gets control back. Removing power gets control back. If I let it set about 45 seconds it disconnects and reconnects to my Windows 10 machine and the alert box says "USB device not recognized". Push RESET and we are back.
Transmitting the wrong code from the ItsyBitsy has not come back with the .py libraries after testing with the ,mpy libraries. Confused!
When I am using the .mpy lib I am using the entire library; except on the Raspberry Pi Pico, it has only the three listed next. The .py lib only has adafruit_esp32spi, adafruit_irremote, and neopixel.
Bruce
Code: Select all
'''
IR Relay and translate by B.B.Blake 10/10/2021
'''
#################### Import entrincic libraries ####################
import array
import board
import digitalio
from digitalio import DigitalInOut, Direction, Pull
import neopixel
import pulseio
import pwmio
import time
import microcontroller # I don't know why we need it, but we do.
#################### Import extrincic libraries ####################
import adafruit_esp32spi
from adafruit_esp32spi import PWMOut
import adafruit_irremote
#################### Figure out what board we have ####################
Pico, Itsy, QTPy, Fthr, ANRC = False, 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
elif(bd == "adafruit_itsybitsy_rp2040"): Itsy = True
elif(bd == "adafruit_qtpy_rp2040"): QTPy = True
elif(bd == "adafruit_feather_rp2040"): Fthr = True
elif(bd == "arduino_nano_rp2040_connect_rp2040"): ANRC = True
else:
while(True):
print("Board Not Supported.")
time.sleep(15)
pass
print("Board Supported.")
#################### Set some variables and constants ####################
freq = 38000 # IR Tone Frequency
duty = 32768 # IR Tone Duty Cycle, aka 50%
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255,255,0)
CYAN = (0,255,255)
MAGENTA = (255,0,255)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
AdaFruit = False
# IR Codes from TiVo IR transmitter, the Peanut
SKIP30 = [0xD0, 0x27, 0x30, 0x85] # SKIP30 - TiVo
INPUT = [0xF4, 0x0B, 0xFB, 0x04] # INPUT - RCA Source Select
# IR Codes from eBay IR transmitter
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]
OK = [0xE3, 0x1C, 0xFF, 0x00]
# IR Codes from AdaFruit IR transmitter
if(AdaFruit):
Skip_1 = [0xEF, 0x10, 0xBF, 0x00]
Skip_2 = [0xEE, 0x11, 0xBF, 0x00]
Skip_3 = [0xED, 0x12, 0xBF, 0x00]
Skip_4 = [0xEB, 0x14, 0xBF, 0x00]
Skip_5 = [0xEA, 0x15, 0xBF, 0x00]
Skip_6 = [0xE9, 0x16, 0xBF, 0x00]
Skip_7 = [0xE7, 0x18, 0xBF, 0x00]
Skip_8 = [0xE6, 0x19, 0xBF, 0x00]
Skip_9 = [0xE5, 0x1A, 0xBF, 0x00]
Skip_10 = [0xF3, 0x0C, 0xBF, 0x00]
OK = [0xF6, 0x09, 0xBF, 0x00] # aka ENTER/SAVE
#################### Configure things based on the board found ####################
if(Pico == True):
IR_TX = board.GP26
IR_RX = board.GP2
IR_PWR = board.GP1
IR_PWR = DigitalInOut(IR_PWR)
IR_PWR.direction = Direction.OUTPUT
IR_PWR.value = True
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, True, False
if(Itsy == True):
IR_TX = board.TX
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
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
time.sleep(0.5)
status_light0[0] = BLUE
status_light1[0] = BLUE
if(QTPy):
# Use SDA to provide +3.3 to Receiver, Use SCK to provide GND to Receiver
IR_TX = board.TX
IR_RX = board.RX
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
time.sleep(0.5)
status_light0[0] = BLUE
if(Fthr):
pass
if not QTPy: LED = DigitalInOut(board.LED)
if not QTPy: LED.direction = Direction.OUTPUT
#################### Create IR encoder and decoder ####################
# 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)
#################### Function Definitions ####################
# 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
def make_fingerprint(datain, nbits=32, debug=False):
datax = datain.copy()
header=[9500, 4500]
zero=[562, 562]
one=[562, 1687]
trail=562
bits_to_send = len(datax) * 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(datax):
byte_count = byte_index # bbb
for j in range(byte_count, -1, -1): # bbb
for i in range(7, -1, -1): # bbb
bit = datax[j] & 1 # bbb
datax[j] = datax[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 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
def reverse_bits(IN):
OUT = [0,0,0,0]
Ks = IN.copy()
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)
#################### Main program ####################
ion = False
while ion: # Just print what the IR receiver receives
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: # Perform actions depending what the IR receiver receives
# Loop waiting to receive pulses.
while True:
if(AdaFruit): IR_ = 'AdaFruit'
else: IR_ = 'eBay'
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 - Clear TV Screen
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 '+IR_+' 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 '+IR_+' remote control press!')
skip_loop(1)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_2), detected, 0.5)):
print('Received Skip_2 '+IR_+' remote control press!')
skip_loop(2)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_3), detected, 0.5)):
print('Received Skip_3 '+IR_+' remote control press!')
skip_loop(3)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_4), detected, 0.5)):
print('Received Skip_4 '+IR_+' remote control press!')
skip_loop(4)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_5), detected, 0.5)):
print('Received Skip_5 '+IR_+' remote control press!')
skip_loop(5)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_6), detected, 0.5)):
print('Received Skip_6 '+IR_+' remote control press!')
skip_loop(6)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_7), detected, 0.5)):
print('Received Skip_7 '+IR_+' remote control press!')
skip_loop(7)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_8), detected, 0.5)):
print('Received Skip_8 '+IR_+' remote control press!')
skip_loop(8)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_9), detected, 0.5)):
print('Received Skip_9 '+IR_+' remote control press!')
skip_loop(9)
elif(fuzzy_pulse_compare(make_fingerprint(Skip_10), detected, 0.5)):
print('Received Skip_10 '+IR_+' remote control press!')
skip_loop(10)
else:
print(detected)
pass
if(Pico): G_LED.value = False
if(Itsy): status_light0.fill(BLACK)
if(Itsy): status_light1.fill(BLACK)
if(QTPy): status_light0.fill(BLACK)
time.sleep(0.1)
pulses.clear()
time.sleep(0.1)
pulses.resume()
time.sleep(0.1)
print("#"*80)
- blakebr
- Posts: 985
- Joined: Tue Apr 17, 2012 6:23 pm
Re: CircuitPython Interpreter vs compiler .py vs .mpy
Dave,
If you want to see what happens.
Change Line 48 to True
Get - AdaFruit Mini Remote Control PRODUCT ID: 389
Bruce
If you want to see what happens.
Change Line 48 to True
Code: Select all
AdaFruit = True
Bruce
- dastels
- Posts: 15819
- Joined: Tue Oct 20, 2015 3:22 pm
Re: CircuitPython Interpreter vs compiler .py vs .mpy
I heard back: it's a known bug and there's an oipen issue to deal with it: https://github.com/adafruit/circuitpython/issues/5469.
Dave
Dave
Please be positive and constructive with your questions and comments.