Merge pull request #36 from adafruit/large-xfer-workaround

Restore large xfer workaround & actually report errors in pio_sm_xfer_data
This commit is contained in:
foamyguy 2025-03-17 13:47:18 -05:00 committed by GitHub
commit 0225964f24
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 61 additions and 4 deletions

View file

@ -12,6 +12,42 @@
namespace piomatter { 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() { static uint64_t monotonicns64() {
struct timespec tp; struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp); clock_gettime(CLOCK_MONOTONIC, &tp);
@ -26,7 +62,7 @@ struct piomatter_base {
piomatter_base &operator=(const piomatter_base &) = delete; piomatter_base &operator=(const piomatter_base &) = delete;
virtual ~piomatter_base() {} virtual ~piomatter_base() {}
virtual void show() = 0; virtual int show() = 0;
double fps; double fps;
}; };
@ -48,7 +84,11 @@ struct piomatter : piomatter_base {
show(); 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(); int buffer_idx = manager.get_free_buffer();
auto &bufseq = buffers[buffer_idx]; auto &bufseq = buffers[buffer_idx];
bufseq.resize(geometry.schedules.size()); bufseq.resize(geometry.schedules.size());
@ -61,6 +101,7 @@ struct piomatter : piomatter_base {
old_active_time = geometry.schedules[i].back().active_time; old_active_time = geometry.schedules[i].back().active_time;
} }
manager.put_filled_buffer(buffer_idx); manager.put_filled_buffer(buffer_idx);
return 0;
} }
~piomatter() { ~piomatter() {
@ -174,7 +215,15 @@ struct piomatter : piomatter_base {
const auto &data = cur_buf[seq_idx]; const auto &data = cur_buf[seq_idx];
auto datasize = sizeof(uint32_t) * data.size(); auto datasize = sizeof(uint32_t) * data.size();
auto dataptr = const_cast<uint32_t *>(&data[0]); auto dataptr = const_cast<uint32_t *>(&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_large(pio, sm, PIO_DIR_TO_SM, datasize,
dataptr);
if (r != 0) {
pending_error_errno.store(errno);
printf("xfer_data() returned error %d (errno=%s)\n", r,
strerror(errno));
}
t1 = monotonicns64(); t1 = monotonicns64();
if (t0 != t1) { if (t0 != t1) {
fps = 1e9 / (t1 - t0); fps = 1e9 / (t1 - t0);
@ -194,6 +243,7 @@ struct piomatter : piomatter_base {
matrix_geometry geometry; matrix_geometry geometry;
colorspace converter; colorspace converter;
std::thread blitter_thread; std::thread blitter_thread;
std::atomic<int> pending_error_errno;
}; };
} // namespace piomatter } // namespace piomatter

View file

@ -18,7 +18,14 @@ struct PyPiomatter {
py::buffer buffer; py::buffer buffer;
std::unique_ptr<piomatter::piomatter_base> matter; std::unique_ptr<piomatter::piomatter_base> 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; } double fps() const { return matter->fps; }
}; };