Russian Qt Forum
Май 04, 2024, 11:13 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 ... 22 23 [24] 25 26 ... 88   Вниз
  Печать  
Автор Тема: Создаю библиотеку для работы с последовательными портами. [УШЕЛ ИЗ ПРОЕКТА].  (Прочитано 752721 раз)
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #345 : Июнь 10, 2011, 15:07 »

Цитата: b-s-a
1. В текст надо пихать все ошибки, которые может определить пользователь класса. Думаю, это все ошибки.
Ок, но проблема в том, что это будут только ошибки вида "Last Error", т.е. пользователь,
не сможет узнать о какой-то конкретной ошибки в процессе I/O.
К примеру, при чтении произошла ошибка, её значение записалось в lastError, пользователь хочет узнать её код и вызывает
метод errorString(), но в этот момент шла и передача данных (т.е. к примеру, обмен танными FullDuplex) и тоже произошла ошибка
и в переменную lastError записалась другая ошибка. И метод errorString() возвратит последнюю зафиксированную ошибку а не ту, что была!
И получатся тогда: а какой смысл вообще в errorString() и т.п?
Ведь такая ситуация же гипотетически может произойти?

Цитата: b-s-a
2. Ничего не имею против информирования о статусах. Но, в тоже время, не вижу практически никакой реальной пользы от этого (разве только для отладки, но оно того стоит?).
Вот для того случая (о котором выше написал) я и ввел возможность "логгирования/отладки" состояний порта, чтобы можно было разобраться что и как.
И да, согласен, что из-за этой "фичи" сильно захламляется код методов и становится некрасивым.
Вот если б можно было как-то более "грациозно" решить данную проблему (даже и для отладки, как ты сказал, но с возможностью/за ненадобностью, в случае чего, вообще отключить этот функционал) было бы здорово.

Цитата: b-s-a
Все необходимые сигналы (кроме очень специфичных для COM) уже есть в QIODevice.
Ну так они и сейчас все используются.
Необходимо только договориться о введении новых и их количества (для порта):
например, достаточно ли текущего их дополнительного количества?
Код
C++ (Qt)
   void exception();
 
   void ctsChanged(bool value);
   void dsrChanged(bool value);
   void ringChanged(bool value);
 
1. Нужен ли сигнал exception()? И если да - то на какие конкретно события он будет реагировать?
2. Нужны ли сигналы cts/dsr/ringChanged()?
Т.к. Винда "из коробки" отслеживает их изменение, а *nix - нет и приходится "костылить", создавая в *nix отдельный тред или таймер для их анализа!
3. Т.к. ОС Windows поддерживает отслеживание и других событий: EV_BREAK, EV_RLSD, EV_RXFLAG, то
стоит ли предоставлять для них API для пользователя или нет?
И если да - то как это сделать: либо уведомлять тоже сигналами или как - то еще?

Цитата: b-s-a
Сокращение меня почти полностью устраивает, но вот может "направление" сократить до Input, Output и Input|Output? Пусть даже используя константы QIODevice. Но такие варианты как Off и None мне не нравятся. Я тоже рассматривал эти варианты, но пришел к выводу, что надежней использовать NoParity и NoFlowControl, так как не перепутаешь. А One/Two/Half заменить на Stop1, Stop2, Stop1_5, чтобы была однообразность с размером данных.
Ну не знаю, если уж сокращать, то склоняюсь к своему мнению и ИМХО, я б не писал: NoParity , NoFlowControl, Stop1..Stop2, т.к. галиматья получается.
А насчет Input, Output - да, можно оставить всего два типа этих енумов (вместо трех) и назвать так как ты предложил.

Цитата: b-s-a
Кстати, предлагаю использовать в качестве значений констант более юзабельные числа (благодаря чему значительно можно оптимизировать низкоуровневую работу с портом):
NoParity = 0, Even = 2, Odd = 3, Space = 4, Mark = 5
Data5 = 5, Data6 = 6, Data7 = 7, Data8 = 8
Stop1 = 1, Stop2 = 2, Stop1_5 = 3
Поясни, что ты имел ввиду?
Ведь раз мы для этих констант создаем новый тип (Enum) - то для пользователя абсолютно по барабану какие там значения,
ведь он будет работать не с 0,1,2,3 - а с типами данных.
Да и для "низкоуровневой" обработки тоже абсолютно по-барабану...
Или я недопонял твою мысль?

Цитата: b-s-a
Список скоростей можно определить путем пересечения множеств стандартных скоростей *nix и Windows:
Код
C++ (Qt)
enum BaudRate {
/*    Baud75 = 75,
   Baud110 = 110,
   Baud134 = 134,
   Baud150 = 150,
   Baud300 = 300,
   Baud600 = 600, */

   Baud1200 = 1200,
   Baud1800 = 1800,
   Baud2400 = 2400,
   Baud4800 = 4800,
   Baud9600 = 9600,
   Baud19200 = 19200,
   Baud38400 = 38400,
   Baud57600 = 57600,
   Baud115200 = 115200
};
Часть скоростей закомментировал, так как не уверен в их необходимости в реальных приложениях.
Да, я тут согласен, этим перечислениям мы можем присвоить численные значения скоростей, тем самым, мы убиваем кучу зайцев,
и реализуем всего один метод для установки скоростей, который принимает тип qint32.
И еще, я б добавил сюда Undefined = -1 значение.

Насчет сокращений линий порта - согласен.

