diff --git a/libfxlink/devices.c b/libfxlink/devices.c
index ad3d835..ae636c2 100644
--- a/libfxlink/devices.c
+++ b/libfxlink/devices.c
@@ -632,6 +632,29 @@ bool fxlink_device_start_bulk_OUT(struct fxlink_device *fdev,
     return true;
 }
 
+bool fxlink_device_has_bulk_OUT(struct fxlink_device *fdev)
+{
+    struct fxlink_comm *comm = fdev->comm;
+    return comm && comm->claimed && comm->ftransfer_OUT;
+}
+
+void fxlink_device_wait_bulk_OUT(
+    libusb_context *ctx, struct fxlink_device *fdev)
+{
+    while(fxlink_device_has_bulk_OUT(fdev))
+        libusb_handle_events(ctx);
+}
+
+bool fxlink_device_send_bulk_OUT(
+    libusb_context *ctx, struct fxlink_device *fdev,
+    char const *app, char const *type, void const *data, int size)
+{
+    if(!fxlink_device_start_bulk_OUT(fdev, app, type, data, size, false))
+        return false;
+    fxlink_device_wait_bulk_OUT(ctx, fdev);
+    return true;
+}
+
 //---
 // Polled file descriptor tracking
 //---
diff --git a/libfxlink/include/fxlink/devices.h b/libfxlink/include/fxlink/devices.h
index 0d14fd6..1fabb97 100644
--- a/libfxlink/include/fxlink/devices.h
+++ b/libfxlink/include/fxlink/devices.h
@@ -235,6 +235,21 @@ bool fxlink_device_start_bulk_OUT(struct fxlink_device *fdev,
     char const *app, char const *type, void const *data, int size,
     bool own_data);
 
+/* Check whether a device currently has an ongoing OUT transfer. */
+bool fxlink_device_has_bulk_OUT(struct fxlink_device *fdev);
+
+/* Wait for an ongoing OUT transfer to finish. If there is no such transfer
+   ongoing, this function is a no-op. */
+void fxlink_device_wait_bulk_OUT(
+   libusb_context *ctx, struct fxlink_device *fdev);
+
+/* Run an OUT transfer on the device and wait for its completion. Note that if
+   the calculator does not properly receive the data for whatever reason, this
+   function will never return. */
+bool fxlink_device_send_bulk_OUT(
+   libusb_context *ctx, struct fxlink_device *fdev,
+   char const *app, char const *type, void const *data, int size);
+
 /* Interrupt any active transfers on the device. */
 void fxlink_device_interrupt_transfers(struct fxlink_device *fdev);