Я пробовал вариант с сигналом bytesWritten(qint64), но он поступает когда данные будут переданы в системную функцию write(), и при этом число переданных байт будет всегда равно отправляемому.
Не. Планировалось так, чтобы сигнал bytesWritten() излучался именно тогда, когда данные "были отправлены" в устройство. Т.е. когда сработала аналогия select() && fdwrite (QSocketNotifier с типом Write), т.е. когда передающий буфер драйвера вновь готов к заполнению новыми данными для передачи. Да, это понятно, что реально это не означает, что если передающий буфер опустел то данные переданы в линию. В реальности все сложнее.. Но тем не менее "косвенно" можно примерно на это положиться.
Еще ты можешь попробовать использовать QSerialPort::handle() для вызова сисколла ioctl() с флагом FIONWRITE чтобы посмотреть сколько там данных в буфере драйвера еще готовы к отправке но еще не отправились и как-то поллить это. Но этот FIONWRITE поддерживается не всеми драйверами и ядрами (вроде как), да и вообще не факт что заработает.
UPD: Или можешь также попробовать использовать этот самый QSerialPort::handle() и через ioctl() установить порт в блокирующий режим (т.к. по-умолчанию он открывается в неблокирующем). Тогда уж точно функция write() будет ждать пока данные не отправятся. Но в этом случае тебе придется перенести QSerialPort в отдельный поток, т.к. сам понимаешь - блокирующий ввод/вывод - это блокирующий ввод/вывод.
В качестве второго варианта я хотел использовать функцию waitForBytesWritten(), но она, видимо, не переопределена в QSerialPort и всегда возвращает false.
Да не, вроде она должна работать. Если не работает - значит какой-то касяк в QSerialPort .