Цитата: b-s-a
Теперь немного о улучшении функциональности.
Что сейчас происходит в случае ошибки четности/целостности пакета? А мне бы хотелось иметь возможность настраивать поведение. На мой взгляд возможны варианты:
1. Пропустить "битые данные" (т.е. "их не было")
2. Передать 0 вместо битых данных
3. Игнорировать ошибку (т.е. как-будто ошибки не было)
4. Прервать чтение прямо перед указанным "битым" байтом, выставить ошибку и специальный статус (ParityError, например). Последующее чтение примет первым байтом этот "битый" в том виде, в котором он получен (аналогично п 3) и остальные до следующего "битого", если есть.
Ну так для этого придется ввести еще в API некие дополнительные перечисления и методы и как-то их осмысленной назвать и реализовать?!
Тут я в растерянности:
с одной стороны - эти ошибки являются ошибками IO, т.е. они отличаются от других ошибок и следует ли их выделить от остальных или нет?
Хотя, в принципе, у QIODevice нет каких то интерфейсов (АПИ) для разграничения на типы/уровни ошибок и все они объединены вместе.
----

Также неясно что делать с методами типа: listBaudrate/listDataBits/listStopBits и т.п. ?

Вот, вспомнил насчет:
Цитировать
6. нестатические методы типа QMap<AbstractSerial::StopBits, QString> stopBitsMap() const. Нахрена?
Согласен, можно убрать. Просто меня просили добавить эти методы (но я так и не понял зачем они понадобились).  Улыбающийся
Эти методы нужны были для того, чтобы заполнять QComboBox, и при выборе текстового представления параметра,
в метод сразу подставлялся его тип (int/Enum)!
Кстати да, можно их оставить и сделать статическими, пригодятся.
Записан

ArchLinux x86_64 / Win10 64 bit
b-s-a
Гость
« Ответ #346 : Июнь 10, 2011, 15:48 »

К примеру, при чтении произошла ошибка, её значение записалось в lastError, пользователь хочет узнать её код и вызывает
метод errorString(), но в этот момент шла и передача данных (т.е. к примеру, обмен танными FullDuplex) и тоже произошла ошибка
и в переменную lastError записалась другая ошибка. И метод errorString() возвратит последнюю зафиксированную ошибку а не ту, что была!
И получатся тогда: а какой смысл вообще в errorString() и т.п?
Ведь такая ситуация же гипотетически может произойти?
Такое происходить не должно. Т.е. у пользователя произошел сбой, он прочитал lastError() и получил описание этого сбоя. То что у порта там в фоне работает никого не волнует. Другими словами, нужно писать обход этой ситуации.

Вот для того случая (о котором выше написал) я и ввел возможность "логгирования/отладки" состояний порта, чтобы можно было разобраться что и как.
И да, согласен, что из-за этой "фичи" сильно захламляется код методов и становится некрасивым.
Вот если б можно было как-то более "грациозно" решить данную проблему (даже и для отладки, как ты сказал, но с возможностью/за ненадобностью, в случае чего, вообще отключить этот функционал) было бы здорово.
С помощью #ifdef/#endif включать возможность детальной отладки. Все остальное запихать в qDebug()/qWarning() для неглубокой отладки конечным пользователем.

Ну так они и сейчас все используются.
Необходимо только договориться о введении новых и их количества (для порта):
например, достаточно ли текущего их дополнительного количества?
Код
C++ (Qt)
   void exception();
 
   void ctsChanged(bool value);
   void dsrChanged(bool value);
   void ringChanged(bool value);
 
1. Нужен ли сигнал exception()? И если да - то на какие конкретно события он будет реагировать?
2. Нужны ли сигналы cts/dsr/ringChanged()?
Т.к. Винда "из коробки" отслеживает их изменение, а *nix - нет и приходится "костылить", создавая в *nix отдельный тред или таймер для их анализа!
3. Т.к. ОС Windows поддерживает отслеживание и других событий: EV_BREAK, EV_RLSD, EV_RXFLAG, то
стоит ли предоставлять для них API для пользователя или нет?
И если да - то как это сделать: либо уведомлять тоже сигналами или как - то еще?
ИМХО, exception не нужен. Остальные сигналы нужны/не помешали бы. Я бы добавил сигналы реакции на break и изменения состояния линий (общего для всех входящих линий, возможно, взамен ряда отдельных сигналов).

Ну не знаю, если уж сокращать, то склоняюсь к своему мнению и ИМХО, я б не писал: NoParity , NoFlowControl,
Stop1..Stop2, т.к. галиматья получается.
Предлагаю в данном вопросе узнать мнения других участников. Может, выяснится, что мы с тобой оба не правы, и красивое решение совсем иначе выглядит. Подмигивающий

Цитата: b-s-a
Кстати, предлагаю использовать в качестве значений констант более юзабельные числа (благодаря чему значительно можно оптимизировать низкоуровневую работу с портом):
NoParity = 0, Even = 2, Odd = 3, Space = 4, Mark = 5
Data5 = 5, Data6 = 6, Data7 = 7, Data8 = 8
Stop1 = 1, Stop2 = 2, Stop1_5 = 3
Поясни, что ты имел ввиду?
Ведь раз мы для этих констант создаем новый тип (Enum) - то для пользователя абсолютно по барабану какие там значения,
ведь он будет работать не с 0,1,2,3 - а с типами данных.
Да и для "низкоуровневой" обработки тоже абсолютно по-барабану...
Или я недопонял твою мысль?
Если ты помнишь, я делал свой класс работы с портом. Так вот, там я сильно не заморачивался на конвертацию каждый раз инума в нужное число. Более того, логика работы с битом четности сильно завязана на это число: обрати внимание, что even/space четные, а odd/mark нечетные. Очень удобно использовать при эмуляции space/mark под *nix (не нужно делать лишние действия).

