From fc7295eb74016b51c61272ef2b990734c6453382 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 09:03:44 -0500 Subject: [PATCH 1/2] Actually report errors in pio_sm_xfer_data --- src/include/piomatter/piomatter.h | 20 +++++++++++++++++--- src/pymain.cpp | 9 ++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/include/piomatter/piomatter.h b/src/include/piomatter/piomatter.h index c43f7ec..1143a18 100644 --- a/src/include/piomatter/piomatter.h +++ b/src/include/piomatter/piomatter.h @@ -26,7 +26,7 @@ struct piomatter_base { piomatter_base &operator=(const piomatter_base &) = delete; virtual ~piomatter_base() {} - virtual void show() = 0; + virtual int show() = 0; double fps; }; @@ -48,7 +48,11 @@ struct piomatter : piomatter_base { show(); } - void show() override { + int show() override { + int err = pending_error_errno.exchange(0); // we're handling this error + if (err != 0) { + return err; + } int buffer_idx = manager.get_free_buffer(); auto &bufseq = buffers[buffer_idx]; bufseq.resize(geometry.schedules.size()); @@ -61,6 +65,7 @@ struct piomatter : piomatter_base { old_active_time = geometry.schedules[i].back().active_time; } manager.put_filled_buffer(buffer_idx); + return 0; } ~piomatter() { @@ -174,7 +179,15 @@ struct piomatter : piomatter_base { const auto &data = cur_buf[seq_idx]; auto datasize = sizeof(uint32_t) * data.size(); auto dataptr = const_cast(&data[0]); - pio_sm_xfer_data(pio, sm, PIO_DIR_TO_SM, datasize, dataptr); + // returns err = rp1_ioctl.... which seems to be a negative + // errno value + int r = + pio_sm_xfer_data(pio, sm, PIO_DIR_TO_SM, datasize, dataptr); + if (r != 0) { + pending_error_errno.store(-r); + printf("xfer_data() returned error %d (%s)\n", r, + strerror(-r)); + } t1 = monotonicns64(); if (t0 != t1) { fps = 1e9 / (t1 - t0); @@ -194,6 +207,7 @@ struct piomatter : piomatter_base { matrix_geometry geometry; colorspace converter; std::thread blitter_thread; + std::atomic pending_error_errno; }; } // namespace piomatter diff --git a/src/pymain.cpp b/src/pymain.cpp index 483b2dc..053aded 100644 --- a/src/pymain.cpp +++ b/src/pymain.cpp @@ -18,7 +18,14 @@ struct PyPiomatter { py::buffer buffer; std::unique_ptr matter; - void show() { matter->show(); } + void show() { + int err = matter->show(); + if (err != 0) { + errno = err; + PyErr_SetFromErrno(PyExc_OSError); + throw py::error_already_set(); + } + } double fps() const { return matter->fps; } }; From 89dd515ae5489a9cbde3b2c1e4c9b7c62d7e2756 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 10:29:45 -0500 Subject: [PATCH 2/2] restore large xfer workaround sadly, it's not possible to gracefully switch from large to blocked xfers, further xfer ioctls fail after the first large xfer fails. --- src/include/piomatter/piomatter.h | 46 +++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/src/include/piomatter/piomatter.h b/src/include/piomatter/piomatter.h index 1143a18..4ead468 100644 --- a/src/include/piomatter/piomatter.h +++ b/src/include/piomatter/piomatter.h @@ -12,6 +12,42 @@ namespace piomatter { +static int pio_sm_xfer_data_large(PIO pio, int sm, int direction, size_t size, + uint32_t *databuf) { +#if 0 + // it would be NICE to gracefully fall back to blocked transfer, but sadly + // once the large xfer ioctl fails, future small xfers fail too. + static enum { UNKNOWN, OK, BAD } large_xfer_status = UNKNOWN; + printf("large_xfer_status=%d\n", large_xfer_status); + if (large_xfer_status != BAD) { + int r = pio_sm_xfer_data(pio, sm, direction, size, databuf); + if (large_xfer_status == UNKNOWN && r != 0) { + large_xfer_status = BAD; + fprintf(stderr, + "Transmission limit workaround engaged. May reduce quality of " + "output.\nSee https://github.com/raspberrypi/utils/issues/123 " + "for details.\n"); + } else { + if (large_xfer_status == UNKNOWN && r == 0) { + large_xfer_status = OK; + } + return r; + } + } +#endif + constexpr size_t MAX_XFER = 65532; + while (size) { + size_t xfersize = std::min(size_t{MAX_XFER}, size); + int r = pio_sm_xfer_data(pio, sm, direction, xfersize, databuf); + if (r != 0) { + return r; + } + size -= xfersize; + databuf += xfersize / sizeof(*databuf); + } + return 0; +} + static uint64_t monotonicns64() { struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); @@ -181,12 +217,12 @@ struct piomatter : piomatter_base { auto dataptr = const_cast(&data[0]); // returns err = rp1_ioctl.... which seems to be a negative // errno value - int r = - pio_sm_xfer_data(pio, sm, PIO_DIR_TO_SM, datasize, dataptr); + int r = pio_sm_xfer_data_large(pio, sm, PIO_DIR_TO_SM, datasize, + dataptr); if (r != 0) { - pending_error_errno.store(-r); - printf("xfer_data() returned error %d (%s)\n", r, - strerror(-r)); + pending_error_errno.store(errno); + printf("xfer_data() returned error %d (errno=%s)\n", r, + strerror(errno)); } t1 = monotonicns64(); if (t0 != t1) {