Во-первых, надо каким-то образом хранить информацию о местах ошибок в данных. Вариантов вижу не много - только 2. Первый вариант - хранение в виде, в котором они поступают со стороны Unix (ошибки и 255 экранируются кодом 255). Второй вариант - хранить список позиций ошибок в отдельном списке (гиморней делать, но быстрее будет работать).
А зачем хранить эту информацию о местах ошибок? Т.е. ты планируешь добавить еще какой-то метод для получения списка этих позиций/мест?
Что это дает?
Не проще ли при обнаружении (при чтении) просто устанавливать в переменную ошибки последнее значение ошибки,
типа: ошибка паритета, ошибка фрейма и т.п?
В-третьих, QIODevice производит предварительное чтение данных в свой внутренний буфер. Ориентируется на bytesAvailable(). Думаю, необходимо будет отключить эту фичу, иначе будет проблема с тем видом ошибок.
А на что влияет bytesAvailable()? Оно сбрасывает ошибки или что?
Ведь можно сделать аналогично тому, как я сделал в винде, алгоритм примерно такой:
1. Если у нас установлена любая политика
не равная "игнорировать", то в методе
WinSerialPortEngine::read(char *data, qint64 len) , когда приходит время читать, параметру len присваивается 1.
И метод read() читает ровно 1 байт.
2. Есть еще виндовый нотификатор, который кроме событий EV_RXCHAR и EV_TXEMPTY, отлавливает и EV_ERR.
3. Есть еще булевая переменная m_flagErrorFromCommEvent, которая устанавливается в true при возникновении любой ошибки по евенту EV_ERR
и сбрасывается в методе WinSerialPortEngine::read() после чтения и анализа байта.
Так вот, как это все работает:
при приходе в UART "битого" байта, срабатывает сначала нотифир по евенту EV_ERR (ХЗ почему, но вроде в винде оно так получается ) и устанавливает
через SerialPortPrivate::canErrorNotification() => m_engine->processIOErrors() одновременно в переменную ошибок - тип ошибки,
а также делает m_flagErrorFromCommEvent = true.
Далее, в этом же нотифире на этот же байт срабатывает событие EV_RXCHAR и автоматом вызывается метод чтения,
через SerialPortPrivate::canReadNotification() => readFromPort() => read() => nativeRead().
Далее в nativeRead() смотрим: если политика есть "не игнорировать", то читаем один байт и далее,
смотрим: а булева переменная m_flagErrorFromCommEvent == true ?
И если да - то смотрим, а какая же политика установлена: SkipPolicy, PassZeroPolicy, StopReceivingPolicy
и в зависимости от того, какая политика - мы просто либо подменяем прочитанный байт на ноль либо еще что - то и т.п.
и в конце этого дела мы сбрасываем m_flagErrorFromCommEvent = false.
Т.к. все эти действия: нотификация по EV_ERR, а потом по EV_RXCHAR происходят в одном потоке, то по идее, они должны и
соответствующие методы выполнять по порядку, т.е. сначала фиксируется факт ошибки, а потом происходит чтение байта.
Так вот, можно было б и что-то аналогичное для *nix сделать:
аналогом нотифира ошибок сделать QSocketNotifier(), настроенный на отлов ошибок.
Но тут проблема: неизвестно, реагирует ли он на ошибки паритета и фрейма,
и если даже и реагирует - то быстрее чем такойже нотифир но на событие о приходе байта?
В-четвертых, может ввести булевый метод parityError(), который будет принимать значение true, если последняя операция чтения завершилась из-за ошибки четности.
Итак, решение я вижу следующее:
1. добавить в engine метод чтения по одному байту: char nativeGetChar(bool *ok)
2. добавить внутренний буфер чтения и список положений сбойных байтов
Попробуй, т.к. я не особо понимаю как в *nix поймать ошибки четности и паритета.
Но насчет введения nativeGetChar(), а почему прочто не выставлять в методе nativeRead() размер = 1?
3. побайтное чтение использовать только для случая StopReceivingPolicy
А почему не сделать побайтное чтение для всех политик не равных "игнорировать"?
4. способ чтения должен выбирать класс SerialPortPrivate в зависимости от настроек (если четность есть и выбрана StopReceivingPolicy, то чтение по байтам через буфер, иначе - блоками напрямую)
4. попробовать принудительно выставлять флаг Unbuffered при вызове QIODevice::open(), чтобы отключить встроенную буферизацию.
Ну так если отключить буферизацию, то отключится и асинхронное чтение и (вроде так оно сейчас там сделано, т.е. если флаг m_isBuffered == true,
то вызывается SerialPortPrivate::readFromPort ).
Я только одного не понял, зачем нужны публичные методы с пиставкой native? Логичнее было бы, чтобы они были защищенными, а публичными были без этой приставки. А то лишняя какая-то писанина получается. Понятно что engine - это и так нативная реализация под конкретную платформу...
Ок, убрал все упоминания о "native"