Цитата: b-s-a
Теперь немного о улучшении функциональности.
Что сейчас происходит в случае ошибки четности/целостности пакета? А мне бы хотелось иметь возможность настраивать поведение. На мой взгляд возможны варианты:
1. Пропустить "битые данные" (т.е. "их не было")
2. Передать 0 вместо битых данных
3. Игнорировать ошибку (т.е. как-будто ошибки не было)
4. Прервать чтение прямо перед указанным "битым" байтом, выставить ошибку и специальный статус (ParityError, например). Последующее чтение примет первым байтом этот "битый" в том виде, в котором он получен (аналогично п 3) и остальные до следующего "битого", если есть.
Ну так для этого придется ввести еще в API некие дополнительные перечисления и методы и как-то их осмысленной назвать и реализовать?!
Тут я в растерянности:
с одной стороны - эти ошибки являются ошибками IO, т.е. они отличаются от других ошибок и следует ли их выделить от остальных или нет?
Хотя, в принципе, у QIODevice нет каких то интерфейсов (АПИ) для разграничения на типы/уровни ошибок и все они объединены вместе.
Этот тип ошибок надо отделять. Но по требованию пользователя. Т.е. если он готов их обрабатывать, то пусть включает этот режим. Если нет, то и беспокоить его никто не будет. Только надо выбрать режим по умолчанию. Думаю, третий или второй.

Также неясно что делать с методами типа: listBaudrate/listDataBits/listStopBits и т.п. ?
От двух последних стоит точно отказаться. А вот с первым можно поступить так: переименовать его в standardBaudrateList() (или как-то иначе) и чтобы он возвращал стандартный для данной ОС набор скоростей.

Вот, вспомнил насчет:
Цитировать
6. нестатические методы типа QMap<AbstractSerial::StopBits, QString> stopBitsMap() const. Нахрена?
Согласен, можно убрать. Просто меня просили добавить эти методы (но я так и не понял зачем они понадобились).  Улыбающийся
Эти методы нужны были для того, чтобы заполнять QComboBox, и при выборе текстового представления параметра,
в метод сразу подставлялся его тип (int/Enum)!
Кстати да, можно их оставить и сделать статическими, пригодятся.
Я считаю подобный метод лишним. ИМХО, достаточно будет статических методов (или внешних функций) конвертации этих констант в строковое представление и обратно.
Записан
asvil
Гость
« Ответ #347 : Июнь 10, 2011, 16:59 »

Цитировать
Я считаю подобный метод лишним. ИМХО, достаточно будет статических методов (или внешних функций) конвертации этих констант в строковое представление и обратно.
Если класс Q_OBJECT, то можно Q_ENUM.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #348 : Июнь 11, 2011, 19:51 »

Ну хорошо, вот составил шаблон с обновленным API:
Код
C++ (Qt)
 
#ifndef SERIALDEVICE_H
#define SERIALDEVICE_H
 
#include <QtCore/QIODevice>
 
#ifndef QT_NO_DEBUG_STREAM
#include <QtCore/QDebug>
#endif
 
#include "../qserialdevice_global.h"
 
