adafruit / adafruit/Adafruit_CircuitPython_PIO_UART

Unexpected .in_waiting and .written values

Open
#13 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
11
Forks
4
PR merge metrics
No merged PRs in 30d

Description

**code.py:**
```py
import time ; time.sleep(3) # wait for serial after reset
import board
import adafruit_pio_uart

def write(size, ch):
print(f'writing {size} bytes of {ch}...', end=" ")
written = u1.write(f'{size * ch}')
time.sleep(1)
print(f'{written=} {} {u2.in_waiting=}')

# two PIO UARTs, connected to each other
# PIO uart rx buffer 8-9 bytes
# u1 will write, u2 will check in_waiting

print("\nWITHOUT hardware flow control\n")
u1 = adafruit_pio_uart.UART(tx=board.GP0, rx=board.GP1)
u2 = adafruit_pio_uart.UART(tx=board.GP4, rx=board.GP5)

# write a chunk of bytes all at once
for size in (4, 5, 6, 7, 8, 9, 10):
# clear the read buffer for each new test
u2.reset_input_buffer()
print(f'busio initial {u2.in_waiting=}')
write(size, "Z")
print(f"{u2.read(16)=}")

print()
# write bytes one at a time
# clear the read buffer for each new test
u2.reset_input_buffer()
print(f'busio initial {u2.in_waiting=}')
write(4, "Y")
write(1, "X")
write(1, "W")
write(1, "V")
write(1, "U")
write(1, "T") # 9th byte
write(1, "S") # 10th byte
write(1, "R") # 11th byte
write(1, "Q") # 12th byte
print(f"{u2.read(16)=}")

u1.deinit()
u2.deinit()

print("\nWITH hardware flow control\n")
u1 = adafruit_pio_uart.UART(tx=board.GP0, rx=board.GP1, cts=board.GP2, rts=board.GP3)
u2 = adafruit_pio_uart.UART(tx=board.GP4, rx=board.GP5, cts=board.GP6, rts=board.GP7)

# write a chunk of bytes all at once
for size in (4, 5, 6, 7, 8): # 9 bytes would block
# clear the read buffer for each new test
u2.reset_input_buffer()
print(f'busio initial {u2.in_waiting=}')
write(size, "A")
print(f"{u2.read(16)=}")

print()
# write bytes one at a time
# clear the read buffer for each new test
u2.reset_input_buffer()
print(f'busio initial {u2.in_waiting=}')
write(4, "B")
write(1, "C")
write(1, "D")
write(1, "E")
write(1, "F")
# write(1, "G") # 9th byte would block
print(f"{u2.read(16)=}")
```

**code.py output:**
```
WITHOUT hardware flow control

busio initial u2.in_waiting=0
writing 4 bytes of Z... written=None () u2.in_waiting=4
busio initial u2.in_waiting=0
writing 5 bytes of Z... written=None () u2.in_waiting=5
busio initial u2.in_waiting=0
writing 6 bytes of Z... written=None () u2.in_waiting=6
busio initial u2.in_waiting=0
writing 7 bytes of Z... written=None () u2.in_waiting=7
busio initial u2.in_waiting=0
writing 8 bytes of Z... written=None () u2.in_waiting=8
busio initial u2.in_waiting=0
writing 9 bytes of Z... written=None () u2.in_waiting=8
busio initial u2.in_waiting=1
writing 10 bytes of Z... written=None () u2.in_waiting=8
u2.read(16)=bytearray(b'ZZZZZZZZZ')

busio initial u2.in_waiting=0
writing 4 bytes of Y... written=None () u2.in_waiting=4
writing 1 bytes of X... written=None () u2.in_waiting=5
writing 1 bytes of W... written=None () u2.in_waiting=6
writing 1 bytes of V... written=None () u2.in_waiting=7
writing 1 bytes of U... written=None () u2.in_waiting=8
writing 1 bytes of T... written=None () u2.in_waiting=8
writing 1 bytes of S... written=None () u2.in_waiting=8
writing 1 bytes of R... written=None () u2.in_waiting=8
writing 1 bytes of Q... written=None () u2.in_waiting=8
u2.read(16)=bytearray(b'YYYYXWVUT')

WITH hardware flow control

busio initial u2.in_waiting=0
writing 4 bytes of A... written=None () u2.in_waiting=4
busio initial u2.in_waiting=0
writing 5 bytes of A... written=None () u2.in_waiting=5
busio initial u2.in_waiting=0
writing 6 bytes of A... written=None () u2.in_waiting=6
busio initial u2.in_waiting=0
writing 7 bytes of A... written=None () u2.in_waiting=7
busio initial u2.in_waiting=0
writing 8 bytes of A... written=None () u2.in_waiting=7
u2.read(16)=bytearray(b'AAAAAAAA')

busio initial u2.in_waiting=0
writing 4 bytes of B... written=None () u2.in_waiting=4
writing 1 bytes of C... written=None () u2.in_waiting=5
writing 1 bytes of D... written=None () u2.in_waiting=6
writing 1 bytes of E... written=None () u2.in_waiting=7
writing 1 bytes of F... written=None () u2.in_waiting=7
u2.read(16)=bytearray(b'BBBBCDEF')
```

**Observations:**

1. Without flow control, 9 bytes can be written then read, even though `in_waiting` never goes above 8. Anything written after 9 bytes is lost.
2. With flow control, only 8 bytes can be written then read before write blocks, even though `in_waiting` never goes above 7. Any attempt to write after 8 bytes is blocked.
3. [Other ports](https://github.com/adafruit/circuitpython/issues/10621) also have perhaps unexpected `in_waiting` behavior, but those behave consistently and are probably attributable to SDK or hardware buffers.
4. `.written` always returns `None` instead of the number of bytes written.
5. Unlike `raspberrypi` and `espressif` `busio.UART`, PIO UART with flow control _does not_ hang the serial console when write is blocked. Control-c will interrupt the code.
6. Unlike some other ports' `busio.UART`, PIO UART read will drop extra bytes written when the buffer is full, rather than FIFO-ing the bytes in and dropping older bytes.

Contributor guide

No contributing guide indexed for this repository

Research direction

Begin with code.py and the UART API calls exercised by write(), in_waiting, read(), reset_input_buffer(), and deinit(). Reproduce both hardware-flow-control cases, compare the observed counts, blocking, dropped bytes, and None return with CircuitPython UART expectations, and define a regression check for the agreed behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.