microbit-foundation / micropython-microbit-v2

Temporary home for MicroPython for micro:bit v2 as we stablise it before pushing upstream
MIT License
43 stars 24 forks source link

uart.read([nbytes]) triggers OS Error 11 when the buffer doesn't have the requested characters ready #45

Closed martinwork closed 3 years ago

martinwork commented 3 years ago

uart.read([nbytes]) triggers OS Error 11 when the buffer doesn't have enough characters ready.

Tested with Mu and https://github.com/microbit-foundation/micropython-microbit-v2/commit/967c0765c88f3b1fb3e765123bf0ae788bac1bb3

from microbit import *
import time

uart.init(baudrate=115200)

display.show("A")
sleep(200)

read_time0 =  time.ticks_ms()
bytes_in = uart.read(1)
read_time1 =  time.ticks_ms()

display.show("B")
sleep(200)

display.show(read_time1-read_time0)

while True:
    sleep(0)
dpgeorge commented 3 years ago

This is (kind of) expected behaviour: OS Error 11 is EAGAIN which means to try again when characters are ready.

How did it behave on micro:bit v1?

martinwork commented 3 years ago

On V1 from python.microbit.org, the sample displays A, B, 0.

On V2 with Mu and 967c076, the sample display A, sad face, OSError 11.

jaustin commented 3 years ago

So should the V2 uart code be retrying behind the scenes? Or do we think that user could should always be preared to handle EAGAIN? Could this be because V2 is faster and throws errors in cases V1 didn't?

microbit-mark commented 3 years ago

This was also reproduced by someone in https://support.microbit.org/a/tickets/43006 and in https://support.microbit.org/a/tickets/43098

V1.5 works as expected. V2 fails with OS error 11 at line 14

from microbit import *

Buf_Uart=bytearray(20)

Entete_Trame ="ABCDE"

while True :

    if uart.any() :

        #Buf_Uart=uart.read()  #error 11

        uart.readinto(Buf_Uart)  #error 11

        if chr(Buf_Uart[0]) in Entete_Trame :

            print ("Bien recu : ", chr(Buf_Uart[0]))

            if chr(Buf_Uart[0])=="F" :
                Pitch_Consigne= 1

            elif Buf_Uart[0]=="B" :
                Pitch_Consigne= -1

            elif Buf_Uart[0]=="A" :
                Pitch_Consigne= 0

        else :
            print ("Hors trame :", chr(Buf_Uart[0]))
martinwork commented 3 years ago

uart.read([nbytes]) is documented to return something or nothing within a timeout.

Read bytes. If nbytes is specified then read at most that many bytes, otherwise read as many bytes as possible.

Return value: a bytes object or None on timeout.

jaustin commented 3 years ago

So I think even if we're documentationally happy with the behaviour, I think the goal of compatibility is more important here. @dpgeorge could we please restore the V1 equivalent behaviour, or at least make them more similar?

dpgeorge commented 3 years ago

Should be fixed by ab8cff4d8b2f0170fbdd12a0b03b7b79504ecadb (now has the same behaviour as v1).

microbit-carlos commented 3 years ago

Thanks Damien! I'll mark this as fixed 🎉

@microbit-mark we need to cut a MicroPython release very very soon, which will go into the beta Python editor. When that is done could you ask the support users from https://github.com/microbit-foundation/micropython-microbit-v2/issues/45#issuecomment-775888806 to retest? We can reopen this ticket if there are still problems.