#ifndef SERIALDEVICE_BUFFERSIZE
#define SERIALDEVICE_BUFFERSIZE Q_INT64_C(16384)
#endif
 
 
class SerialDevicePrivate;
#if defined(QSERIALDEVICE_EXPORT)
class QSERIALDEVICE_EXPORT SerialDevice : public QIODevice
#else
class SerialDevice : public QIODevice
#endif
{
   Q_OBJECT
 
Q_SIGNALS:
   void ctsChanged(bool value);
   void dsrChanged(bool value);
   void ringChanged(bool value);
   void error(SerialDevice::SerialError);
 
public:
 
   /*! \~english
       \enum StreamDirectionFlag
       Directions baud rate that supports the class SerialDevice.
   */

   enum StreamDirectionFlag {
       Input  = 1, /*!< \~english Input baud rate. */
       Output = 2  /*!< \~english Output baud rate. */
   };
   Q_DECLARE_FLAGS(StreamDirection, StreamDirectionFlag)
 
   /*! \~english
       \enum BaudRate
       Standard types of speed serial device that supports the class SerialDevice.
   */

   enum BaudRate {
       Baud9600   = 9600,   /*!< \~english Speed 9600 bauds. */
       Baud19200  = 19200,  /*!< \~english Speed 19200 bauds. */
       Baud38400  = 38400,  /*!< \~english Speed 38400 bauds. */
       Baud57600  = 57600,  /*!< \~english Speed 57600 bauds. */
       Baud115200 = 115200, /*!< \~english Speed 115200 bauds. */
       UnknownBaudRate = -1 /*!< \~english Unknown speed. */
   };
   /*! \~english
       \enum DataBits
       Standard types of data bits serial device that supports the class SerialDevice.
   */

   enum DataBits {
       Data5 = 5, /*!< \~english 5 data bits. */
       Data6 = 6, /*!< \~english 6 data bits. */
       Data7 = 7, /*!< \~english 7 data bits. */
       Data8 = 8, /*!< \~english 8 data bits. */
       UnknownDataBits = -1 /*!< \~english Unknown data bits. */
   };
   /*! \~english
       \enum Parity
       Standard types of parity serial device that supports the class SerialDevice.
   */

   enum Parity {
       None  = 0,         /*!< \~english No parity. */
       Odd   = 2,         /*!< \~english Odd parity. */
       Even  = 3,         /*!< \~english Even parity. */
       Space = 4,         /*!< \~english Space parity. */
       Mark  = 5,         /*!< \~english Mark parity. */
       UnknownParity = -1 /*!< \~english Parity unknown. */
   };
   /*! \~english
       \enum StopBits
       Standard types of stop bits serial device that supports the class SerialDevice.
   */

   enum StopBits {
       One  = 1, /*!< \~english One stop bit. */
       Half = 3, /*!< \~english Half stop bits. */
       Two  = 2, /*!< \~english Two stop bits. */
       UnknownStopBits = -1 /*!< \~english Unknown stop bits number. */
   };
   /*! \~english
       \enum Flow
       Standard types of flow control serial device that supports the class SerialDevice.
   */

   enum Flow {
       Off,      /*!< \~english Flow control "Off". */
       Hardware, /*!< \~english Flow control "Hardware". */
       Software, /*!< \~english Flow control "Xon/Xoff". */
       UnknownFlow = -1 /*!< \~english Flow control unknown. */
   };
   /*! \~english
       \enum LineFlag
       Flags of states of the lines: CTS, DSR, DCD, RI, RTS, DTR, ST, SR
       interface serial device (see RS-232 standard, etc.).\n
       To determine the state of the desired line is necessary to impose a mask "and" of the flag line at
       the result of the method: quint16 SerialDevice::lines().
   */

   enum LineFlag {
       Le  = 0x01, /*!< \~english Line DSR (data set ready/line enable). */
       Dtr = 0x02, /*!< \~english Line DTR (data terminal ready). */
       Rts = 0x04, /*!< \~english Line RTS (request to send). */
       St  = 0x08, /*!< \~english Line Secondary TXD (transmit). */
       Sr  = 0x10, /*!< \~english Line Secondary RXD (receive.) */
       Cts = 0x20, /*!< \~english Line CTS (clear to send). */
       Dcd = 0x40, /*!< \~english Line DCD (data carrier detect). */
       Ri  = 0x80, /*!< \~english Line RNG (ring). */
       Dsr = Le    /*!< \~english Line DSR (data set ready). */
   };
   Q_DECLARE_FLAGS(Line, LineFlag)
 
   /*! \~english
       \enum BrokenDataControl
   */

   enum BrokenDataControl {
       Skip,
       PassZero,
       Ignore,
       BreakRecv
   };
 
   /*! \~english
       \enum SerialError
   */

   enum SerialError {
       /* Что тут писать? */
   };
 
   explicit SerialDevice(QObject *parent = 0);
   virtual ~SerialDevice();
 
   void setDeviceName(const QString &deviceName);
   QString deviceName() const;
 
   bool open(OpenMode mode);
   void close();
 
   //baud rate
   bool setBaudRate(qint32 baud, StreamDirection dir = Input | Output);
   qint32 baudRate(StreamDirection dir = Input | Output) const;
   //data bits
   bool setDataBits(DataBits dataBits);
   DataBits dataBits() const;
   //parity
   bool setParity(Parity parity);
   Parity parity() const;
   //stop bits
   bool setStopBits(StopBits stopBits);
   StopBits stopBits() const;
   //flow
   bool setFlowControl(Flow flow);
   Flow flowControl() const;
   // Timeouts
   void setCharIntervalTimeout(int usecs = 0);
   int charIntervalTimeout() const;
   void setTotalReadConstantTimeout(int msecs = 0);
   int totalReadConstantTimeout() const;
   //Lines statuses
   bool setDtr(bool set);
   bool setRts(bool set);
   quint16 lines();
   //Break
   bool sendBreak(int duration);
   bool setBreak(bool set);
   //
   bool flush();
   bool reset();
   //+++
   void setBrokenDataControl(BrokenDataControl control = Ignore);
   SerialError error() const;
 
   bool isSequential() const;
 
   qint64 bytesAvailable() const;
   qint64 bytesToWrite() const;
 
   bool waitForReadyRead(int msecs);
   bool waitForBytesWritten(int msecs);
 
   qint64 readBufferSize() const;
   void setReadBufferSize(qint64 size);
 
protected:
   qint64 readData(char *data, qint64 maxSize);
   qint64 writeData(const char *data, qint64 maxSize);
 
   void setSerialError(SerialError serialError);
 
   SerialDevicePrivate * const d_ptr;
 
private:
   Q_DECLARE_PRIVATE(SerialDevice)
   Q_DISABLE_COPY(SerialDevice)
};
 
Q_DECLARE_OPERATORS_FOR_FLAGS(SerialDevice::StreamDirection)
 

Конструктивные изменения и дополнения приветствуются (исходник в аттаче).
 
Записан

ArchLinux x86_64 / Win10 64 bit
b-s-a
Гость
« Ответ #349 : Июнь 13, 2011, 18:47 »

Может все-таки назвать класс SerialPort? SerialDevice это больше устройство на том конце может означать.
SerialDevice::SerialError - не много ли "Serial"? Может достаточно будет SerialDevice::Error?
Не уверен, что нужна сигнализация об ошибках. Лучше сделать метод lastError(), так как сигнал может придти хрен знает когда.
Мне продолжают симпатизировать NoParity, NoFlowControl вместо None и Off. Участники форума, включайтесь в дискуссию
Что-то стандартных скоростей мало стало. Неужели в Mac OS X так мало совместимых?
Значение Odd и Even перепутаны. Odd и Mark должны быть нечетными.
Что-то я не припомню количество стопов равное 0.5. Есть 1.5 - "one and a half".
Flow - поток, FlowControl - управление потоком. Ведь у тебя не тип Stop, а StopBits. ;-)
BrokenDataControl - что-то не нравится.
BreakRecv - а разве принято использовать сокращения в интерфейсе?
Есть методы setDtr()/setRts(), а dtr()/rts() нет. Непорядок.
Сигнал breakReceived() не вводится?
А зачем это: readBufferSize()/setReadBufferSize()?
Думаю, что PIMPL стоило помещать в приватную зону. Так же, как и setSerialError().

Замечание по стилю - virtual стоит писать у всех переопределяемых методах.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #350 : Июнь 13, 2011, 20:24 »

Цитировать
Может все-таки назвать класс SerialPort? SerialDevice это больше устройство на том конце может означать.
Не, имхо, устройство лучше. Порт- это как-то банально и такой класс уже в имеется на просторах тырнета.

Цитировать
SerialDevice::SerialError - не много ли "Serial"? Может достаточно будет SerialDevice::Error?
По аналогии с сокетами, там именно так и написано: AbstractSocket::SocketError

Цитировать
Не уверен, что нужна сигнализация об ошибках.
Пусть будет, т.к. в сокетах оно есть. Если что, то убрать не проблема.

Цитировать
Лучше сделать метод lastError(), так как сигнал может придти хрен знает когда.
Для этого будет метод: QString errorString() из QIODevice.

Цитировать
Что-то стандартных скоростей мало стало. Неужели в Mac OS X так мало совместимых?
Не угодишь, то много, то мало.. Да в принципе без разницы, потом можно будет изменить кол-во.

Цитировать
Значение Odd и Even перепутаны. Odd и Mark должны быть нечетными.
Упс, ошибся.

Цитировать
Что-то я не припомню количество стопов равное 0.5. Есть 1.5 - "one and a half".
Да, точно, гугл транслятор накосячил.

Цитировать
Flow - поток, FlowControl - управление потоком. Ведь у тебя не тип Stop, а StopBits. ;-)
Ок.

Цитировать
BrokenDataControl - что-то не нравится.
BreakRecv - а разве принято использовать сокращения в интерфейсе?
Напиши свой вариант.

Цитировать
Есть методы setDtr()/setRts(), а dtr()/rts() нет. Непорядок.
Есть метод: line() , в принципе наверное этого достаточно.

Цитировать
Сигнал breakReceived() не вводится?
А я не знаю как его отлавливать и в чем его смысл.

Цитировать
А зачем это: readBufferSize()/setReadBufferSize()?
Это хз для чего, просто в сокетах они есть. По ходу в будущем нужны для установки размера приемного буфера или что-то типа того.
Оставил дабы не отходить от оригинала ( QAbstractSocket )

Цитировать
Думаю, что PIMPL стоило помещать в приватную зону. Так же, как и setSerialError().
А почему в сокетах оно в протектед тогда?

Цитировать
Замечание по стилю - virtual стоит писать у всех переопределяемых методах.
Напиши свой вариант API со всеми нюансами для сравнения.

ЗЫ: Что-то никто больше не хочет больше обсуждать, наверное никому это не нужно.  В замешательстве
« Последнее редактирование: Июнь 13, 2011, 22:05 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
asvil
Гость
« Ответ #351 : Июнь 13, 2011, 21:28 »

Цитировать
Думаю, что PIMPL стоило помещать в приватную зону.
Долой приватные секции! Их же из наследника не получить.
Что подключаться-то? Цель запила - соответствовать qt-style. Сильно много дискуссии не надо. Ориентация на сокеты самая правильная.
Записан
b-s-a
Гость
« Ответ #352 : Июнь 14, 2011, 00:14 »

Цитировать
Ориентация на сокеты самая правильная.
Народ, не надо ориентироваться на QAbstractSocket. Я уже давал ссылку, где сами тролли говорили, что это пример крайне неудачного дизайна. В нашем случае, мы обсуждаем фактически конечный вариант класса - наследоваться от него смысла почти нет (более того, мне в голову и не приходит зачем).
Поэтому, предлагаю НЕ ДОБАВЛЯТЬ в класс то, что "зачем не знаю, но у них есть".
Цитировать
Долой приватные секции! Их же из наследника не получить.
Вот именно - не нужно наследоваться. Это класс должен быть вполне законченным, чтобы у людей даже мысли не возникало. Никто же не наследуется от QFile!
Цитировать
Не, имхо, устройство лучше. Порт- это как-то банально и такой класс уже в имеется на просторах тырнета.
Банально не банально, но соответствует содержанию больше. Разве не так?
Цитировать
По аналогии с сокетами, там именно так и написано: AbstractSocket::SocketError
И? Ну накосячили или предполагали, что могут быть у наследников еще какие варианты ошибок. Думаю, лучше сократить.
Цитировать
Пусть будет, т.к. в сокетах оно есть. Если что, то убрать не проблема.
см. выше. Кстати, добавить потом проще, чем удалить. Процесс удаления довольно мучителен: сначала надо пометить depracated, затем, через пару лет, уже можно удалять. Имхо, проще не добавлять.
Цитировать
Для этого будет метод: QString errorString() из QIODevice.
switch по QString не сделаешь. Да и ловить ошибки на языке текущего пользователя довольно забавное занятие. Я еще понимаю, пользователь выдернул USB-COM переходник. Да, в этом случае - конец работы с портом. А что делать, если возникла ошибка четности (в соответствующем режиме работы)?
Цитировать
Не угодишь, то много, то мало.. Да в принципе без разницы, потом можно будет изменить кол-во.
Просто есть какой-то оптимум. Пяток стандартных значений на мой взгляд выглядит как-то бедно. Но я не настаиваю с пеной у рта.
Цитировать
Напиши свой вариант.
По поводу BrokenDataControl: FaultPolicy, DataErrorPolicy, CorruptionPolicy...
По поводу BreakRecv: BreakReceiving, StopReceiving...
Цитировать
Есть метод: line() , в принципе наверное этого достаточно.
Тут надо как-то симметрично подходить. А то для установки состояния линий нужно одно свойство менять, а для того, чтобы узнать текущее - читать другое свойство и выгрызать из него данные.
Цитировать
Цитировать
Сигнал breakReceived() не вводится?
А я не знаю как его отлавливать и в чем его смысл.
Согласен, что-то я сам себе противоречу - если что, потом добавить можно.
Цитировать
Напиши свой вариант API со всеми нюансами для сравнения.
Не вижу смысла. Ты все написал так, как я и считаю. Но есть ряд "нюансов", на которые ИМХО следует делать иначе. Я это описал. Если же я выложу свой вариант, то мы просто поменяемся ролями - ты станешь критиком.  Смеющийся
Записан
asvil
Гость
« Ответ #353 : Июнь 14, 2011, 10:08 »

Тогда мое мнение во внимание не принимайте. Как b-s-a скажет, так хорошо.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #354 : Июнь 14, 2011, 10:18 »

Цитата: b-s-a
Я уже давал ссылку, где сами тролли говорили, что это пример крайне неудачного дизайна.
Ну так набросай удачный дизайн, а то я не вкурю (что есть "удачный"), делов то.  Подмигивающий
Есть примеры то?

ЗЫ: Ну а что скажет многоуважаемый тов. pastor ?

ЗЫЗЫ: вот, прикрепил подправленную версию АПИ (ни вашим ни нашим Улыбающийся )

И вопросы:
1. Может быть, все-таки нужно убрать сигналы:
Код:
    void ctsChanged(bool value);
    void dsrChanged(bool value);
    void ringChanged(bool value);
??
Т.к. в *nix нет нативных средств для отслеживания изменения этих сигналов и приходится использовать либо отдельный поток либо таймер с определенным интервалом времени.
Но тут дилемма: чем меньше интервал, например около 1мс (и не факт что оно будет срабатывать/опрашивать точь в точь в такой промежуток) - то растет нагрузка на процессор (причем заметно), но чем больше интервал - тем больше шанс что мы "профукаем" изменение сигнала на линии.
Так что: а есть ли смысл в них?

2. Кто-нить заполните перечисление: SerialError

В остальном АПИ, пожалуй, можно оставить так как есть.
« Последнее редактирование: Июнь 14, 2011, 11:34 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
b-s-a
Гость
« Ответ #355 : Июнь 14, 2011, 13:07 »

Тогда мое мнение во внимание не принимайте. Как b-s-a скажет, так хорошо.
Прошу не считать меня последней инстанцией.

Вот мой вариант. Название класса и пр. я изменил так, как описывал выше. Разве что SerialError оставил - в QFile тоже FileError.
Код
C++ (Qt)
/* <license header> */
 
#ifndef SERIALPORT_H
#define SERIALPORT_H
 
#include <QtCore/qiodevice.h>
 
#ifndef SERIALPORT_EXPORT
#define SERIALPORT_EXPORT
#endif
 
class SerialPortPrivate;
 
class SERIALPORT_EXPORT SerialPort : public QIODevice
{
   Q_OBJECT
   Q_PROPERTY(BaudRate baudRate READ baudRate WRITE setBaudRate)
   Q_PROPERTY(DataBits dataBits READ dataBits WRITE setDataBits)
   Q_PROPERTY(Parity parity READ parity WRITE setParity)
   Q_PROPERTY(StopBits stopBits READ stopBits WRITE setStopBits)
   Q_PROPERTY(FlowControl flowControl READ flowControl WRITE setFlowControl)
   Q_PROPERTY(DataErrorPolicy dataErrorPolicy READ dataErrorPolicy WRITE setDataErrorPolicy)
   Q_PROPERTY(bool dtr READ dtr WRITE setDtr)
   Q_PROPERTY(bool rts READ rts WRITE setRts)
   Q_PROPERTY(SerialError error READ error RESET unsetError)
   Q_ENUMS( Direction BaudRate DataBits Parity StopBits FlowControl Line DataErrorPolicy SerialError )
 
public:
 
   /*! \~english
       \enum DirectionFlag
       Directions baud rate that supports the class SerialPort.
   */

   enum Direction {
       Input  = 1, /*!< \~english Input baud rate. */
       Output = 2  /*!< \~english Output baud rate. */
   };
   Q_DECLARE_FLAGS(Directions, Direction)
 
   /*! \~english
       \enum BaudRate
       Standard types of speed serial device that supports the class SerialPort.
   */

   enum BaudRate {
       Baud1200   = 1200,   /*!< \~english Speed 1200 bauds. */
       Baud1800   = 1800,   /*!< \~english Speed 1800 bauds. */
       Baud2400   = 2400,   /*!< \~english Speed 2400 bauds. */
       Baud4800   = 4800,   /*!< \~english Speed 4800 bauds. */
       Baud9600   = 9600,   /*!< \~english Speed 9600 bauds. */
       Baud19200  = 19200,  /*!< \~english Speed 19200 bauds. */
       Baud38400  = 38400,  /*!< \~english Speed 38400 bauds. */
       Baud57600  = 57600,  /*!< \~english Speed 57600 bauds. */
       Baud115200 = 115200, /*!< \~english Speed 115200 bauds. */
       UnknownBaudRate = -1 /*!< \~english Unknown speed. */
   };
   /*! \~english
       \enum DataBits
       Standard types of data bits serial device that supports the class SerialPort.
   */

   enum DataBits {
       Data5 = 5,           /*!< \~english 5 data bits. */
       Data6 = 6,           /*!< \~english 6 data bits. */
       Data7 = 7,           /*!< \~english 7 data bits. */
       Data8 = 8,           /*!< \~english 8 data bits. */
       UnknownDataBits = -1 /*!< \~english Unknown data bits. */
   };
   /*! \~english
       \enum Parity
       Standard types of parity serial device that supports the class SerialPort.
   */

   enum Parity {
       NoParity  = 0,     /*!< \~english No parity. */
       Even  = 2,         /*!< \~english Even parity. */
       Odd   = 3,         /*!< \~english Odd parity. */
       Space = 4,         /*!< \~english Space parity. */
       Mark  = 5,         /*!< \~english Mark parity. */
       UnknownParity = -1 /*!< \~english Parity unknown. */
   };
   /*! \~english
       \enum StopBits
       Standard types of stop bits serial device that supports the class SerialPort.
   */

   enum StopBits {
       One        = 2,      /*!< \~english One stop bit. */
       OneAndHalf = 3,      /*!< \~english One and half stop bits. */
       Two        = 4,      /*!< \~english Two stop bits. */
       UnknownStopBits = -1 /*!< \~english Unknown stop bits number. */
   };
   /*! \~english
       \enum FlowControl
       Standard types of flow control serial device that supports the class SerialPort.
   */

   enum FlowControl {
       NoFlowControl,      /*!< \~english Flow control "Off". */
       Hardware,           /*!< \~english Flow control "Hardware". */
       Software,           /*!< \~english Flow control "Xon/Xoff". */
       UnknownFlow = -1    /*!< \~english Flow control unknown. */
   };
   /*! \~english
       \enum LineFlag
       Flags of states of the lines: CTS, DSR, DCD, RI, RTS, DTR, ST, SR
       interface serial device (see RS-232 standard, etc.).\n
       To determine the state of the desired line is necessary to impose a mask "and" of the flag line at
       the result of the method: quint16 SerialPort::lines().
   */

   enum Line {
       Le  = 0x01, /*!< \~english Line DSR (data set ready/line enable). */
       Dtr = 0x02, /*!< \~english Line DTR (data terminal ready). */
       Rts = 0x04, /*!< \~english Line RTS (request to send). */
       St  = 0x08, /*!< \~english Line Secondary TXD (transmit). */
       Sr  = 0x10, /*!< \~english Line Secondary RXD (receive.) */
       Cts = 0x20, /*!< \~english Line CTS (clear to send). */
       Dcd = 0x40, /*!< \~english Line DCD (data carrier detect). */
       Ri  = 0x80, /*!< \~english Line RNG (ring). */
       Dsr = Le    /*!< \~english Line DSR (data set ready). */
   };
   Q_DECLARE_FLAGS(Lines, LineFlag)
 
   /*! \~english
       \enum DataErrorPolicy
   */

   enum DataErrorPolicy {
       Skip,
       PassZero,
       Ignore,
       StopReceiving
   };
 
   /*! \~english
       \enum SerialError
   */

   enum SerialError {
       NoError,                /*!< \~english Last operation successfully finished */
       NoSuchDevice,           /*!< \~english Port open failed due to device absence in the system */
       PermissionDenied,       /*!< \~english Port open failed due to insufficient rights */
       DeviceAlreadyOpened,    /*!< \~english Port open failed due to previously opened */
       DeviceIsNotOpened,      /*!< \~english Port is not opened before processing operation */
       ParityError, /*!< \~english Last read operation stops due to parity error */
       IoError /*!< \~english Other error */
   };
 
   explicit SerialPort(QObject *parent = 0);
   explicit SerialPort(const QString &deviceName, QObject *parent = 0);
   virtual ~SerialPort();
 
   void setDeviceName(const QString &deviceName);
   QString deviceName() const;
 
   virtual bool open(OpenMode mode);
   virtual void close();
 
   bool setup(qint32 bauds, Parity parity = NoParity, StopBits stopBits = One,
              FlowControl flowControl = NoFlowControl, DataErrorPolicy policy = Ignore);
 
   SerialError error() const;
   void unsetError();
 
   bool setBaudRate(qint32 bauds, Directions dir = Input | Output);
   qint32 baudRate(Directions dir = Input | Output) const;
 
   bool setDataBits(DataBits dataBits);
   DataBits dataBits() const;
 
   bool setParity(Parity parity);
   Parity parity() const;
 
   bool setStopBits(StopBits stopBits);
   StopBits stopBits() const;
 
   bool setFlowControl(FlowControl flow);
   FlowControl flowControl() const;
 
   void setDataInterval(int usecs);
   int dataInterval() const;
 
   void setReadTimeout(int msecs); //-1 - infinity, 0 - only buffered, ...
   int readTimeout() const;
 
   bool dtr() const;
   bool rts() const;
 
   Lines lines() const;
 
   bool flush(Directions dir = Input | Output);
   virtual bool reset();
 
   void setDataErrorPolicy(DataErrorPolicy policy);
   DataErrorPolicy dataErrorPolicy() const;
 
   virtual bool isSequential() const;
 
   virtual qint64 bytesAvailable() const;
   virtual qint64 bytesToWrite() const;
 
   virtual bool waitForReadyRead(int msecs);
   virtual bool waitForBytesWritten(int msecs);
 
public Q_SLOTS:
   bool setDtr(bool set);
   bool setRts(bool set);
   bool sendBreak(int duration = 0);
   bool setBreak(bool set = true);
   bool clearBreak(bool clear = true);
 
protected:
   virtual qint64 readData(char *data, qint64 maxSize);
   virtual qint64 writeData(const char *data, qint64 maxSize);
 
private:
   const SerialPortPrivate *d_ptr;
 
   Q_DECLARE_PRIVATE(SerialPort)
   Q_DISABLE_COPY(SerialPort)
};
 
inline bool SerialPort::clearBreak(bool clear)
{ return setBreak(!clear); }
 
Q_DECLARE_OPERATORS_FOR_FLAGS(SerialPort::Directions)
Q_DECLARE_OPERATORS_FOR_FLAGS(SerialPort::Lines)
 
#endif // SERIALPORT_H
« Последнее редактирование: Июнь 14, 2011, 13:09 от b-s-a » Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #356 : Июнь 14, 2011, 20:41 »

В целом я согласен и поддерживаю идеи b-s-a. Но есть несколько предложений (поправок):

1) Удалить из списка стандартных скоростей значение 1800
2) Переместить в приват или удалить вовсе метод setup. имхо это избыточно. При open можно установить настройки порта по-умолчанию, если иные небыли установлены ранее при помощи соответствующих сеттеров.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
b-s-a
Гость
« Ответ #357 : Июнь 14, 2011, 20:57 »

2) Переместить в приват или удалить вовсе метод setup. имхо это избыточно. При open можно установить настройки порта по-умолчанию, если иные небыли установлены ранее при помощи соответствующих сеттеров.
Я его специально ввел, чтобы можно было одним методом установить все основные свойства сразу.
Можно это конечно в open запихать, но будет слишком много аргументов. Да и реализовать сложней - обработка ошибок кучу лишних условий добавит.
« Последнее редактирование: Июнь 14, 2011, 21:02 от b-s-a » Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #358 : Июнь 14, 2011, 21:44 »

>>Есть методы setDtr()/setRts(), а dtr()/rts() нет. Непорядок.
Согласен, нужно одного стиля придерживатся. а метод line() вообще не понятен.
Записан

Юра.
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #359 : Июнь 14, 2011, 21:45 »

Я его специально ввел, чтобы можно было одним методом установить все основные свойства сразу.
Можно это конечно в open запихать, но будет слишком много аргументов. Да и реализовать сложней - обработка ошибок кучу лишних условий добавит.

Нет, я не имел ввиду переносить параметры в open. Я имел ввиду следующее:

1)

Код
C++ (Qt)
bool SerialPort::open(OpenMode mode)
{
    if ("baud rate" is not set) {
        setBaudRate(Baud9600);  //set default baud rate
    }
 
    if ("parity" is not set) {
        setParity(NoParity);  //set default parity
    }
    if ("stop bits" is not set) {
        setStopBits(One);  //set default stop bits
    }
    .....
 
    //open serial port here
}


Код
C++ (Qt)
SerialPort port("foo");
port.setBaudRate(SerialPort::Baud9600);
 
if (!port.open(_mode_)) {
    // show error message
    return;
}


2)
или ввести еще один метод open с дополнительным параметром, который будет принимать скорость порта:

Код
C++ (Qt)
bool open(OpenMode mode, qint32 bauds);

В этом случае:

Код
C++ (Qt)
bool SerialPort::open(OpenMode mode, qint32 bauds)
{
    setBaudRate(bauds);
    return open(mode);
}

3)
или задать все параметры по умолчанию, например, в конструкторе. Если пользователю необходимо изменить какой-либо параметр, он дернет соответствующий сеттер:

Код
C++ (Qt)
SerialPort port("foo");
port.setBaudRate(SerialPort::Baud9600);
port.setDataBits(SerialPort::Data7);
 
if (!port.open(_mode_)) {
    // show error message
    return;
}

мне по душе 3)

В случае с setup, при изменение, допустим, DataErrorPolicy, нужно будет перечислить все значение до него, что не есть, имхо, удобно.
« Последнее редактирование: Июнь 14, 2011, 22:22 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Страниц: 1 ... 22 23 [24] 25 26 ... 88   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.283 секунд. Запросов: 23.