├── README.md ├── main.cpp ├── qt_modbus.pro ├── version.h ├── mainwindow.h ├── LICENSE ├── mainwindow.ui ├── mainwindow.cpp ├── serialport.h ├── modbuswnd.h ├── serialport.cpp ├── form.ui ├── modbuswnd.cpp └── CRC.h /README.md: -------------------------------------------------------------------------------- 1 | # qt_modbus 2 | - modbusRTU, modbus-ASCII Test Program using Qt 3 | 4 | ## Development Environment 5 | - Windows 32bit 6 | - Qt 5.6.0 7 | - Qt Creator 3.6.1 8 | - MINGW 4.8 9 | 10 | ## Features 11 | - All log data save to csv file which is 2MB size, consecutively. 12 | - All send packet save to send list, then it can reuse later. 13 | - Packet data in send list can send repeatedly. 14 | - Caculate CRC. 15 | - Transform ASCII <-> HEX. 16 | - Transform dec <-> hex10 17 | 18 | ## HowTo 19 | - load .pro file to Qt Creator 20 | 21 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mainwindow.h" 3 | #include "version.h" 4 | 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | QApplication a(argc, argv); 10 | MainWindow w; 11 | QCoreApplication::setOrganizationName("COMPANY"); 12 | QCoreApplication::setOrganizationDomain("PART"); 13 | QCoreApplication::setApplicationName(QString("%1").arg(PROGRAM_TITLE)); 14 | 15 | w.setWindowTitle(QString("%1 ver %2") 16 | .arg(PROGRAM_TITLE) 17 | .arg(VER_NUMBER)); 18 | w.show(); 19 | return a.exec(); 20 | } 21 | -------------------------------------------------------------------------------- /qt_modbus.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2014-04-09T16:06:22 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui serialport 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = ModbusRTU-ASCII Tester 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | mainwindow.cpp \ 17 | serialport.cpp \ 18 | modbuswnd.cpp 19 | 20 | HEADERS += mainwindow.h \ 21 | serialport.h \ 22 | version.h \ 23 | modbuswnd.h \ 24 | CRC.h 25 | 26 | FORMS += mainwindow.ui \ 27 | form.ui 28 | 29 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | #ifndef __VERSION_H__ 2 | #define __VERSION_H__ 3 | 4 | #define VER_MODEL "MODEL" 5 | #define VER_BOARD "BOARD" 6 | #define VER_REFERENCE "REFERENCE" 7 | #define VER_NUMBER "0.9.32.1" 8 | 9 | // 각 클래스의 디버그 메시지 on/off 를 위해 10 | // m_debugEnabled 변수를 무조건 만듬. 부모 클래스에서 setProperty 를 통해 접근 가능하게 함. 11 | 12 | 13 | // 레지스트리 세팅을 공유 해야 하므로 APP_NAME 은 실행 파일 이름과는 다르다. 14 | #define APP_NAME "ModbusRTU-ASCII Tester" 15 | 16 | #define APP_CONFIG_FILE "config.ini" 17 | 18 | 19 | #define PROGRAM_TITLE APP_NAME 20 | #define PROGRAM_WIDTH 800 21 | #define PROGRAM_HEIGHT 480 // 14인치 16:10 모니터 22 | 23 | #define KOR_TRANSLATION_FILE_PATH "data/translation/ko_kr.qm" 24 | #define ENG_TRANSLATION_FILE_PATH "data/translation/en_us.qm" 25 | 26 | 27 | #endif /* __VERSION_H__ */ 28 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "serialport.h" 16 | 17 | namespace Ui { 18 | class MainWindow; 19 | } 20 | 21 | class MainWindow : public QMainWindow 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | explicit MainWindow(QWidget *parent = 0); 27 | ~MainWindow(); 28 | void createConnection(); 29 | void closeEvent(QCloseEvent * event); 30 | 31 | signals: 32 | 33 | 34 | private: 35 | Ui::MainWindow *ui; 36 | SerialPort* m_port; 37 | 38 | 39 | public slots: 40 | void onActionAboutClicked(); 41 | void onConnected(QString str); 42 | void onDisconnected(QString str); 43 | 44 | 45 | 46 | }; 47 | 48 | #endif // MAINWINDOW_H 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Charles Park 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 787 10 | 626 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 787 29 | 21 30 | 31 | 32 | 33 | 34 | Help 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | About 44 | 45 | 46 | 47 | 48 | 49 | 50 | ModbusWnd 51 | QWidget 52 |
modbuswnd.h
53 | 1 54 |
55 |
56 | 57 | 58 |
59 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | ui->setupUi(this); 9 | createConnection(); 10 | } 11 | MainWindow::~MainWindow() 12 | { 13 | } 14 | void MainWindow::createConnection() 15 | { 16 | connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(onActionAboutClicked() )); 17 | 18 | connect(ui->widget, SIGNAL(sgConnected(QString)), this, SLOT(onConnected(QString) )); 19 | connect(ui->widget, SIGNAL(sgDisconnected(QString)), this, SLOT(onDisconnected(QString) )); 20 | 21 | 22 | 23 | setStyleSheet(" QMainWindow {" 24 | " background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ff0000, stop: 1 #ffff00); " 25 | "}" ); 26 | 27 | 28 | } 29 | 30 | void MainWindow::onActionAboutClicked() 31 | { 32 | QMessageBox::about(this, "Made by", "CharlesPark"); 33 | } 34 | 35 | void MainWindow::closeEvent(QCloseEvent * event) 36 | { 37 | ui->widget->closeEvent(event); 38 | } 39 | 40 | void MainWindow::onConnected(QString str) 41 | { 42 | setStyleSheet(" QMainWindow {" 43 | " background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #007f00, stop: 1 #aaffaa); " 44 | "}" ); 45 | 46 | ui->statusBar->showMessage(str); 47 | 48 | 49 | } 50 | void MainWindow::onDisconnected(QString str) 51 | { 52 | setStyleSheet(" QMainWindow {" 53 | " background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ff0000, stop: 1 #ffff00); " 54 | "}" ); 55 | ui->statusBar->showMessage(str); 56 | } 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /serialport.h: -------------------------------------------------------------------------------- 1 | #ifndef SERIALPORT_H 2 | #define SERIALPORT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class SerialPort : public QObject 19 | { 20 | Q_OBJECT 21 | public: 22 | explicit SerialPort(QObject *parent = 0); 23 | ~SerialPort(); 24 | 25 | void setResponseTimeout(int msec) { m_msec_responseTimeout = msec; } 26 | int responseTimeout() { return m_msec_responseTimeout; } 27 | void setT15IntervalUsec(int usec) { m_usec_interval_t15 = usec; emit sgT15IntervalChanged(); } 28 | void setT35IntervalUsec(int usec) { m_usec_interval_t35 = usec; emit sgT35IntervalChanged(); } 29 | int t15IntervalUsec() { return m_usec_interval_t15; } 30 | int t35IntervalUsec() { return m_usec_interval_t35; } 31 | void setMode(QString mode) { m_commMode = mode; } 32 | QString mode() { return m_commMode; } 33 | void setIgnoreAck(bool ignore){ m_isIgnoreAck = ignore; } 34 | bool isIgnoreAck() { return m_isIgnoreAck; } 35 | 36 | bool check_LSBUS_sum(QByteArray buf); 37 | bool check_ModbusRTU_CRC16(QByteArray buf); 38 | quint8 LSBUS_sum (QByteArray buf); 39 | quint16 ModbusRTU_CRC16 (const char *buf, quint16 wLength); 40 | 41 | private: 42 | void addTxQueue(QByteArray sendData) { m_queueSendPkt.append(sendData); emit sgSendPktQueueCountChanged();} 43 | void resetTxQueue() { m_queueSendPkt.clear(); emit sgSendPktQueueCountChanged(); } 44 | void timerEvent(QTimerEvent *event); 45 | 46 | 47 | signals: 48 | void sgReceivedErrorData(QByteArray errorData); 49 | void sgReceivedData(QByteArray recvedData); 50 | void sgSendedData(QByteArray sendPkt); 51 | 52 | void sgStateStop(); 53 | void sgInitOk(); 54 | void sgReInit(); 55 | 56 | void sgConnectingTimeout(); 57 | void sgConnected(); 58 | void sgDisconnected(); 59 | void sgTryDisconnect(); 60 | 61 | void sgError(QString error); 62 | 63 | void sgSendPktQueued(); 64 | void sgSendData(); 65 | 66 | void sgSendingComplete(); 67 | 68 | void sgReponseReceived(); 69 | void sgResponseTimeout(); 70 | 71 | void sgSendPktQueueCountChanged(); 72 | void sgT15IntervalChanged(); 73 | void sgT35IntervalChanged(); 74 | 75 | void sgReadyEntered(); 76 | void sgIgnoreAck(); 77 | 78 | public slots: 79 | void init(); 80 | 81 | void tryConnect(QString portName, quint32 baudrate , quint32 dataBits, quint32 parity, quint32 stopBits); 82 | void tryDisconnect(); 83 | void sendData(QByteArray sendData); 84 | void changeBaudrate(quint32 baudrate); 85 | void changeDataBits(quint32 dataBits); 86 | void changeParity(quint32 parity); 87 | void changeStopBits(quint32 stopBits); 88 | QString errorString(); 89 | 90 | void onBytesWritten(qint64) ; 91 | void onReadyRead(); 92 | void mainStateEntered(); 93 | void finalStateEntered(); 94 | 95 | void initEntered(); 96 | void connectedEntered(); 97 | void disconnectedEntered(); 98 | 99 | void readyEntered(); 100 | 101 | void sendingEntered(); 102 | void waitAckEntered(); 103 | 104 | void onError(QSerialPort::SerialPortError serialError); 105 | 106 | private: 107 | void createConnection(); 108 | void createState(); 109 | 110 | QSerialPort* m_port; 111 | QByteArray m_recvPkt; 112 | QList m_queueSendPkt; 113 | 114 | QByteArray m_lastSendPkt; 115 | int m_lastSendPktSize; 116 | QStateMachine* m_state; 117 | 118 | QStringList m_availablePorts; 119 | 120 | QBasicTimer* m_timerResponseTimeout; 121 | QBasicTimer* m_timerRTU35Timeout; 122 | QElapsedTimer* m_timerElapsedRTUTimeout; 123 | 124 | int m_msec_responseTimeout; 125 | qreal m_usec_interval_t15; 126 | qreal m_usec_interval_t35; 127 | 128 | QString m_commMode; 129 | bool m_isIgnoreAck; 130 | }; 131 | 132 | #endif // SERIALPORT_H 133 | -------------------------------------------------------------------------------- /modbuswnd.h: -------------------------------------------------------------------------------- 1 | #ifndef MODBUSWND_H 2 | #define MODBUSWND_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | namespace MODBUS_WND_TXRX_RESULT_COLUMNS 19 | { 20 | enum { 21 | TIMESTAMP , 22 | STATUS , 23 | MODE , 24 | RAWDATA , 25 | CRC , 26 | SLAVE_ADDR , 27 | FUNCTION , 28 | INFO , 29 | COUNT 30 | }; 31 | } 32 | namespace MODBUS_WND_TX_QUEUE_COLUMNS 33 | { 34 | enum { 35 | ENABLE , 36 | HEX , 37 | ASCII , 38 | COMMENT , 39 | COUNT 40 | }; 41 | } 42 | 43 | 44 | 45 | namespace Ui { 46 | class Form; 47 | } 48 | 49 | class ModbusWnd : public QWidget 50 | { 51 | Q_OBJECT 52 | 53 | public: 54 | explicit ModbusWnd(QWidget *parent = 0); 55 | ~ModbusWnd(); 56 | static bool check_ModbusRTU_CRC16(QByteArray buf, quint16 &result); 57 | static quint16 ModbusRTU_CRC16 (const char *buf, quint16 wLength); 58 | static quint8 LSBUS_sum(QByteArray buf); 59 | static QByteArray toHexString(QByteArray buf); 60 | 61 | void createConnection(); 62 | 63 | void resetRxCount() { m_rxCount = 0; emit sgRxCountChanged(); } 64 | void resetTxCount() { m_txCount = 0; emit sgTxCountChanged(); } 65 | void resetErrorCount() { m_errorCount = 0; emit sgErrorCountChanged(); } 66 | void addRxCount() { m_rxCount++; emit sgRxCountChanged(); } 67 | void addTxCount() { m_txCount++; emit sgTxCountChanged(); } 68 | void addErrorCount() { m_errorCount++; emit sgErrorCountChanged(); } 69 | 70 | 71 | int onParseData(QStringList &parsedData, QByteArray data); 72 | 73 | void readSettings(); 74 | 75 | void closeEvent(QCloseEvent * event); 76 | void addDataToTxRxResultModel(QStringList info); 77 | void addDataToTxPktQueueModel(QStringList parsedData); 78 | 79 | QByteArray makeRTUFrame(QByteArray slaveAddr, QByteArray functionCode, QByteArray startAddr, 80 | QByteArray numOfRegister, QByteArray byteCount, const QByteArray writeData); 81 | QByteArray makeLSBUSFrame(QByteArray slaveAddr, QByteArray functionCode, QByteArray startAddr, 82 | QByteArray numOfRegister, QByteArray byteCount, const QByteArray writeData); 83 | 84 | public slots: 85 | 86 | void onPortConnected(); 87 | void onPortDisconnected(); 88 | void onPortResponseTimeout(); 89 | 90 | void onBtnOpenClicked(); 91 | void onBtnCloseClicked(); 92 | void onRecvedData(QByteArray data); 93 | void onSendedData(QByteArray data); 94 | void onRecvedErrorData(QByteArray data); 95 | 96 | void onCmbComportTextChanged(QString str); 97 | quint32 onCmbBaudrateTextChanged(QString str); 98 | quint32 onCmbDataBitsTextChanged(QString str); 99 | quint32 onCmbParityTextChanged(QString str); 100 | quint32 onCmbStopBitsTextChanged(QString str); 101 | 102 | void onLineDecimalChanged(); 103 | void onLineHexChanged(); 104 | 105 | void onCmbCommModeCurrentTextChanged(QString str); 106 | void onCmbFunctionCurrentTextChanged(QString str); 107 | void onCmbSendCountTextChanged(QString str); 108 | void onChkAutoSendToggled(bool checked); 109 | void onChkIgnoreAckToggled(bool checked); 110 | void onLineModbusTimeoutChanged(QString str); 111 | void onLineModbusEditingFinished(); 112 | 113 | void onBtnManualSendClicked(); 114 | void onBtnScreenClearClicked(); 115 | void removeModelTxRxResult(); 116 | void onBtnRefreshClicked(); 117 | 118 | void onRxCountChanged(); 119 | void onTxCountChanged(); 120 | void onErrorCountChanged(); 121 | void onT15IntervalChanged(); 122 | void onT35IntervalChanged(); 123 | 124 | void onBtnResultFileSaveClicked(); 125 | 126 | void btnTxQueueAddClicked() ; 127 | void btnTxQueueRemoveClicked() ; 128 | void btnTxQueueUpClicked() ; 129 | void btnTxQueueDownClicked() ; 130 | void btnTxQueueFileOpenClicked() ; 131 | void btnTxqueueFileSaveClicked() ; 132 | 133 | void btnCheckSumClicked(); 134 | void btnCRC16Clicked(); 135 | void btnCRC32Clicked(); 136 | 137 | void onLineAscToHexAscInputClicked(); 138 | void onLineAscToHexHexInputClicked(); 139 | void onModelTxPktQueueDataChanged(QModelIndex topLeft, QModelIndex bottomRight); 140 | 141 | 142 | 143 | 144 | 145 | void onTimerAutoSendTimeout(); 146 | void onTimer100msTimeout(); 147 | void onModelTxResultRowInserted(const QModelIndex &parent, int first, int last); 148 | void onViewTxQueueDataSelectionCurrentRowChanged(const QModelIndex ¤t, const QModelIndex &previous); 149 | void sendModelTxPktQueue(int index ); 150 | void onReadyEntered(); 151 | 152 | signals: 153 | void sgRxCountChanged(); 154 | void sgTxCountChanged(); 155 | void sgErrorCountChanged(); 156 | void sgConnected(QString str); 157 | void sgDisconnected(QString str); 158 | 159 | private: 160 | SerialPort* m_port; 161 | QStandardItemModel* m_modelTxPktQueue; 162 | QStandardItemModel* m_modelTxRxResult; 163 | quint64 m_rxCount; 164 | quint64 m_txCount; 165 | quint64 m_errorCount; 166 | quint64 m_txRxResultMaxRow; 167 | QThread* m_threadForSerial; 168 | 169 | QTimer* m_timerAutoSend; 170 | QTimer* m_timer100msec; 171 | QRegularExpression m_reHex; 172 | 173 | quint32 m_recvedCount; 174 | quint32 m_sendedCount; 175 | quint64 m_1msCount; 176 | quint64 m_previousTimeStamp; 177 | qint64 m_recvedTimeStamp; 178 | qint64 m_sendedTimeStamp; 179 | 180 | Ui::Form *ui; 181 | }; 182 | 183 | #endif // MODBUSWND_H 184 | -------------------------------------------------------------------------------- /serialport.cpp: -------------------------------------------------------------------------------- 1 | #include "serialport.h" 2 | 3 | SerialPort::SerialPort(QObject *parent) : 4 | QObject(parent), 5 | m_port(new QSerialPort(this) ), 6 | m_timerResponseTimeout(new QBasicTimer()), 7 | m_timerRTU35Timeout(new QBasicTimer() ), 8 | m_timerElapsedRTUTimeout(new QElapsedTimer() ) 9 | { 10 | setT15IntervalUsec(750); 11 | setT35IntervalUsec(1500); 12 | m_lastSendPktSize = 0; 13 | qRegisterMetaType("QSerialPort::SerialPortError"); 14 | m_isIgnoreAck = false; 15 | } 16 | void SerialPort::init() 17 | { 18 | createConnection(); 19 | createState(); 20 | } 21 | 22 | SerialPort::~SerialPort() 23 | { 24 | if( m_timerResponseTimeout != 0 ) 25 | delete m_timerResponseTimeout; 26 | 27 | if( m_timerElapsedRTUTimeout != 0 ) 28 | delete m_timerElapsedRTUTimeout; 29 | 30 | if( m_timerRTU35Timeout != 0 ) 31 | delete m_timerRTU35Timeout; 32 | 33 | } 34 | 35 | void SerialPort::createConnection() 36 | { 37 | connect(m_port, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)) ); 38 | connect(m_port, SIGNAL(readyRead()), this, SLOT(onReadyRead()) ); 39 | connect(m_port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError) )); 40 | } 41 | 42 | 43 | void SerialPort::createState() 44 | { 45 | m_state = new QStateMachine(this); 46 | 47 | QState *mainState = new QState(m_state); 48 | QFinalState *finalState = new QFinalState(m_state); 49 | 50 | QState *init = new QState(mainState); 51 | QState *connected = new QState(mainState); 52 | QState *disconnected = new QState(mainState); 53 | 54 | QState *ready = new QState(connected); 55 | QState *sending = new QState(connected); 56 | QState *waitAck = new QState(connected); 57 | 58 | m_state->setInitialState(mainState); 59 | 60 | mainState->setInitialState(init); 61 | connected->setInitialState(ready); 62 | 63 | mainState->addTransition(this, SIGNAL(sgStateStop() ), finalState); 64 | 65 | init->addTransition(this, SIGNAL(sgInitOk() ), disconnected); 66 | init->addTransition(this, SIGNAL(sgReInit() ), init ); 67 | 68 | disconnected->addTransition(this, SIGNAL(sgConnected() ), connected ); 69 | 70 | connected->addTransition(this, SIGNAL(sgTryDisconnect() ), disconnected ); 71 | connected->addTransition(this, SIGNAL(sgError(QString) ), disconnected ); 72 | 73 | ready->addTransition(this, SIGNAL(sgSendPktQueued()), ready); 74 | ready->addTransition(this, SIGNAL(sgSendData() ), sending); 75 | 76 | sending->addTransition(this, SIGNAL(sgSendingComplete() ), waitAck); 77 | sending->addTransition(this, SIGNAL(sgIgnoreAck() ), ready); 78 | 79 | waitAck->addTransition(this, SIGNAL(sgReponseReceived() ), ready); 80 | waitAck->addTransition(this, SIGNAL(sgResponseTimeout() ), ready); 81 | 82 | connect(mainState, SIGNAL(entered()), this, SLOT(mainStateEntered() )); 83 | connect(finalState, SIGNAL(entered()), this, SLOT(finalStateEntered() )); 84 | 85 | connect(init, SIGNAL(entered()), this, SLOT(initEntered() )); 86 | connect(connected, SIGNAL(entered()), this, SLOT(connectedEntered() )); 87 | connect(disconnected, SIGNAL(entered()), this, SLOT(disconnectedEntered() )); 88 | 89 | connect(ready, SIGNAL(entered()), this, SLOT(readyEntered() )); 90 | 91 | connect(sending, SIGNAL(entered()), this, SLOT(sendingEntered() )); 92 | connect(waitAck, SIGNAL(entered()), this, SLOT(waitAckEntered() )); 93 | 94 | 95 | // history 의 경우 Entered 할수 없음. 96 | m_state->start(); 97 | } 98 | 99 | 100 | 101 | void SerialPort::mainStateEntered(){} 102 | 103 | void SerialPort::finalStateEntered() 104 | { 105 | qDebug() << Q_FUNC_INFO; 106 | } 107 | 108 | void SerialPort::initEntered() 109 | { 110 | qDebug() << Q_FUNC_INFO; 111 | emit sgInitOk(); 112 | } 113 | void SerialPort::disconnectedEntered() 114 | { 115 | qDebug() << Q_FUNC_INFO << "is port open?" << m_port->isOpen() << 116 | m_port->portName() << m_port->baudRate() << m_port->handle() << m_port->parity(); 117 | if( m_port->isOpen() == true ) 118 | { 119 | m_port->close(); 120 | } 121 | m_timerResponseTimeout->stop(); 122 | 123 | if( m_recvPkt.isEmpty() == false ) 124 | { 125 | emit sgReceivedErrorData(m_recvPkt); 126 | } 127 | m_queueSendPkt.clear(); 128 | m_recvPkt.clear(); 129 | 130 | 131 | emit sgDisconnected(); 132 | 133 | 134 | } 135 | 136 | void SerialPort::connectedEntered() 137 | { 138 | qDebug() << Q_FUNC_INFO << "is port open?" << m_port->isOpen() << 139 | m_port->portName() << 140 | m_port->baudRate() << 141 | m_port->dataBits() << 142 | m_port->parity() << 143 | m_port->stopBits() << 144 | m_port->handle() ; 145 | 146 | } 147 | 148 | void SerialPort::readyEntered() 149 | { 150 | // qDebug() << Q_FUNC_INFO; 151 | emit sgReadyEntered(); 152 | if( m_queueSendPkt.count() ) 153 | { 154 | m_lastSendPkt = m_queueSendPkt.takeFirst(); 155 | m_lastSendPktSize = m_lastSendPkt.size(); 156 | emit sgSendData(); 157 | } 158 | } 159 | 160 | void SerialPort::sendingEntered() 161 | { 162 | // qDebug() << Q_FUNC_INFO << m_lastSendPkt.toHex(); 163 | m_port->write(m_lastSendPkt); 164 | } 165 | 166 | void SerialPort::waitAckEntered() 167 | { 168 | m_timerResponseTimeout->start(m_msec_responseTimeout, Qt::PreciseTimer, this); 169 | } 170 | 171 | 172 | void SerialPort::tryConnect(QString portName, quint32 baudrate, quint32 dataBits, quint32 parity, quint32 stopBits ) 173 | { 174 | m_port->setPortName(portName); 175 | 176 | m_port->setBaudRate(baudrate); 177 | m_port->setDataBits((QSerialPort::DataBits)dataBits); 178 | m_port->setParity((QSerialPort::Parity)parity); 179 | m_port->setStopBits((QSerialPort::StopBits)stopBits); 180 | m_port->setFlowControl(QSerialPort::NoFlowControl); 181 | 182 | if( m_port->open(QIODevice::ReadWrite) == true ) 183 | { 184 | emit sgConnected(); 185 | } 186 | else 187 | { 188 | emit sgDisconnected(); 189 | } 190 | } 191 | 192 | void SerialPort::tryDisconnect() 193 | { 194 | if( m_port->isOpen() == true ) 195 | { 196 | m_port->close(); 197 | } 198 | 199 | emit sgTryDisconnect(); 200 | } 201 | 202 | void SerialPort::changeBaudrate(quint32 baudrate ) 203 | { 204 | m_port->setBaudRate(baudrate); 205 | const int multiplier = 1; 206 | if( baudrate > QSerialPort::Baud19200 ) 207 | { 208 | // defined in modbus-rtu specification. 209 | setT15IntervalUsec(750 * multiplier); 210 | setT35IntervalUsec(1500 * multiplier); 211 | // qDebug() << Q_FUNC_INFO << "interval changed to default t15" << t15IntervalUsec() << "t35" << t35IntervalUsec(); 212 | } 213 | else 214 | { 215 | // 1 byte 구성 start bit + data bits + parity bit + stopbits 216 | int oneBytesBits = (1 + 217 | m_port->dataBits() + 218 | (m_port->parity() == QSerialPort::NoParity ? 0 : 1) + 219 | (m_port->stopBits() == QSerialPort::OneStop ? 1 : 2 ) ); 220 | 221 | setT15IntervalUsec( (1000000 / (m_port->baudRate() / oneBytesBits)) * 1.5 * multiplier); 222 | setT35IntervalUsec( (1000000 / (m_port->baudRate() / oneBytesBits)) * 3.5 * multiplier); 223 | // qDebug() << Q_FUNC_INFO << "interval changed to t15" << t15IntervalUsec() << "t35" << t35IntervalUsec(); 224 | } 225 | } 226 | void SerialPort::changeDataBits(quint32 dataBits) 227 | { 228 | m_port->setDataBits((QSerialPort::DataBits) dataBits); 229 | } 230 | void SerialPort::changeParity(quint32 parity) 231 | { 232 | m_port->setParity((QSerialPort::Parity) parity ); 233 | } 234 | void SerialPort::changeStopBits(quint32 stopBits) 235 | { 236 | m_port->setStopBits((QSerialPort::StopBits) stopBits); 237 | } 238 | 239 | QString SerialPort::errorString() 240 | { 241 | return QString("[%1] [error num: %2]") 242 | .arg( m_port->errorString() ) 243 | .arg(m_port->error()); 244 | 245 | } 246 | 247 | 248 | void SerialPort::sendData(QByteArray sendData) 249 | { 250 | // qDebug() << Q_FUNC_INFO << sendData.toHex(); 251 | 252 | if( sendData.size() ) 253 | { 254 | addTxQueue(sendData); 255 | emit sgSendPktQueued(); 256 | } 257 | } 258 | 259 | void SerialPort::onError(QSerialPort::SerialPortError serialError) 260 | { 261 | if( serialError == QSerialPort::NoError || 262 | serialError == QSerialPort::ParityError || 263 | serialError == QSerialPort::FramingError || 264 | serialError == QSerialPort::UnknownError ) 265 | return; 266 | 267 | qDebug() << Q_FUNC_INFO << "errorNumber" << serialError << 268 | m_port->portName() << 269 | m_port->baudRate() << 270 | m_port->dataBits() << 271 | m_port->stopBits() << 272 | m_port->parity() << 273 | m_port->handle() << 274 | m_port->errorString(); 275 | 276 | emit sgError(m_port->errorString() ); 277 | } 278 | 279 | void SerialPort::onBytesWritten(qint64 count) 280 | { 281 | m_lastSendPktSize -= count; 282 | if( m_lastSendPktSize == 0) 283 | { 284 | // qDebug() << Q_FUNC_INFO << m_lastSendPkt.toHex(); 285 | emit sgSendedData(m_lastSendPkt); 286 | if( isIgnoreAck() == true ) 287 | { 288 | emit sgIgnoreAck(); 289 | } 290 | else{ 291 | emit sgSendingComplete(); 292 | } 293 | 294 | } 295 | } 296 | 297 | 298 | void SerialPort::onReadyRead() 299 | { 300 | //한 바이트와 한바이트 사이의 시간을 측정하기에는 OS 상에서는 역부족이므로 해당 루틴 넣지 않도록 301 | // QSerialPort 의 경우 async 방식만 사용해야함 -> 같은 쓰레드에서만 동작하도록 구성되어 있기 때문 302 | 303 | QByteArray buffer; 304 | while(m_port->bytesAvailable()) 305 | { 306 | if( m_timerResponseTimeout->isActive() == true ) 307 | m_timerResponseTimeout->start(m_msec_responseTimeout, Qt::PreciseTimer, this); 308 | buffer = m_port->read(1); 309 | 310 | if( m_commMode == "LSBUS") 311 | { 312 | 313 | if( buffer.at(0) == 0x05 && buffer.at(0) == 0x06 || buffer.at(0) == 0x15 ) 314 | { 315 | if( m_recvPkt.isEmpty() == false ) 316 | { 317 | emit sgReceivedErrorData(m_recvPkt); 318 | m_recvPkt.clear(); 319 | } 320 | } 321 | 322 | m_recvPkt += buffer; 323 | 324 | if( buffer.at(0) == 0x04 ) 325 | { 326 | m_timerResponseTimeout->stop(); 327 | 328 | if(check_LSBUS_sum(m_recvPkt) == true ) 329 | { 330 | emit sgReponseReceived(); 331 | emit sgReceivedData(m_recvPkt); 332 | } 333 | else 334 | { 335 | emit sgReponseReceived(); 336 | emit sgReceivedErrorData(m_recvPkt); 337 | } 338 | m_timerResponseTimeout->stop(); 339 | m_recvPkt.clear(); 340 | } 341 | } 342 | else // for RTU 343 | { 344 | m_recvPkt += buffer; 345 | 346 | if(check_ModbusRTU_CRC16(m_recvPkt) == true ) 347 | { 348 | emit sgReponseReceived(); 349 | emit sgReceivedData(m_recvPkt); 350 | m_timerResponseTimeout->stop(); 351 | m_recvPkt.clear(); 352 | } 353 | else if( m_recvPkt.count() > 255 ) 354 | { 355 | emit sgReponseReceived(); 356 | emit sgReceivedErrorData(m_recvPkt); 357 | m_timerResponseTimeout->stop(); 358 | m_recvPkt.clear(); 359 | } 360 | 361 | 362 | // qDebug() << buffer.toHex() << m_timerElapsedRTUTimeout->elapsed(); 363 | // m_timerElapsedRTUTimeout->start(); 364 | // m_timerRTU35Timeout->start( qCeil( m_usec_interval_t35 / 1000), Qt::PreciseTimer, this ); 365 | 366 | } 367 | } 368 | 369 | } 370 | 371 | void SerialPort::timerEvent(QTimerEvent *event) 372 | { 373 | if ( event->timerId() == m_timerResponseTimeout->timerId()) 374 | { 375 | // qDebug() << Q_FUNC_INFO << m_msec_responseTimeout << m_recvPkt.toHex(); 376 | m_timerResponseTimeout->stop(); 377 | m_timerRTU35Timeout->stop(); 378 | 379 | emit sgResponseTimeout(); 380 | if( m_recvPkt.isEmpty() == false ) 381 | { 382 | emit sgReceivedErrorData(m_recvPkt); 383 | m_recvPkt.clear(); 384 | } 385 | } 386 | else if ( event->timerId() == m_timerRTU35Timeout->timerId()) 387 | { 388 | // qDebug() << m_recvPkt.toHex() << m_timerElapsedRTUTimeout->elapsed(); 389 | m_timerResponseTimeout->stop(); 390 | m_timerRTU35Timeout->stop(); 391 | 392 | } 393 | else { 394 | QObject::timerEvent(event); 395 | } 396 | } 397 | 398 | 399 | bool SerialPort::check_ModbusRTU_CRC16(QByteArray buf) 400 | { 401 | if( buf.size() >= 4 ) 402 | { 403 | QByteArray srcCrc = buf.mid(buf.size()-2, 2); 404 | QByteArray dstCrc = ""; 405 | quint16 crc = ModbusRTU_CRC16(buf.constData(), buf.size() -2 ); 406 | dstCrc = QByteArray::fromRawData((char*)&crc, 2); 407 | 408 | if( srcCrc == dstCrc ) 409 | { 410 | return true; 411 | } 412 | else 413 | { 414 | return false; 415 | } 416 | } 417 | return false; 418 | } 419 | bool SerialPort::check_LSBUS_sum(QByteArray buf) 420 | { 421 | if( buf.size() >= 2 ) 422 | { 423 | if( buf.left(1).at(0) == 0x05 || 424 | buf.left(1).at(0) == 0x06 || 425 | buf.left(1).at(0) == 0x15) 426 | { 427 | if( buf.right(1).at(0) == 0x04 ) 428 | { 429 | QByteArray srcCrc = buf.right(3).left(2); 430 | QByteArray dstCrc = ""; 431 | quint8 sum = LSBUS_sum(buf.mid(0, buf.count() - 3)); 432 | dstCrc = QByteArray::fromRawData((char*)&sum, 1).toHex().toUpper(); 433 | 434 | // qDebug() << buf << buf.toHex() << srcCrc.toHex() << dstCrc.toHex(); 435 | if( srcCrc == dstCrc ) 436 | { 437 | return true; 438 | } 439 | else 440 | { 441 | return false; 442 | } 443 | } 444 | 445 | } 446 | 447 | } 448 | return false; 449 | } 450 | quint8 SerialPort::LSBUS_sum (QByteArray buf) 451 | { 452 | quint8 sum = 0x00; 453 | for ( int i = 1 ; i < buf.count(); i ++ ) 454 | { 455 | // qDebug() << QByteArray(1, buf.at(i)).toHex(); 456 | sum += buf.at(i); 457 | } 458 | // qDebug() << "sum" << QByteArray(1, sum).toHex(); 459 | return sum; 460 | } 461 | 462 | 463 | quint16 SerialPort::ModbusRTU_CRC16 (const char *buf, quint16 wLength) 464 | { 465 | static const quint16 wCRCTable[] = { 466 | 0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241, 467 | 0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440, 468 | 0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40, 469 | 0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841, 470 | 0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40, 471 | 0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41, 472 | 0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641, 473 | 0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040, 474 | 0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240, 475 | 0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441, 476 | 0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41, 477 | 0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840, 478 | 0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41, 479 | 0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40, 480 | 0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640, 481 | 0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041, 482 | 0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240, 483 | 0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441, 484 | 0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41, 485 | 0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840, 486 | 0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41, 487 | 0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40, 488 | 0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640, 489 | 0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041, 490 | 0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241, 491 | 0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440, 492 | 0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40, 493 | 0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841, 494 | 0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40, 495 | 0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41, 496 | 0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641, 497 | 0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 }; 498 | 499 | quint8 nTemp; 500 | quint16 CRC16 = 0xFFFF; 501 | 502 | while (wLength--) 503 | { 504 | nTemp = *buf++ ^ CRC16; 505 | CRC16 >>= 8; 506 | CRC16 ^= wCRCTable[nTemp]; 507 | } 508 | return CRC16; 509 | } // End: CRC16 510 | 511 | 512 | -------------------------------------------------------------------------------- /form.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 751 10 | 796 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 0 32 | 33 | 34 | 35 | 36 | 37 | false 38 | 39 | 40 | 41 | Send repeatedly 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | false 52 | 53 | 54 | 55 | Qt::Horizontal 56 | 57 | 58 | 59 | 68 60 | 10 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 0 70 | 0 71 | 72 | 73 | 74 | 75 | false 76 | 77 | 78 | 79 | Interval(ms) 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 60 88 | 0 89 | 90 | 91 | 92 | 93 | 60 94 | 16777215 95 | 96 | 97 | 98 | 99 | false 100 | 101 | 102 | 103 | 1000 104 | 105 | 106 | 7 107 | 108 | 109 | 4 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | false 118 | 119 | 120 | 121 | Qt::Horizontal 122 | 123 | 124 | 125 | 68 126 | 10 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | false 136 | 137 | 138 | 139 | Force send(ignore response) 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | false 152 | 153 | 154 | 155 | Qt::Vertical 156 | 157 | 158 | 159 | 160 | false 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 0 169 | 0 170 | 171 | 172 | 173 | 174 | 0 175 | 0 176 | 177 | 178 | 179 | 180 | 16777215 181 | 16777215 182 | 183 | 184 | 185 | 186 | false 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | false 196 | 197 | 198 | 199 | Transmit 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | false 208 | 209 | 210 | 211 | Move up 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | false 220 | 221 | 222 | 223 | Move down 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | false 232 | 233 | 234 | 235 | Delete 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | false 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | false 253 | 254 | 255 | 256 | true 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | false 267 | 268 | 269 | 270 | file save 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | false 279 | 280 | 281 | 282 | AutoScroll 283 | 284 | 285 | true 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | false 294 | 295 | 296 | 297 | Qt::Vertical 298 | 299 | 300 | 301 | 20 302 | 40 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 0 312 | 0 313 | 314 | 315 | 316 | 317 | false 318 | 319 | 320 | 321 | Info 322 | 323 | 324 | 325 | 326 | 327 | Bytes/s 328 | 329 | 330 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 331 | 332 | 333 | 334 | 335 | 336 | 337 | 0 338 | 339 | 340 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 0 349 | 0 350 | 351 | 352 | 353 | 354 | false 355 | 356 | 357 | 358 | TX Cnt 359 | 360 | 361 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | false 370 | 371 | 372 | 373 | 0 374 | 375 | 376 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 0 385 | 0 386 | 387 | 388 | 389 | 390 | false 391 | 392 | 393 | 394 | RX Cnt 395 | 396 | 397 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | false 406 | 407 | 408 | 409 | 0 410 | 411 | 412 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 0 421 | 0 422 | 423 | 424 | 425 | 426 | false 427 | 428 | 429 | 430 | Error Cnt 431 | 432 | 433 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | false 442 | 443 | 444 | 445 | 0 446 | 447 | 448 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | false 460 | 461 | 462 | 463 | clear 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 0 481 | 0 482 | 483 | 484 | 485 | 486 | 0 487 | 0 488 | 489 | 490 | 491 | 492 | 16777215 493 | 16777215 494 | 495 | 496 | 497 | 498 | false 499 | 500 | 501 | 502 | 0 503 | 504 | 505 | 506 | Setting 507 | 508 | 509 | 510 | 511 | 512 | 513 | false 514 | 515 | 516 | 517 | 518 | RTU 519 | 520 | 521 | 522 | 523 | LSBUS 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | false 533 | 534 | 535 | 536 | Qt::Vertical 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | false 547 | 548 | 549 | 550 | Dec: 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | false 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 0 572 | 0 573 | 574 | 575 | 576 | 577 | false 578 | 579 | 580 | 581 | Addr(Hex) 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 0 590 | 0 591 | 592 | 593 | 594 | 595 | 60 596 | 0 597 | 598 | 599 | 600 | 601 | 60 602 | 16777215 603 | 604 | 605 | 606 | 607 | false 608 | 609 | 610 | 611 | 0001 612 | 613 | 614 | 4 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 0 627 | 0 628 | 629 | 630 | 631 | 632 | false 633 | 634 | 635 | 636 | Count(Hex) 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 0 645 | 0 646 | 647 | 648 | 649 | 650 | false 651 | 652 | 653 | 654 | true 655 | 656 | 657 | 16 658 | 659 | 660 | 661 | 01 662 | 663 | 664 | 665 | 666 | 02 667 | 668 | 669 | 670 | 671 | 03 672 | 673 | 674 | 675 | 676 | 04 677 | 678 | 679 | 680 | 681 | 05 682 | 683 | 684 | 685 | 686 | 06 687 | 688 | 689 | 690 | 691 | 07 692 | 693 | 694 | 695 | 696 | 08 697 | 698 | 699 | 700 | 701 | 09 702 | 703 | 704 | 705 | 706 | 0A 707 | 708 | 709 | 710 | 711 | 0B 712 | 713 | 714 | 715 | 716 | 0C 717 | 718 | 719 | 720 | 721 | 0D 722 | 723 | 724 | 725 | 726 | 0E 727 | 728 | 729 | 730 | 731 | 0F 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | false 745 | 746 | 747 | 748 | Hex 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | false 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | false 768 | 769 | 770 | 771 | Add SendList 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | false 782 | 783 | 784 | 785 | Write Data(Hex) 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | false 794 | 795 | 796 | 797 | 0000 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | false 808 | 809 | 810 | 811 | Apply Addr -1 ? 812 | 813 | 814 | true 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 0 825 | 0 826 | 827 | 828 | 829 | 830 | false 831 | 832 | 833 | 834 | DeviceID(Hex) 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 0 843 | 0 844 | 845 | 846 | 847 | 848 | 30 849 | 0 850 | 851 | 852 | 853 | 854 | 60 855 | 16777215 856 | 857 | 858 | 859 | 860 | false 861 | 862 | 863 | 864 | 01 865 | 866 | 867 | 2 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 0 880 | 0 881 | 882 | 883 | 884 | 885 | false 886 | 887 | 888 | 889 | Cmd 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 0 898 | 0 899 | 900 | 901 | 902 | 903 | 200 904 | 0 905 | 906 | 907 | 908 | 909 | false 910 | 911 | 912 | 913 | true 914 | 915 | 916 | 10 917 | 918 | 919 | 920 | 03 (Read Holding Register) 921 | 922 | 923 | 924 | 925 | 04 (Read Input Register) 926 | 927 | 928 | 929 | 930 | 06 (Write Single Register) 931 | 932 | 933 | 934 | 935 | 10 (Write Multiple Register) 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | CRC Calc 947 | 948 | 949 | 950 | 951 | 952 | CRC16 953 | 954 | 955 | 956 | 957 | 958 | 959 | 0 960 | 961 | 962 | 963 | 964 | Result Hex: 0x 965 | 966 | 967 | 968 | 969 | 970 | 971 | true 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | Result ASCII: 983 | 984 | 985 | 986 | 987 | 988 | 989 | true 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | Hex In 1001 | 1002 | 1003 | true 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | ASCII In 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 20 1019 | 16777215 1020 | 1021 | 1022 | 1023 | C 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | CheckSum 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | CRC32 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | ASC to Hex 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | Ascii Input 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 0 1067 | 0 1068 | 1069 | 1070 | 1071 | 1072 | 30 1073 | 16777215 1074 | 1075 | 1076 | 1077 | Clr 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 66 1093 | 0 1094 | 1095 | 1096 | 1097 | Hex Input 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 30 1106 | 16777215 1107 | 1108 | 1109 | 1110 | Clr 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 0 1128 | 0 1129 | 1130 | 1131 | 1132 | 1133 | 16777215 1134 | 16777215 1135 | 1136 | 1137 | 1138 | 1139 | false 1140 | 1141 | 1142 | 1143 | Comm Option 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 100 1153 | 16777215 1154 | 1155 | 1156 | 1157 | 1158 | false 1159 | 1160 | 1161 | 1162 | Open 1163 | 1164 | 1165 | false 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | false 1173 | 1174 | 1175 | 1176 | 100 1177 | 16777215 1178 | 1179 | 1180 | 1181 | 1182 | false 1183 | 1184 | 1185 | 1186 | Close 1187 | 1188 | 1189 | false 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | false 1202 | 1203 | 1204 | 1205 | Timeout(msec) 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 0 1214 | 0 1215 | 1216 | 1217 | 1218 | 1219 | 50 1220 | 0 1221 | 1222 | 1223 | 1224 | 1225 | 100 1226 | 16777215 1227 | 1228 | 1229 | 1230 | 1231 | false 1232 | 1233 | 1234 | 1235 | 500 1236 | 1237 | 1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | false 1246 | 1247 | 1248 | 1249 | Qt::Horizontal 1250 | 1251 | 1252 | 1253 | 227 1254 | 20 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | 0 1264 | 0 1265 | 1266 | 1267 | 1268 | 1269 | false 1270 | 1271 | 1272 | 1273 | Minimum Timeout: (3.5T) * 2 + (1.5T * length) 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 0 1284 | 0 1285 | 1286 | 1287 | 1288 | 1289 | false 1290 | 1291 | 1292 | 1293 | 1.5 char(us) 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 0 1302 | 0 1303 | 1304 | 1305 | 1306 | 1307 | false 1308 | 1309 | 1310 | 1311 | 0 1312 | 1313 | 1314 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 6 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 0 1330 | 0 1331 | 1332 | 1333 | 1334 | 1335 | false 1336 | 1337 | 1338 | 1339 | Port 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 0 1348 | 0 1349 | 1350 | 1351 | 1352 | 1353 | false 1354 | 1355 | 1356 | 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 30 1363 | 16777215 1364 | 1365 | 1366 | 1367 | 1368 | false 1369 | 1370 | 1371 | 1372 | Re 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | false 1387 | 1388 | 1389 | 1390 | Baudrate 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | false 1399 | 1400 | 1401 | 1402 | 1403 | 1200 1404 | 1405 | 1406 | 1407 | 1408 | 2400 1409 | 1410 | 1411 | 1412 | 1413 | 4800 1414 | 1415 | 1416 | 1417 | 1418 | 9600 1419 | 1420 | 1421 | 1422 | 1423 | 19200 1424 | 1425 | 1426 | 1427 | 1428 | 38400 1429 | 1430 | 1431 | 1432 | 1433 | 57600 1434 | 1435 | 1436 | 1437 | 1438 | 115200 1439 | 1440 | 1441 | 1442 | 1443 | 1444 | 1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | false 1452 | 1453 | 1454 | 1455 | Data bits 1456 | 1457 | 1458 | 1459 | 1460 | 1461 | 1462 | 1463 | false 1464 | 1465 | 1466 | 1467 | 1468 | 8 1469 | 1470 | 1471 | 1472 | 1473 | 7 1474 | 1475 | 1476 | 1477 | 1478 | 6 1479 | 1480 | 1481 | 1482 | 1483 | 5 1484 | 1485 | 1486 | 1487 | 1488 | 1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | 1496 | false 1497 | 1498 | 1499 | 1500 | Parity 1501 | 1502 | 1503 | 1504 | 1505 | 1506 | 1507 | 1508 | false 1509 | 1510 | 1511 | 1512 | 1513 | none 1514 | 1515 | 1516 | 1517 | 1518 | even 1519 | 1520 | 1521 | 1522 | 1523 | odd 1524 | 1525 | 1526 | 1527 | 1528 | 1529 | 1530 | 1531 | 1532 | 1533 | 1534 | 1535 | 1536 | false 1537 | 1538 | 1539 | 1540 | Stop bits 1541 | 1542 | 1543 | 1544 | 1545 | 1546 | 1547 | 1548 | false 1549 | 1550 | 1551 | 1552 | 1553 | 1 1554 | 1555 | 1556 | 1557 | 1558 | 2 1559 | 1560 | 1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | false 1572 | 1573 | 1574 | 1575 | Qt::Horizontal 1576 | 1577 | 1578 | 1579 | 27 1580 | 20 1581 | 1582 | 1583 | 1584 | 1585 | 1586 | 1587 | 1588 | 1589 | 1590 | 1591 | 0 1592 | 0 1593 | 1594 | 1595 | 1596 | 1597 | false 1598 | 1599 | 1600 | 1601 | 3.5 char(us) 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 0 1610 | 0 1611 | 1612 | 1613 | 1614 | 1615 | false 1616 | 1617 | 1618 | 1619 | 0 1620 | 1621 | 1622 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | horizontalSpacer 1632 | horizontalSpacer_2 1633 | label_22 1634 | 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | -------------------------------------------------------------------------------- /modbuswnd.cpp: -------------------------------------------------------------------------------- 1 | #include "modbuswnd.h" 2 | #include "ui_form.h" 3 | #include "version.h" 4 | #include "CRC.h" 5 | 6 | 7 | 8 | ModbusWnd::ModbusWnd(QWidget *parent) : 9 | QWidget(parent), 10 | ui(new Ui::Form), 11 | m_modelTxPktQueue(new QStandardItemModel(this) ), 12 | m_modelTxRxResult(new QStandardItemModel(this) ), 13 | m_threadForSerial(new QThread(this) ), 14 | m_timerAutoSend(new QTimer(this)), 15 | m_timer100msec(new QTimer(this)), 16 | m_reHex("[a-fA-F0-9]+", QRegularExpression::CaseInsensitiveOption), 17 | m_recvedCount(0), 18 | m_sendedCount(0), 19 | m_1msCount(1) 20 | { 21 | ui->setupUi(this); 22 | onBtnRefreshClicked(); 23 | m_timerAutoSend->setSingleShot(true); 24 | m_timer100msec->setInterval(100); 25 | 26 | ui->cmbBaudrate->setCurrentText("9600"); 27 | 28 | QStringList headers; 29 | headers << "ENABLE" << "HEX" << "ASCII" << "COMMENT"; 30 | m_modelTxPktQueue->setHorizontalHeaderLabels(headers); 31 | ui->viewTxQueueData->setModel(m_modelTxPktQueue); 32 | ui->viewTxQueueData->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); 33 | ui->viewTxQueueData->setSelectionMode(QAbstractItemView::SingleSelection); 34 | ui->viewTxQueueData->setSelectionBehavior(QAbstractItemView::SelectRows); 35 | 36 | headers.clear(); 37 | headers << "TIME STAMP" << "STATUS" << "MODE" << "RAW DATA" << "CRC" << "S ADDR" << "FUNC" << "INFO"; 38 | m_modelTxRxResult->setHorizontalHeaderLabels(headers); 39 | ui->viewTxRxResult->setModel(m_modelTxRxResult); 40 | ui->viewTxRxResult->setEditTriggers(QAbstractItemView::NoEditTriggers); 41 | // ui->viewTxRxResult->horizontalHeader()->setStretchLastSection(true); 42 | ui->viewTxRxResult->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); 43 | ui->viewTxRxResult->setSelectionMode(QAbstractItemView::SingleSelection); 44 | ui->viewTxRxResult->setSelectionBehavior(QAbstractItemView::SelectRows); 45 | 46 | 47 | m_rxCount = 0; 48 | m_txCount = 0; 49 | m_errorCount = 0; 50 | 51 | m_txRxResultMaxRow = 20000; 52 | 53 | createConnection(); 54 | readSettings(); 55 | 56 | ui->lineWriteData->setValidator(new QRegularExpressionValidator(m_reHex) ); 57 | ui->lineAddr->setValidator(new QRegularExpressionValidator(m_reHex) ); 58 | } 59 | 60 | ModbusWnd::~ModbusWnd() 61 | { 62 | delete ui; 63 | m_threadForSerial->exit(); 64 | } 65 | 66 | void ModbusWnd::createConnection() 67 | { 68 | m_port = new SerialPort(); 69 | // for serial 70 | connect(m_port, SIGNAL(sgReceivedData(QByteArray)), this, SLOT(onRecvedData(QByteArray) )); 71 | connect(m_port, SIGNAL(sgReceivedErrorData(QByteArray)), this, SLOT(onRecvedErrorData(QByteArray) )); 72 | connect(m_port, SIGNAL(sgSendedData(QByteArray)), this, SLOT(onSendedData(QByteArray) )); 73 | connect(m_threadForSerial, SIGNAL(finished()), m_port, SLOT(deleteLater()) ); 74 | connect(m_threadForSerial, SIGNAL(started()), m_port, SLOT(init()) ); 75 | 76 | connect(m_port, SIGNAL(sgConnected()), this, SLOT(onPortConnected() )); 77 | connect(m_port, SIGNAL(sgDisconnected()), this, SLOT(onPortDisconnected() )); 78 | connect(m_port, SIGNAL(sgResponseTimeout()), this, SLOT(onPortResponseTimeout() )); 79 | connect(m_port, SIGNAL(sgT15IntervalChanged()), this, SLOT(onT15IntervalChanged() )); 80 | connect(m_port, SIGNAL(sgT35IntervalChanged()), this, SLOT(onT35IntervalChanged() )); 81 | 82 | // 타이밍이 중요 하므로 쓰레드 우선순위를 높임 83 | m_port->moveToThread(m_threadForSerial); 84 | m_threadForSerial->start(QThread::TimeCriticalPriority); 85 | 86 | connect(ui->btnOpen, SIGNAL(clicked()), this, SLOT(onBtnOpenClicked() )); 87 | connect(ui->btnClose, SIGNAL(clicked()), this, SLOT(onBtnCloseClicked()) ); 88 | 89 | connect(ui->cmbComPort, SIGNAL(currentTextChanged(QString)), this, SLOT(onCmbComportTextChanged(QString) )); 90 | connect(ui->cmbBaudrate, SIGNAL(currentTextChanged(QString)), this, SLOT(onCmbBaudrateTextChanged(QString) )); 91 | connect(ui->cmbDataBits, SIGNAL(currentTextChanged(QString)), this, SLOT(onCmbDataBitsTextChanged(QString) )); 92 | connect(ui->cmbParity, SIGNAL(currentTextChanged(QString)), this, SLOT(onCmbParityTextChanged(QString) )); 93 | connect(ui->cmbStopBits, SIGNAL(currentTextChanged(QString)), this, SLOT(onCmbStopBitsTextChanged(QString) )); 94 | 95 | connect(ui->lineDecimalChange, SIGNAL(editingFinished()), this, SLOT(onLineDecimalChanged() )); 96 | connect(ui->lineHexChange, SIGNAL(editingFinished()), this, SLOT(onLineHexChanged() )); 97 | 98 | 99 | connect(ui->cmbCommMode, SIGNAL(currentTextChanged(QString)),this, SLOT(onCmbCommModeCurrentTextChanged(QString) )); 100 | connect(ui->cmbFunction, SIGNAL(currentTextChanged(QString)), this, SLOT(onCmbFunctionCurrentTextChanged(QString) )); 101 | connect(ui->cmbSendCount, SIGNAL(currentTextChanged(QString)), this, SLOT(onCmbSendCountTextChanged(QString) )); 102 | connect(ui->chkAutoSend, SIGNAL(toggled(bool)), this, SLOT(onChkAutoSendToggled(bool) )); 103 | connect(ui->chkIgnoreAck, SIGNAL(toggled(bool)), this, SLOT(onChkIgnoreAckToggled(bool) )); 104 | 105 | 106 | connect(ui->lineModbusTimeout, SIGNAL(textChanged(QString)), this, SLOT(onLineModbusTimeoutChanged(QString) )); 107 | connect(ui->lineModbusTimeout, SIGNAL(editingFinished()), this, SLOT(onLineModbusEditingFinished())); 108 | 109 | connect(ui->btnManualSend, SIGNAL(clicked() ) , this, SLOT(onBtnManualSendClicked() )); 110 | connect(ui->btnScreenClear, SIGNAL(clicked() ) , this, SLOT(onBtnScreenClearClicked() )); 111 | connect(ui->btnRefresh, SIGNAL(clicked() ) , this, SLOT(onBtnRefreshClicked() )); 112 | 113 | connect(this, SIGNAL(sgRxCountChanged()), this, SLOT(onRxCountChanged() )); 114 | connect(this, SIGNAL(sgTxCountChanged()), this, SLOT(onTxCountChanged() )); 115 | connect(this, SIGNAL(sgErrorCountChanged()), this, SLOT(onErrorCountChanged() )); 116 | 117 | connect(ui->btnResultFileSave, SIGNAL(clicked() ), this, SLOT(onBtnResultFileSaveClicked() )); 118 | 119 | connect(ui->btnTxQueueAdd, SIGNAL(clicked() ), this, SLOT(btnTxQueueAddClicked() )); 120 | connect(ui->btnTxQueueRemove, SIGNAL(clicked() ), this, SLOT(btnTxQueueRemoveClicked() )); 121 | connect(ui->btnTxQueueUp, SIGNAL(clicked() ), this, SLOT(btnTxQueueUpClicked() )); 122 | connect(ui->btnTxQueueDown, SIGNAL(clicked() ), this, SLOT(btnTxQueueDownClicked() )); 123 | 124 | connect(ui->btnCheckSum, SIGNAL(clicked() ), this, SLOT(btnCheckSumClicked() )); 125 | connect(ui->btnCRC16, SIGNAL(clicked() ), this, SLOT(btnCRC16Clicked() )); 126 | connect(ui->btnCRC32, SIGNAL(clicked() ), this, SLOT(btnCRC32Clicked() )); 127 | connect(ui->btnDataInputClear, SIGNAL(clicked() ), ui->lineDataInput, SLOT(clear() )); 128 | 129 | 130 | 131 | 132 | connect(ui->lineAscToHexAscInput, SIGNAL(returnPressed()), this, SLOT(onLineAscToHexAscInputClicked() )); 133 | connect(ui->lineAscToHexHexInput, SIGNAL(returnPressed()), this, SLOT(onLineAscToHexHexInputClicked() )); 134 | 135 | connect(ui->btnAscInput, SIGNAL(clicked() ), ui->lineAscToHexAscInput, SLOT(clear() )); 136 | connect(ui->btnHexInput, SIGNAL(clicked() ), ui->lineAscToHexHexInput, SLOT(clear() )); 137 | 138 | 139 | connect(m_modelTxPktQueue, SIGNAL(dataChanged(QModelIndex,QModelIndex)), 140 | this, SLOT(onModelTxPktQueueDataChanged(QModelIndex, QModelIndex) )); 141 | 142 | 143 | 144 | 145 | connect(m_timerAutoSend, SIGNAL(timeout()), this, SLOT(onTimerAutoSendTimeout() )); 146 | connect(m_timer100msec, SIGNAL(timeout()), this, SLOT(onTimer100msTimeout() )); 147 | 148 | connect(m_modelTxRxResult, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 149 | this, SLOT(onModelTxResultRowInserted(const QModelIndex &, int, int))); 150 | 151 | 152 | connect(ui->viewTxQueueData->selectionModel(), 153 | SIGNAL(currentRowChanged(const QModelIndex&, const QModelIndex&)), this, 154 | SLOT(onViewTxQueueDataSelectionCurrentRowChanged(const QModelIndex &, const QModelIndex &) )); 155 | 156 | } 157 | 158 | void ModbusWnd::readSettings() 159 | { 160 | 161 | QSettings settings(APP_CONFIG_FILE, QSettings::IniFormat); 162 | 163 | QString cmbComport = settings.value("cmbComport").toString(); 164 | QString cmbBaudrate = settings.value("cmbBaudrate").toString(); 165 | QString cmbDataBits = settings.value("cmdDataBits").toString(); 166 | QString cmbParity = settings.value("cmbParity").toString(); 167 | QString cmbStopBits = settings.value("cmbStopBits").toString(); 168 | QString lineAddr = settings.value("lineAddr").toString(); 169 | QString lineInterval = settings.value("lineInterval").toString(); 170 | QString lineSlaveAddr = settings.value("lineSlaveAddr").toString(); 171 | QString lineWriteData = settings.value("lineWriteData").toString(); 172 | QString cmbFunction = settings.value("cmbFunction").toString(); 173 | QString cmbSendCount = settings.value("cmbSendCount").toString(); 174 | bool chkAutoSend = settings.value("chkAutoSend").toBool(); 175 | QString lineModbusTimeout = settings.value("lineModbusTimeout").toString(); 176 | QString cmbCommMode = settings.value("cmbCommMode").toString(); 177 | QStringList txQueueData = settings.value("txQueueData").toStringList(); 178 | 179 | foreach(QString str, txQueueData) 180 | { 181 | QList items; 182 | QStringList tempStrs = str.split(","); 183 | 184 | for(int i = 0; i < MODBUS_WND_TX_QUEUE_COLUMNS::COUNT; i++ ) 185 | { 186 | QStandardItem* insertedItem = new QStandardItem(); 187 | 188 | switch(i) 189 | { 190 | case MODBUS_WND_TX_QUEUE_COLUMNS::ENABLE: 191 | insertedItem->setCheckable(true); 192 | insertedItem->setEditable(false); 193 | break; 194 | case MODBUS_WND_TX_QUEUE_COLUMNS::ASCII: 195 | insertedItem->setEditable(false); 196 | insertedItem->setEditable(false); 197 | insertedItem->setText(tempStrs.at(i-1).toLatin1()); 198 | default: 199 | insertedItem->setText(tempStrs.at(i-1)); 200 | } 201 | items << insertedItem; 202 | } 203 | 204 | m_modelTxPktQueue->appendRow(items); 205 | 206 | 207 | } 208 | 209 | qDebug() << Q_FUNC_INFO << cmbComport << cmbBaudrate << cmbDataBits << cmbParity << cmbStopBits << 210 | lineAddr << lineInterval << lineSlaveAddr << lineWriteData << cmbFunction << cmbSendCount << chkAutoSend << lineModbusTimeout; 211 | if( cmbComport.isEmpty() == false) 212 | ui->cmbComPort->setCurrentText(cmbComport); 213 | if( cmbBaudrate.isEmpty() == false) 214 | ui->cmbBaudrate->setCurrentText(cmbBaudrate); 215 | if( cmbDataBits.isEmpty() == false) 216 | ui->cmbDataBits->setCurrentText(cmbDataBits); 217 | if( cmbParity.isEmpty() == false) 218 | ui->cmbParity->setCurrentText(cmbParity); 219 | if( cmbStopBits.isEmpty() == false) 220 | ui->cmbStopBits->setCurrentText(cmbStopBits); 221 | 222 | 223 | if( lineAddr.isEmpty() == false) 224 | ui->lineAddr->setText(lineAddr); 225 | if( lineInterval.isEmpty() == false) 226 | ui->lineInterval->setText(lineInterval); 227 | if( lineSlaveAddr.isEmpty() == false) 228 | ui->lineSlaveAddr->setText(lineSlaveAddr); 229 | if( lineWriteData.isEmpty() == false) 230 | ui->lineWriteData->setText(lineWriteData); 231 | if( cmbFunction.isEmpty() == false) 232 | ui->cmbFunction->setCurrentText(cmbFunction); 233 | if( cmbSendCount.isEmpty() == false) 234 | { 235 | ui->cmbSendCount->setCurrentText(cmbSendCount); 236 | } 237 | onCmbFunctionCurrentTextChanged(cmbFunction); 238 | // ui->chkAutoSend->setChecked(chkAutoSend); 239 | 240 | if( lineModbusTimeout.isEmpty() == false) 241 | { 242 | ui->lineModbusTimeout->setText(lineModbusTimeout); 243 | m_port->setResponseTimeout(lineModbusTimeout.toInt() ); 244 | } 245 | else 246 | { 247 | ui->lineModbusTimeout->setText("500"); 248 | m_port->setResponseTimeout(500); 249 | } 250 | 251 | if( cmbCommMode.isEmpty() == false) 252 | { 253 | ui->cmbCommMode->setCurrentText(cmbCommMode); 254 | m_port->setMode(cmbCommMode); 255 | } 256 | 257 | if( ui->cmbCommMode->currentText().contains("RTU") == true ) 258 | { 259 | ui->chkAddrMinusOne->setVisible(true); 260 | } 261 | else 262 | { 263 | ui->chkAddrMinusOne->setVisible(false); 264 | } 265 | 266 | } 267 | 268 | void ModbusWnd::closeEvent(QCloseEvent * event) 269 | { 270 | 271 | Q_UNUSED(event); 272 | QSettings settings(APP_CONFIG_FILE, QSettings::IniFormat); 273 | 274 | QString cmbComport = ui->cmbComPort->currentText(); 275 | QString cmbBaudrate = ui->cmbBaudrate->currentText(); 276 | QString cmbDataBits = ui->cmbDataBits->currentText(); 277 | QString cmbParity = ui->cmbParity->currentText(); 278 | QString cmbStopBits = ui->cmbStopBits->currentText(); 279 | QString lineAddr = ui->lineAddr->text(); 280 | QString lineInterval = ui->lineInterval->text(); 281 | QString lineSlaveAddr = ui->lineSlaveAddr->text(); 282 | QString lineWriteData = ui->lineWriteData->text(); 283 | QString cmbFunction = ui->cmbFunction->currentText(); 284 | QString cmbSendCount = ui->cmbSendCount->currentText(); 285 | bool chkAutoSend = ui->chkAutoSend->checkState() == Qt::Unchecked ? false : true; 286 | QString lineModbusTimeout = ui->lineModbusTimeout->text(); 287 | QStringList txQueueData; 288 | 289 | for( int i = 0; i < m_modelTxPktQueue->rowCount(); i ++ ) 290 | { 291 | txQueueData << m_modelTxPktQueue->item(i, MODBUS_WND_TX_QUEUE_COLUMNS::HEX)->text() + " ," + 292 | m_modelTxPktQueue->item(i, MODBUS_WND_TX_QUEUE_COLUMNS::ASCII)->text() + " ," + 293 | m_modelTxPktQueue->item(i, MODBUS_WND_TX_QUEUE_COLUMNS::COMMENT)->text(); 294 | } 295 | 296 | settings.setValue("cmbComport", cmbComport ); 297 | settings.setValue("cmbBaudrate", cmbBaudrate); 298 | settings.setValue("cmdDataBits", cmbDataBits); 299 | settings.setValue("cmbParity", cmbParity); 300 | settings.setValue("cmbStopBits", cmbStopBits); 301 | settings.setValue("lineAddr", lineAddr); 302 | settings.setValue("lineInterval", lineInterval); 303 | settings.setValue("lineSlaveAddr", lineSlaveAddr); 304 | settings.setValue("lineWriteData", lineWriteData); 305 | settings.setValue("cmbFunction", cmbFunction); 306 | settings.setValue("cmbSendCount", cmbSendCount); 307 | settings.setValue("chkAutoSend", chkAutoSend); 308 | settings.setValue("lineModbusTimeout", lineModbusTimeout); 309 | settings.setValue("txQueueData", txQueueData); 310 | settings.sync(); 311 | } 312 | 313 | void ModbusWnd::addDataToTxRxResultModel(QStringList info) 314 | { 315 | QStandardItemModel* model = m_modelTxRxResult; 316 | 317 | QList addItems; 318 | QBrush foregroundBursh(Qt::black); 319 | 320 | for ( int i = 0 ; i < MODBUS_WND_TXRX_RESULT_COLUMNS::COUNT ; i ++ ) 321 | { 322 | QStandardItem* tempItem = new QStandardItem(); 323 | switch(i) 324 | { 325 | case MODBUS_WND_TXRX_RESULT_COLUMNS::TIMESTAMP: 326 | { 327 | QString timeStamp = info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::TIMESTAMP); 328 | QString status = info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS); 329 | if( status.contains("RX") == true ) 330 | foregroundBursh.setColor(Qt::blue); 331 | tempItem->setText(timeStamp); 332 | break; 333 | } 334 | case MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS : 335 | { 336 | QString status = info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS); 337 | if( status.contains("NOK") == true ) 338 | foregroundBursh.setColor(Qt::red); 339 | tempItem->setText(status); 340 | break; 341 | } 342 | case MODBUS_WND_TXRX_RESULT_COLUMNS::MODE : 343 | { 344 | QString status = info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::MODE); 345 | tempItem->setText(status); 346 | break; 347 | } 348 | case MODBUS_WND_TXRX_RESULT_COLUMNS::RAWDATA : 349 | tempItem->setText(info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::RAWDATA)); 350 | break; 351 | case MODBUS_WND_TXRX_RESULT_COLUMNS::CRC : 352 | tempItem->setText(info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::CRC)); 353 | break; 354 | 355 | case MODBUS_WND_TXRX_RESULT_COLUMNS::SLAVE_ADDR : 356 | tempItem->setText("[" +info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::SLAVE_ADDR) + "]"); 357 | break; 358 | case MODBUS_WND_TXRX_RESULT_COLUMNS::FUNCTION : 359 | tempItem->setText("[" + info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::FUNCTION) + "]"); 360 | break; 361 | case MODBUS_WND_TXRX_RESULT_COLUMNS::INFO : 362 | tempItem->setText(info.at(MODBUS_WND_TXRX_RESULT_COLUMNS::INFO)); 363 | break; 364 | 365 | } 366 | addItems << tempItem; 367 | } 368 | foreach(QStandardItem* item, addItems) 369 | { 370 | item->setEditable(false); 371 | item->setForeground(foregroundBursh); 372 | } 373 | 374 | model->appendRow(addItems); 375 | 376 | if( ui->chkAutoScroll->checkState() == Qt::Checked ) 377 | ui->viewTxRxResult->scrollToBottom(); 378 | } 379 | 380 | void ModbusWnd::addDataToTxPktQueueModel(QStringList parsedData) 381 | { 382 | QStandardItemModel* model = m_modelTxPktQueue; 383 | 384 | QList addItems; 385 | QBrush foregroundBursh(Qt::black); 386 | 387 | for ( int i = 0 ; i < MODBUS_WND_TX_QUEUE_COLUMNS::COUNT ; i ++ ) 388 | { 389 | QStandardItem* tempItem = new QStandardItem(); 390 | 391 | switch(i) 392 | { 393 | case MODBUS_WND_TX_QUEUE_COLUMNS::ENABLE: 394 | { 395 | tempItem->setCheckable(true); 396 | tempItem->setCheckState(Qt::Checked); 397 | tempItem->setEditable(false); 398 | break; 399 | } 400 | case MODBUS_WND_TX_QUEUE_COLUMNS::HEX : 401 | tempItem->setEditable(true); 402 | tempItem->setText(parsedData.at(MODBUS_WND_TXRX_RESULT_COLUMNS::RAWDATA)); 403 | break; 404 | 405 | case MODBUS_WND_TX_QUEUE_COLUMNS::ASCII : 406 | { 407 | tempItem->setEditable(false); 408 | 409 | QByteArray text; 410 | QByteArray targetText = ""; 411 | text = parsedData.at(MODBUS_WND_TXRX_RESULT_COLUMNS::RAWDATA).toLatin1().trimmed(); 412 | text = text.replace(" " , ""); 413 | 414 | for (int i =0; i < text.count() ; i = i+2 ) 415 | { 416 | targetText +=QByteArray::fromHex(text.mid(i, 2)); 417 | 418 | } 419 | tempItem->setText(targetText); 420 | } 421 | break; 422 | 423 | case MODBUS_WND_TX_QUEUE_COLUMNS::COMMENT : 424 | tempItem->setCheckable(false); 425 | tempItem->setEditable(true); 426 | tempItem->setText("\"comment\""); 427 | break; 428 | 429 | } 430 | addItems << tempItem; 431 | } 432 | foreach(QStandardItem* item, addItems) 433 | { 434 | item->setForeground(foregroundBursh); 435 | } 436 | 437 | model->appendRow(addItems); 438 | ui->viewTxQueueData->scrollToBottom(); 439 | } 440 | 441 | 442 | void ModbusWnd::onSendedData(QByteArray data) 443 | { 444 | QStringList sendedData; 445 | m_sendedCount += data.size(); 446 | 447 | onParseData(sendedData, data); 448 | sendedData[MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS] = "[TX " + sendedData.at(MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS); 449 | 450 | m_sendedTimeStamp = QDateTime::currentMSecsSinceEpoch(); 451 | addDataToTxRxResultModel(sendedData); 452 | addTxCount(); 453 | } 454 | 455 | void ModbusWnd::onRecvedData(QByteArray data) 456 | { 457 | QStringList receivedData; 458 | 459 | m_recvedCount += data.size(); 460 | 461 | onParseData(receivedData, data); 462 | receivedData[MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS] = "[RX " + receivedData.at(MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS); 463 | 464 | m_recvedTimeStamp = QDateTime::currentMSecsSinceEpoch(); 465 | 466 | //qDebug() << m_recvedTimeStamp - m_sendedTimeStamp << " " << receivedData << "\n"; 467 | addDataToTxRxResultModel(receivedData); 468 | addRxCount(); 469 | } 470 | 471 | 472 | void ModbusWnd::onRecvedErrorData(QByteArray data) 473 | { 474 | QStringList receivedData; 475 | onParseData(receivedData, data); 476 | receivedData[MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS] = "[RX " + receivedData.at(MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS); 477 | addDataToTxRxResultModel(receivedData); 478 | addRxCount(); 479 | } 480 | 481 | int ModbusWnd::onParseData(QStringList &parsedData, QByteArray data) 482 | { 483 | QString timeStamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz"); 484 | QString status = ""; 485 | QString rawData = QString(ModbusWnd::toHexString(data)); 486 | QString slaveAddr = ""; 487 | QString function = ""; 488 | QString info = ""; 489 | QString crc = ""; 490 | QString commMode = ui->cmbCommMode->currentText(); 491 | 492 | int exception_code = 0x00; 493 | if( commMode == "RTU") 494 | { 495 | if( data.count() >= 4 ) 496 | { 497 | slaveAddr = QString( data.mid(0, 1).toHex() ); 498 | function = QString( data.mid(1, 1).toHex() ); 499 | crc = QString( data.mid(data.count() -2 , 2).toHex() ); 500 | 501 | if( data.at(1) & 0x80 ) 502 | exception_code = data.at(2); 503 | 504 | quint16 crc_result = 0x0ffff; 505 | if( check_ModbusRTU_CRC16(data, crc_result) == true ) 506 | { 507 | if( exception_code != 0x00 ) 508 | { 509 | info += QString("[ERROR CODE] ") + data.mid(2, data.count() - 4).toHex(); 510 | exception_code = 0xff; 511 | } 512 | } 513 | else 514 | { 515 | info = QString("[ERROR CRC] expected %1").arg(crc_result, 4, 16, QChar('0')); 516 | exception_code = 0xff; 517 | } 518 | } 519 | else 520 | { 521 | exception_code = 0xff; 522 | } 523 | } 524 | else if( commMode == "LSBUS") 525 | { 526 | if( data.count() >= 4 ) 527 | { 528 | QString response_start = QString( data.mid(0, 1).toHex() ); 529 | slaveAddr = QString( data.mid(1, 2) ); 530 | function = QString( data.mid(3, 1) ); 531 | crc = QString( data.mid(data.count() -3, 2) ); 532 | 533 | quint8 sum = LSBUS_sum(data.mid(0, data.count() - 3)); 534 | 535 | if( sum == crc.toInt(NULL, 16) ) 536 | { 537 | if( response_start == "15" ) 538 | { 539 | info += QString("[ERROR CODE] ") + data.mid(4, 2) + " "; 540 | exception_code = 0xff; 541 | } 542 | info += "" + data.mid(0, data.count()) ; 543 | } 544 | else 545 | { 546 | info = QString("[ERROR SUM] expected %1").arg(sum, 4, 16, QChar('0')); 547 | exception_code = 0xff; 548 | } 549 | } 550 | else 551 | { 552 | exception_code = 0xff; 553 | } 554 | } 555 | 556 | 557 | if( exception_code != 0x00 ) 558 | { 559 | status = "NOK]"; 560 | } 561 | else 562 | { 563 | status = "OK]"; 564 | } 565 | 566 | parsedData << timeStamp << status << commMode << rawData << crc << slaveAddr << function << info; 567 | // qDebug() << parsedData; 568 | return exception_code; 569 | } 570 | 571 | void ModbusWnd::onCmbComportTextChanged(QString str) 572 | { 573 | 574 | } 575 | 576 | quint32 ModbusWnd::onCmbBaudrateTextChanged(QString str) 577 | { 578 | QMetaObject::invokeMethod(m_port, "changeBaudrate", Qt::BlockingQueuedConnection, 579 | Q_ARG(quint32, str.toInt() )); 580 | 581 | return str.toInt(); 582 | } 583 | 584 | quint32 ModbusWnd::onCmbDataBitsTextChanged(QString str) 585 | { 586 | QMetaObject::invokeMethod(m_port, "changeDataBits", Qt::BlockingQueuedConnection, 587 | Q_ARG(quint32, str.toInt() )); 588 | 589 | return str.toInt(); 590 | } 591 | quint32 ModbusWnd::onCmbParityTextChanged(QString str) 592 | { 593 | QSerialPort::Parity parity = QSerialPort::UnknownParity; 594 | 595 | if( str == "none" ) 596 | { 597 | parity = QSerialPort::NoParity; 598 | } 599 | else if ( str == "even" ) 600 | { 601 | parity = QSerialPort::EvenParity; 602 | } 603 | else if ( str == "odd" ) 604 | { 605 | parity = QSerialPort::OddParity; 606 | } 607 | 608 | QMetaObject::invokeMethod(m_port, "changeParity", Qt::BlockingQueuedConnection, 609 | Q_ARG(quint32, parity )); 610 | 611 | return parity; 612 | } 613 | quint32 ModbusWnd::onCmbStopBitsTextChanged(QString str) 614 | { 615 | QSerialPort::StopBits stopBits = QSerialPort::UnknownStopBits; 616 | if( str.toInt() == 1 ) 617 | stopBits = QSerialPort::OneStop; 618 | else if ( str.toInt() == 2) 619 | stopBits = QSerialPort::TwoStop; 620 | 621 | QMetaObject::invokeMethod(m_port, "changeStopBits", Qt::BlockingQueuedConnection, 622 | Q_ARG(quint32, stopBits )); 623 | 624 | return stopBits; 625 | } 626 | 627 | 628 | void ModbusWnd::onLineDecimalChanged() 629 | { 630 | QString numText = ui->lineDecimalChange->text(); 631 | numText = numText.replace(" ", ""); 632 | int number = numText.toInt(); 633 | ui->lineHexChange->setText(QByteArray::number(number, 16).toUpper() ); 634 | } 635 | 636 | void ModbusWnd::onLineHexChanged() 637 | { 638 | int number = ui->lineHexChange->text().toInt(0, 16); 639 | ui->lineDecimalChange->setText(QByteArray::number(number, 10).toUpper() ); 640 | 641 | } 642 | 643 | void ModbusWnd::onCmbCommModeCurrentTextChanged(QString str) 644 | { 645 | QStringList functions; 646 | 647 | ui->cmbFunction->clear(); 648 | 649 | if( ui->cmbCommMode->currentText().contains("RTU")) 650 | { 651 | functions << "03 (Read Holding Register)" << 652 | "04 (Read Input Register)" << 653 | "06 (Write Single Register)" << 654 | "10 (Write Multiple Register)" ; 655 | 656 | ui->lblWriteData->setText("Write Data(HEX)"); 657 | ui->chkAddrMinusOne->setVisible(true); 658 | 659 | } 660 | else 661 | { 662 | functions << "52 'R' Read" << 663 | "57 'W' Write" << 664 | "58 'X' Monitor request" << 665 | "59 'Y' Monitor excute" ; 666 | 667 | ui->lblWriteData->setText("Write Data(ASCII)"); 668 | ui->chkAddrMinusOne->setVisible(false); 669 | } 670 | m_port->setMode(str); 671 | ui->cmbFunction->addItems(functions); 672 | } 673 | 674 | void ModbusWnd::onCmbFunctionCurrentTextChanged(QString str) 675 | { 676 | if( str == "06 (Write Single Register)" ) 677 | { 678 | ui->cmbSendCount->setEnabled(false); 679 | ui->lineWriteData->setMaxLength(4); 680 | } 681 | else 682 | { 683 | ui->cmbSendCount->setEnabled(true); 684 | ui->lineWriteData->setMaxLength(512); 685 | } 686 | 687 | if( str.contains("Read") ) 688 | { 689 | ui->lineWriteData->setEnabled(false); 690 | } 691 | else 692 | { 693 | ui->lineWriteData->setEnabled(true); 694 | } 695 | } 696 | 697 | void ModbusWnd::onCmbSendCountTextChanged(QString str) 698 | { 699 | 700 | } 701 | 702 | void ModbusWnd::onChkAutoSendToggled(bool checked) 703 | { 704 | int interval = ui->lineInterval->text().toInt(); 705 | 706 | if( checked == true ) 707 | { 708 | ui->lineInterval->setEnabled(false); 709 | 710 | if( interval == 0 ) 711 | { 712 | interval = 1; 713 | } 714 | 715 | m_sendedCount= 0; 716 | m_recvedCount = 0; 717 | m_1msCount = 0; 718 | m_previousTimeStamp = QDateTime::currentMSecsSinceEpoch(); 719 | 720 | 721 | connect(m_port, SIGNAL(sgReadyEntered()), m_timerAutoSend, SLOT(start())); 722 | m_timerAutoSend->setInterval( interval ); 723 | m_timerAutoSend->start(); 724 | m_timer100msec->start(); 725 | 726 | } 727 | else 728 | { 729 | disconnect(m_port, SIGNAL(sgReadyEntered()), 0, 0); 730 | m_timerAutoSend->stop(); 731 | m_timer100msec->stop(); 732 | ui->lineInterval->setEnabled(true); 733 | } 734 | } 735 | 736 | void ModbusWnd::onChkIgnoreAckToggled(bool checked) 737 | { 738 | if( checked == true ) 739 | { 740 | m_port->setIgnoreAck(true); 741 | } 742 | else 743 | { 744 | m_port->setIgnoreAck(false); 745 | } 746 | } 747 | 748 | void ModbusWnd::onLineModbusTimeoutChanged(QString str) 749 | { 750 | if( ui->lineModbusTimeout->text().toInt() < 10 ) 751 | { 752 | return; 753 | } 754 | } 755 | 756 | void ModbusWnd::onLineModbusEditingFinished() 757 | { 758 | QString str = ui->lineModbusTimeout->text(); 759 | 760 | if( ui->lineModbusTimeout->text().toInt() < 1 ) 761 | { 762 | QMessageBox::warning(this, "Error", "modbus timeout should not be lower than 1 msec"); 763 | ui->lineModbusTimeout->setText("1"); 764 | return; 765 | } 766 | m_port->setResponseTimeout(str.toInt() ); 767 | } 768 | 769 | void ModbusWnd::onPortConnected() 770 | { 771 | ui->lineModbusTimeout->setEnabled(false); 772 | ui->btnOpen->setEnabled(false); 773 | ui->btnClose->setEnabled(true); 774 | ui->cmbComPort->setEnabled(false); 775 | ui->btnRefresh->setEnabled(false); 776 | ui->chkAutoSend->setChecked(false); 777 | 778 | emit sgConnected("Connected"); 779 | } 780 | void ModbusWnd::onPortDisconnected() 781 | { 782 | ui->lineModbusTimeout->setEnabled(true); 783 | ui->btnOpen->setEnabled(true); 784 | ui->btnClose->setEnabled(false); 785 | ui->btnRefresh->setEnabled(true); 786 | ui->cmbComPort->setEnabled(true); 787 | m_timerAutoSend->stop(); 788 | m_timer100msec->stop(); 789 | 790 | emit sgDisconnected( m_port->errorString()); 791 | } 792 | void ModbusWnd::onPortResponseTimeout() 793 | { 794 | 795 | #if 0 796 | namespace MODBUS_WND_TXRX_RESULT_COLUMNS 797 | { 798 | enum { 799 | TIMESTAMP , 800 | STATUS , 801 | MODE , 802 | RAWDATA , 803 | CRC , 804 | SLAVE_ADDR , 805 | FUNCTION , 806 | INFO , 807 | COUNT 808 | }; 809 | } 810 | #endif 811 | 812 | QString timeStamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz"); 813 | QString status = "[RX NOK]"; 814 | QString rawData = ""; 815 | QString slaveAddr = ""; 816 | QString function = ""; 817 | QString info = QString("[ERROR TIMEOUT INTERVAL] %1 msec").arg(QString("%1").arg(m_port->responseTimeout())); 818 | QString crc = ""; 819 | QStringList rowItems; 820 | QString commMode = ui->cmbCommMode->currentText(); 821 | rowItems << timeStamp << status << commMode << rawData << crc << slaveAddr << function << info ; 822 | addDataToTxRxResultModel(rowItems); 823 | addErrorCount(); 824 | } 825 | 826 | 827 | void ModbusWnd::onBtnOpenClicked() 828 | { 829 | QMetaObject::invokeMethod(m_port, "tryConnect", Qt::QueuedConnection , 830 | Q_ARG(QString, ui->cmbComPort->currentText()), 831 | Q_ARG(quint32, onCmbBaudrateTextChanged(ui->cmbBaudrate->currentText()) ), 832 | Q_ARG(quint32, onCmbDataBitsTextChanged(ui->cmbDataBits->currentText()) ), 833 | Q_ARG(quint32, onCmbParityTextChanged(ui->cmbParity->currentText()) ), 834 | Q_ARG(quint32, onCmbStopBitsTextChanged(ui->cmbStopBits->currentText()) ) 835 | ); 836 | } 837 | void ModbusWnd::onBtnCloseClicked() 838 | { 839 | QMetaObject::invokeMethod(m_port, "tryDisconnect", Qt::QueuedConnection); 840 | } 841 | 842 | void ModbusWnd::onBtnManualSendClicked() 843 | { 844 | QModelIndex currentIndex = ui->viewTxQueueData->selectionModel()->currentIndex(); 845 | if( currentIndex.row() != -1) 846 | sendModelTxPktQueue(currentIndex.row()); 847 | } 848 | 849 | void ModbusWnd::onBtnScreenClearClicked() 850 | { 851 | resetRxCount(); 852 | resetTxCount(); 853 | resetErrorCount(); 854 | removeModelTxRxResult(); 855 | } 856 | void ModbusWnd::removeModelTxRxResult() 857 | { 858 | int removeCount = m_modelTxRxResult->rowCount(); 859 | for ( int i = 0; i < removeCount; i++ ) 860 | { 861 | m_modelTxRxResult->removeRow(0); 862 | } 863 | } 864 | 865 | void ModbusWnd::onBtnRefreshClicked() 866 | { 867 | QList portInfos = QSerialPortInfo::availablePorts(); 868 | ui->cmbComPort->clear(); 869 | foreach( QSerialPortInfo portInfo, portInfos) 870 | { 871 | QString portName = portInfo.portName(); 872 | if( portInfo.isBusy() ) 873 | ui->cmbComPort->addItem(portName + "(in use)"); 874 | else 875 | ui->cmbComPort->addItem(portName); 876 | } 877 | } 878 | 879 | 880 | 881 | void ModbusWnd::onRxCountChanged() 882 | { 883 | ui->lblRxCount->setText( QString("%1").arg(m_rxCount) ); 884 | } 885 | 886 | void ModbusWnd::onTxCountChanged() 887 | { 888 | ui->lblTxCount->setText( QString("%1").arg(m_txCount) ); 889 | } 890 | void ModbusWnd::onErrorCountChanged() 891 | { 892 | ui->lblErrorCount->setText( QString("%1").arg(m_errorCount) ); 893 | } 894 | 895 | 896 | 897 | 898 | void ModbusWnd::onT15IntervalChanged() 899 | { 900 | ui->lblDefault15Time->setText(QString("%1").arg(m_port->t15IntervalUsec())); 901 | } 902 | 903 | void ModbusWnd::onT35IntervalChanged() 904 | { 905 | ui->lblDefault35Time->setText(QString("%1").arg(m_port->t35IntervalUsec())); 906 | } 907 | 908 | 909 | void ModbusWnd::onBtnResultFileSaveClicked() 910 | { 911 | QString saveFilePath = QDir::currentPath(); 912 | QString filePath = QFileDialog::getSaveFileName( 913 | this, tr("FILE OPEN"), 914 | saveFilePath, 915 | tr("csv file (*.csv)")); 916 | 917 | if( filePath.isEmpty() == true) 918 | { 919 | return; 920 | } 921 | 922 | QFile file; 923 | file.setFileName(filePath); 924 | 925 | QIODevice::OpenModeFlag openMode; 926 | openMode = QIODevice::WriteOnly; 927 | 928 | if( file.open(openMode) == true ) 929 | { 930 | file.seek(file.size() ); 931 | QString rowData = ""; 932 | 933 | for(int i = 0 ; i < ui->viewTxRxResult->horizontalHeader()->count() ; i ++ ) 934 | { 935 | if( i != ui->viewTxRxResult->horizontalHeader()->count() - 1) 936 | rowData += m_modelTxRxResult->horizontalHeaderItem(i)->text() + ","; 937 | else 938 | rowData += m_modelTxRxResult->horizontalHeaderItem(i)->text() + "\n"; 939 | 940 | } 941 | 942 | file.write(rowData.toLatin1()); 943 | rowData = ""; 944 | 945 | for(int i = 0 ; i < m_modelTxRxResult->rowCount(); i ++ ) 946 | { 947 | rowData = ""; 948 | rowData += " " + m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::TIMESTAMP)->text() + ","; 949 | rowData += m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS)->text() + ","; 950 | rowData += m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::MODE)->text() + ","; 951 | rowData += m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::RAWDATA)->text() + ","; 952 | rowData += m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::CRC)->text() + ","; 953 | rowData += m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::SLAVE_ADDR)->text() + ","; 954 | rowData += m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::FUNCTION)->text() + ","; 955 | rowData += m_modelTxRxResult->item(i, MODBUS_WND_TXRX_RESULT_COLUMNS::INFO)->text() + "\n"; 956 | 957 | file.write(rowData.toLatin1()); 958 | } 959 | file.flush(); 960 | } 961 | else 962 | { 963 | qWarning() << Q_FUNC_INFO << "file save fail" << file.errorString(); 964 | 965 | } 966 | file.close(); 967 | } 968 | 969 | 970 | 971 | void ModbusWnd::btnTxQueueAddClicked() 972 | { 973 | QByteArray slaveAddr = ui->lineSlaveAddr->text().simplified().mid(0, 2).toLatin1(); 974 | QByteArray functionCode = ui->cmbFunction->currentText().simplified().mid(0, 2).toLatin1(); 975 | QByteArray startAddr = ui->lineAddr->text().simplified().mid(0, 4).toLatin1(); 976 | QByteArray writeData = ui->lineWriteData->text().simplified().toLatin1(); 977 | QByteArray numOfRegister =QByteArray("0000" + ui->cmbSendCount->currentText().toLatin1()).right(4); 978 | QByteArray byteCount = ""; 979 | QString commMode = ui->cmbCommMode->currentText(); 980 | byteCount.setNum(ui->cmbSendCount->currentText().toInt(0, 16) * 2, 16); 981 | byteCount = "00" + byteCount; 982 | byteCount = byteCount.right(2); 983 | 984 | 985 | QByteArray sendData = ""; 986 | if( commMode.contains("RTU")) 987 | { 988 | int tempStartAddr = startAddr.toInt(NULL, 16); 989 | if( ui->chkAddrMinusOne->isChecked() == true ) 990 | tempStartAddr--; 991 | 992 | startAddr = QByteArray("0000" + QByteArray::number(tempStartAddr, 16)).right(4); 993 | // qDebug() << Q_FUNC_INFO << startAddr; 994 | sendData = makeRTUFrame(slaveAddr, functionCode, startAddr, numOfRegister, byteCount, writeData); 995 | 996 | } 997 | else 998 | sendData = makeLSBUSFrame(slaveAddr, functionCode, startAddr, numOfRegister, byteCount, writeData); 999 | 1000 | // qDebug() << Q_FUNC_INFO << "commMode" << commMode << "slave" << slaveAddr.toHex() << "function" << functionCode.toHex() << 1001 | // "startAddr" << startAddr.toHex() << "number of register" << numOfRegister.toHex() << "byte Count" << byteCount.toHex() << "sendData" << sendData.toHex(); 1002 | 1003 | QStringList parsedData; 1004 | onParseData(parsedData, sendData); 1005 | addDataToTxPktQueueModel(parsedData); 1006 | } 1007 | 1008 | void ModbusWnd::btnTxQueueRemoveClicked() 1009 | { 1010 | QModelIndex index = ui->viewTxQueueData->selectionModel()->currentIndex(); 1011 | m_modelTxPktQueue->removeRow(index.row()); 1012 | } 1013 | 1014 | void ModbusWnd::btnTxQueueUpClicked() 1015 | { 1016 | QModelIndex currentIndex = ui->viewTxQueueData->currentIndex(); 1017 | if( currentIndex.row() == -1 ) 1018 | return; 1019 | if( currentIndex.row() != 0 ) 1020 | { 1021 | QList currentRow; 1022 | currentRow = m_modelTxPktQueue->takeRow(currentIndex.row()); 1023 | m_modelTxPktQueue->insertRow(currentIndex.row() -1 , currentRow); 1024 | ui->viewTxQueueData->setCurrentIndex(m_modelTxPktQueue->index(currentIndex.row() -1, 0)); 1025 | } 1026 | } 1027 | 1028 | void ModbusWnd::btnTxQueueDownClicked() 1029 | { 1030 | QModelIndex currentIndex = ui->viewTxQueueData->currentIndex(); 1031 | if( currentIndex.row() == -1 ) 1032 | return; 1033 | 1034 | if( currentIndex.row() != m_modelTxPktQueue->rowCount() -1 ) 1035 | { 1036 | QList currentRow; 1037 | currentRow = m_modelTxPktQueue->takeRow(currentIndex.row()); 1038 | m_modelTxPktQueue->insertRow(currentIndex.row() +1 ,currentRow ); 1039 | ui->viewTxQueueData->setCurrentIndex(m_modelTxPktQueue->index(currentIndex.row() +1, 0)); 1040 | } 1041 | qDebug() << Q_FUNC_INFO << currentIndex.row(); 1042 | } 1043 | 1044 | void ModbusWnd::btnTxQueueFileOpenClicked() 1045 | { 1046 | qDebug() << Q_FUNC_INFO; 1047 | } 1048 | 1049 | void ModbusWnd::btnTxqueueFileSaveClicked() 1050 | { 1051 | qDebug() << Q_FUNC_INFO; 1052 | 1053 | } 1054 | 1055 | 1056 | 1057 | void ModbusWnd::btnCheckSumClicked() 1058 | { 1059 | QByteArray inputData; 1060 | if( ui->radioHex->isChecked() ) 1061 | { 1062 | QString inputText; 1063 | inputText = ui->lineDataInput->text(); 1064 | inputText = inputText.replace(" ", ""); 1065 | inputData = QByteArray::fromHex(inputText.toLatin1()); 1066 | 1067 | } 1068 | else 1069 | { 1070 | QString inputText; 1071 | inputText = ui->lineDataInput->text(); 1072 | inputText = inputText.replace(" ", ""); 1073 | inputData = inputText.toLatin1(); 1074 | } 1075 | 1076 | // qDebug() << inputData.toHex() << inputData; 1077 | 1078 | 1079 | quint8 sum = 0x00; 1080 | for ( int i = 0 ; i < inputData.count() ; i ++ ) 1081 | { 1082 | sum += inputData.at(i); 1083 | } 1084 | 1085 | QByteArray checkSum = ""; 1086 | checkSum = QByteArray::fromRawData((char*)&sum, 1); 1087 | ui->lineDataResultHex->setText(checkSum.toHex().toUpper().toHex()); 1088 | ui->lineDataResultASCII->setText(checkSum.toHex().toUpper()); 1089 | 1090 | } 1091 | 1092 | void ModbusWnd::btnCRC16Clicked() 1093 | { 1094 | QByteArray inputData; 1095 | QString inputText; 1096 | inputText = ui->lineDataInput->text(); 1097 | inputText = inputText.replace(" ", ""); 1098 | 1099 | if( ui->radioHex->isChecked() ) 1100 | { 1101 | inputData = QByteArray::fromHex(inputText.toLatin1()); 1102 | } 1103 | else 1104 | { 1105 | inputData = inputText.toLatin1(); 1106 | } 1107 | 1108 | // qDebug() << inputData.toHex() << inputData; 1109 | 1110 | 1111 | QByteArray dstCrc = ""; 1112 | quint16 crc = ModbusWnd::ModbusRTU_CRC16(inputData.constData(), inputData.size()); 1113 | dstCrc = QByteArray::fromRawData((char*)&crc, 2); 1114 | ui->lineDataResultHex->setText(dstCrc.toHex().toUpper().toHex()); 1115 | ui->lineDataResultASCII->setText(dstCrc.toHex().toUpper()); 1116 | 1117 | } 1118 | 1119 | void ModbusWnd::btnCRC32Clicked() 1120 | { 1121 | QByteArray inputData; 1122 | QString inputText; 1123 | inputText = ui->lineDataInput->text(); 1124 | inputText = inputText.replace(" ", ""); 1125 | 1126 | if( ui->radioHex->isChecked() ) 1127 | { 1128 | inputData = QByteArray::fromHex(inputText.toLatin1()); 1129 | } 1130 | else 1131 | { 1132 | inputData = inputText.toLatin1(); 1133 | } 1134 | 1135 | qDebug() << inputData.toHex() << inputData.size(); 1136 | 1137 | 1138 | QByteArray dstCrc = ""; 1139 | uint32_t crc = CRC::Calculate(inputData.constData(), inputData.size(), CRC::CRC_32_MPEG2()); 1140 | dstCrc = QByteArray::fromRawData((char*)&crc, 4); 1141 | ui->lineDataResultHex->setText(dstCrc.toHex().toUpper().toHex()); 1142 | ui->lineDataResultASCII->setText(dstCrc.toHex().toUpper()); 1143 | 1144 | } 1145 | 1146 | 1147 | void ModbusWnd::onLineAscToHexAscInputClicked() 1148 | { 1149 | QByteArray text; 1150 | QByteArray targetText = ""; 1151 | text = ui->lineAscToHexAscInput->text().toLatin1().trimmed(); 1152 | text = text.replace(" " , ""); 1153 | 1154 | for (int i =0; i < text.count() ; i ++ ) 1155 | { 1156 | QByteArray temp; 1157 | targetText += temp.setNum( (int) text.at(i), 16) + " "; 1158 | } 1159 | ui->lineAscToHexHexInput->setText(QString(targetText.toUpper() )); 1160 | } 1161 | 1162 | void ModbusWnd::onLineAscToHexHexInputClicked() 1163 | { 1164 | QByteArray text; 1165 | QByteArray targetText = ""; 1166 | text = ui->lineAscToHexHexInput->text().toLatin1().trimmed(); 1167 | text = text.replace(" " , ""); 1168 | 1169 | for (int i =0; i < text.count() ; i = i+2 ) 1170 | { 1171 | targetText +=QByteArray::fromHex(text.mid(i, 2)); 1172 | } 1173 | ui->lineAscToHexAscInput->setText( targetText ); 1174 | 1175 | } 1176 | 1177 | void ModbusWnd::onModelTxPktQueueDataChanged(QModelIndex topLeft, QModelIndex bottomRight ) 1178 | { 1179 | int row = topLeft.row(); 1180 | int col = topLeft.column(); 1181 | 1182 | if( col == MODBUS_WND_TX_QUEUE_COLUMNS::HEX ) 1183 | { 1184 | QString str = m_modelTxPktQueue->item(row, col)->text(); 1185 | QString asciiStr = ""; 1186 | str = str.trimmed(); 1187 | str = str.replace(" ", ""); 1188 | for(int i = 0; i < str.count()/2 ; i++ ) 1189 | { 1190 | asciiStr += QByteArray::fromHex(str.mid(i*2, 2).toLatin1()); 1191 | } 1192 | m_modelTxPktQueue->setItem(row, col+1, new QStandardItem(asciiStr)); 1193 | } 1194 | } 1195 | 1196 | void ModbusWnd::onTimerAutoSendTimeout() 1197 | { 1198 | onReadyEntered(); 1199 | } 1200 | 1201 | void ModbusWnd::onTimer100msTimeout() 1202 | { 1203 | // total bytes in 100 ms * 10 for 1sec 1204 | quint64 currentTimeStamp = QDateTime::currentMSecsSinceEpoch(); 1205 | 1206 | do { 1207 | 1208 | m_1msCount += currentTimeStamp - m_previousTimeStamp; 1209 | 1210 | ui->lblBps->setText( QString("%1").arg( (int)( (((double) (m_recvedCount + m_sendedCount)) / (double) m_1msCount) * 1000 ))); 1211 | 1212 | m_previousTimeStamp = currentTimeStamp; 1213 | 1214 | }while(false); 1215 | 1216 | } 1217 | 1218 | 1219 | void ModbusWnd::onModelTxResultRowInserted(const QModelIndex & parent, int first, int last) 1220 | { 1221 | // qDebug() << Q_FUNC_INFO << first << last << m_modelTxRxResult->rowCount(); 1222 | 1223 | if( m_txRxResultMaxRow *2 < m_modelTxRxResult->rowCount() ) 1224 | { 1225 | 1226 | QString saveFilePath = QDir::currentPath(); 1227 | QString filePath = saveFilePath + + "/" + QDateTime::currentDateTime().toString("MM-dd_HH-mm") + ".csv"; 1228 | 1229 | // qDebug() << Q_FUNC_INFO << filePath; 1230 | QFile file; 1231 | file.setFileName(filePath); 1232 | 1233 | QIODevice::OpenModeFlag openMode; 1234 | openMode = QIODevice::WriteOnly; 1235 | 1236 | if( file.open(openMode) == true ) 1237 | { 1238 | file.seek(file.size() ); 1239 | QString rowData = ""; 1240 | 1241 | for(int i = 0 ; i < ui->viewTxRxResult->horizontalHeader()->count() ; i ++ ) 1242 | { 1243 | if( i != ui->viewTxRxResult->horizontalHeader()->count() - 1) 1244 | rowData += m_modelTxRxResult->horizontalHeaderItem(i)->text() + ","; 1245 | else 1246 | rowData += m_modelTxRxResult->horizontalHeaderItem(i)->text() + "\n"; 1247 | 1248 | } 1249 | 1250 | file.write(rowData.toLatin1()); 1251 | rowData = ""; 1252 | 1253 | for(int i = 0 ; i < m_txRxResultMaxRow; i ++ ) 1254 | { 1255 | 1256 | QList items; 1257 | items = m_modelTxRxResult->takeRow(0); 1258 | rowData = ""; 1259 | rowData += " " + items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::TIMESTAMP)->text() + ","; 1260 | rowData += items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::STATUS)->text() + ","; 1261 | rowData += items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::MODE)->text() + ","; 1262 | rowData += items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::RAWDATA)->text() + ","; 1263 | rowData += items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::CRC)->text() + ","; 1264 | rowData += items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::SLAVE_ADDR)->text() + ","; 1265 | rowData += items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::FUNCTION)->text() + ","; 1266 | rowData += items.at(MODBUS_WND_TXRX_RESULT_COLUMNS::INFO)->text() + "\n"; 1267 | 1268 | file.write(rowData.toLatin1()); 1269 | 1270 | foreach(QStandardItem* item, items) 1271 | { 1272 | if( item != 0 ) 1273 | delete item; 1274 | } 1275 | } 1276 | file.flush(); 1277 | } 1278 | else 1279 | { 1280 | qWarning() << Q_FUNC_INFO << "file save fail" << file.errorString(); 1281 | 1282 | } 1283 | file.close(); 1284 | 1285 | } 1286 | 1287 | } 1288 | 1289 | void ModbusWnd::onViewTxQueueDataSelectionCurrentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) 1290 | { 1291 | } 1292 | 1293 | 1294 | void ModbusWnd::sendModelTxPktQueue(int index ) 1295 | { 1296 | if( index >= m_modelTxPktQueue->rowCount() ) 1297 | { 1298 | qDebug() << Q_FUNC_INFO << "index overflow"; 1299 | return; 1300 | } 1301 | 1302 | QByteArray sendData; 1303 | sendData = QByteArray::fromHex( m_modelTxPktQueue->item(index, MODBUS_WND_TX_QUEUE_COLUMNS::HEX )->text().toLatin1() ); 1304 | 1305 | // qDebug() << Q_FUNC_INFO << sendData.toHex(); 1306 | 1307 | QMetaObject::invokeMethod(m_port, "sendData", Qt::BlockingQueuedConnection, 1308 | Q_ARG(QByteArray, sendData )); 1309 | } 1310 | 1311 | void ModbusWnd::onReadyEntered() 1312 | { 1313 | // qDebug() << Q_FUNC_INFO; 1314 | static int index = 0; 1315 | 1316 | if( m_modelTxPktQueue->rowCount() == 0) 1317 | { 1318 | return; 1319 | } 1320 | 1321 | for(int count = 0; count < m_modelTxPktQueue->rowCount(); count ++) 1322 | { 1323 | int position = (index + count) % m_modelTxPktQueue->rowCount(); 1324 | 1325 | if( m_modelTxPktQueue->item(position, MODBUS_WND_TX_QUEUE_COLUMNS::ENABLE )->checkState() == Qt::Checked ) 1326 | { 1327 | m_timerAutoSend->stop(); 1328 | sendModelTxPktQueue(position); 1329 | index = (position+1) % m_modelTxPktQueue->rowCount(); 1330 | break; 1331 | } 1332 | else 1333 | { 1334 | m_timerAutoSend->start(); 1335 | } 1336 | } 1337 | } 1338 | 1339 | QByteArray ModbusWnd::toHexString(QByteArray buf) 1340 | { 1341 | QByteArray temp = ""; 1342 | for(int i =0; i < buf.count() ; i ++ ) 1343 | { 1344 | if( i == buf.count() -1 ) 1345 | temp += buf.mid(i, 1).toHex(); 1346 | else 1347 | temp += buf.mid(i, 1).toHex() + " "; 1348 | } 1349 | return temp; 1350 | } 1351 | 1352 | bool ModbusWnd::check_ModbusRTU_CRC16(QByteArray buf, quint16 &result) 1353 | { 1354 | if( buf.size() >= 4 ) 1355 | { 1356 | QByteArray srcCrc = buf.mid(buf.size()-2, 2); 1357 | QByteArray dstCrc = ""; 1358 | quint16 crc = ModbusWnd::ModbusRTU_CRC16(buf.constData(), buf.size() -2 ); 1359 | dstCrc = QByteArray::fromRawData((char*)&crc, 2); 1360 | result = crc; 1361 | 1362 | // qDebug() << Q_FUNC_INFO << "src crc " << srcCrc.toHex() << "dst crc" << dstCrc.toHex(); 1363 | 1364 | if( srcCrc == dstCrc ) 1365 | { 1366 | return true; 1367 | } 1368 | else 1369 | { 1370 | return false; 1371 | } 1372 | } 1373 | result = 0xffff; 1374 | return false; 1375 | } 1376 | 1377 | quint16 ModbusWnd::ModbusRTU_CRC16 (const char *buf, quint16 wLength) 1378 | { 1379 | static const quint16 wCRCTable[] = { 1380 | 0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241, 1381 | 0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440, 1382 | 0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40, 1383 | 0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841, 1384 | 0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40, 1385 | 0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41, 1386 | 0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641, 1387 | 0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040, 1388 | 0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240, 1389 | 0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441, 1390 | 0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41, 1391 | 0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840, 1392 | 0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41, 1393 | 0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40, 1394 | 0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640, 1395 | 0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041, 1396 | 0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240, 1397 | 0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441, 1398 | 0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41, 1399 | 0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840, 1400 | 0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41, 1401 | 0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40, 1402 | 0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640, 1403 | 0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041, 1404 | 0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241, 1405 | 0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440, 1406 | 0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40, 1407 | 0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841, 1408 | 0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40, 1409 | 0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41, 1410 | 0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641, 1411 | 0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 }; 1412 | 1413 | quint8 nTemp; 1414 | quint16 CRC16 = 0xFFFF; 1415 | 1416 | while (wLength--) 1417 | { 1418 | nTemp = *buf++ ^ CRC16; 1419 | CRC16 >>= 8; 1420 | CRC16 ^= wCRCTable[nTemp]; 1421 | } 1422 | return CRC16; 1423 | } // End: CRC16 1424 | 1425 | 1426 | quint8 ModbusWnd::LSBUS_sum (QByteArray buf) 1427 | { 1428 | quint8 sum = 0x00; 1429 | for ( int i = 1 ; i < buf.count() ; i ++ ) 1430 | { 1431 | // qDebug() << QByteArray(1, buf.at(i)).toHex(); 1432 | sum += buf.at(i); 1433 | } 1434 | // qDebug() << "sum" << QByteArray(1, sum).toHex(); 1435 | return sum; 1436 | } 1437 | 1438 | QByteArray ModbusWnd::makeRTUFrame(QByteArray slaveAddr, QByteArray functionCode, QByteArray startAddr, 1439 | QByteArray numOfRegister, QByteArray byteCount, const QByteArray writeData) 1440 | { 1441 | Q_ASSERT(writeData.size() <= 252 * 2); // because of hex string 1442 | QByteArray modbusPDU = ""; 1443 | 1444 | 1445 | 1446 | switch( QByteArray::fromHex(functionCode).at(0) ) 1447 | { 1448 | case 0x03: 1449 | modbusPDU += functionCode + startAddr + numOfRegister; 1450 | break; 1451 | case 0x04: 1452 | modbusPDU += functionCode + startAddr + numOfRegister; 1453 | break; 1454 | case 0x06: 1455 | modbusPDU += functionCode + startAddr + writeData; 1456 | break; 1457 | case 0x10: 1458 | modbusPDU += functionCode + startAddr + numOfRegister + byteCount + writeData; 1459 | break; 1460 | default: 1461 | modbusPDU += functionCode + startAddr + writeData; 1462 | break; 1463 | } 1464 | 1465 | QByteArray frame =""; 1466 | QDataStream ds(&frame, QIODevice::WriteOnly); 1467 | ds.setByteOrder(QDataStream::LittleEndian); 1468 | 1469 | 1470 | ds << quint8(QByteArray::fromHex(slaveAddr).at(0)); 1471 | // QByteArray 의 경우 0x00 데이터가 있는 경우, size() 로 check 안되므로 toHex 처리 1472 | ds.writeRawData(QByteArray::fromHex(modbusPDU).constData(), modbusPDU.size() /2 ); 1473 | quint16 crc = ModbusRTU_CRC16(frame.constData(), frame.size()); 1474 | 1475 | ds << quint16(crc); 1476 | 1477 | // qDebug() << slaveAddr << functionCode << startAddr << numOfRegister << writeData; 1478 | // qDebug() << Q_FUNC_INFO << modbusPDU << frame.toHex(); 1479 | 1480 | return frame; 1481 | } 1482 | 1483 | QByteArray ModbusWnd::makeLSBUSFrame(QByteArray slaveAddr, QByteArray functionCode, QByteArray startAddr, 1484 | QByteArray numOfRegister, QByteArray byteCount, const QByteArray writeData) 1485 | { 1486 | Q_ASSERT(writeData.size() <= 252); 1487 | QByteArray modbusPDU = ""; 1488 | 1489 | switch( QByteArray::fromHex(functionCode).at(0) ) 1490 | { 1491 | case 0x52: 1492 | modbusPDU += slaveAddr + QByteArray::fromHex(functionCode).at(0) + startAddr + numOfRegister.right(1); 1493 | break; 1494 | case 0x57: 1495 | modbusPDU += slaveAddr + QByteArray::fromHex(functionCode).at(0) + startAddr + numOfRegister.right(1) + writeData; 1496 | break; 1497 | case 0x58: 1498 | break; 1499 | case 0x59: 1500 | break; 1501 | default: 1502 | break; 1503 | } 1504 | 1505 | QByteArray frame =""; 1506 | QDataStream ds(&frame, QIODevice::WriteOnly); 1507 | ds.setByteOrder(QDataStream::LittleEndian); 1508 | 1509 | ds << quint8(0x05); 1510 | // QByteArray 의 경우 0x00 데이터가 있는 경우, size() 로 check 안되므로 toHex 처리 1511 | ds.writeRawData(modbusPDU.constData(), modbusPDU.size()); 1512 | 1513 | quint8 sum = LSBUS_sum(frame); 1514 | ds.writeRawData( QByteArray::number(sum, 16).toUpper().constData(), 2 ); 1515 | 1516 | // qDebug() << slaveAddr << QByteArray::fromHex(functionCode).at(0) << startAddr << numOfRegister.right(2) << writeData << QByteArray::number(sum, 16); 1517 | 1518 | ds << quint8(0x04); 1519 | return frame; 1520 | } 1521 | 1522 | 1523 | 1524 | 1525 | 1526 | 1527 | -------------------------------------------------------------------------------- /CRC.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file CRC.h 3 | @author Daniel Bahr 4 | @version 0.2.0.6 5 | @copyright 6 | @parblock 7 | CRC++ 8 | Copyright (c) 2016, Daniel Bahr 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of CRC++ nor the names of its 22 | contributors may be used to endorse or promote products derived from 23 | this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | @endparblock 36 | */ 37 | 38 | /* 39 | CRC++ can be configured by setting various #defines before #including this header file: 40 | 41 | #define crcpp_uint8 - Specifies the type used to store CRCs that have a width of 8 bits or less. 42 | This type is not used in CRC calculations. Defaults to ::std::uint8_t. 43 | #define crcpp_uint16 - Specifies the type used to store CRCs that have a width between 9 and 16 bits (inclusive). 44 | This type is not used in CRC calculations. Defaults to ::std::uint16_t. 45 | #define crcpp_uint32 - Specifies the type used to store CRCs that have a width between 17 and 32 bits (inclusive). 46 | This type is not used in CRC calculations. Defaults to ::std::uint32_t. 47 | #define crcpp_uint64 - Specifies the type used to store CRCs that have a width between 33 and 64 bits (inclusive). 48 | This type is not used in CRC calculations. Defaults to ::std::uint64_t. 49 | #define crcpp_size - This type is used for loop iteration and function signatures only. Defaults to ::std::size_t. 50 | #define CRCPP_USE_NAMESPACE - Define to place all CRC++ code within the ::CRCPP namespace. 51 | #define CRCPP_BRANCHLESS - Define to enable a branchless CRC implementation. The branchless implementation uses a single integer 52 | multiplication in the bit-by-bit calculation instead of a small conditional. The branchless implementation 53 | may be faster on processor architectures which support single-instruction integer multiplication. 54 | #define CRCPP_USE_CPP11 - Define to enables C++11 features (move semantics, constexpr, static_assert, etc.). 55 | #define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS - Define to include definitions for little-used CRCs. 56 | */ 57 | 58 | #ifndef CRCPP_CRC_H_ 59 | #define CRCPP_CRC_H_ 60 | 61 | #include // Includes CHAR_BIT 62 | #ifdef CRCPP_USE_CPP11 63 | #include // Includes ::std::size_t 64 | #include // Includes ::std::uint8_t, ::std::uint16_t, ::std::uint32_t, ::std::uint64_t 65 | #else 66 | #include // Includes size_t 67 | #include // Includes uint8_t, uint16_t, uint32_t, uint64_t 68 | #endif 69 | #include // Includes ::std::numeric_limits 70 | #include // Includes ::std::move 71 | 72 | #ifndef crcpp_uint8 73 | # ifdef CRCPP_USE_CPP11 74 | /// @brief Unsigned 8-bit integer definition, used primarily for parameter definitions. 75 | # define crcpp_uint8 ::std::uint8_t 76 | # else 77 | /// @brief Unsigned 8-bit integer definition, used primarily for parameter definitions. 78 | # define crcpp_uint8 uint8_t 79 | # endif 80 | #endif 81 | 82 | #ifndef crcpp_uint16 83 | # ifdef CRCPP_USE_CPP11 84 | /// @brief Unsigned 16-bit integer definition, used primarily for parameter definitions. 85 | # define crcpp_uint16 ::std::uint16_t 86 | # else 87 | /// @brief Unsigned 16-bit integer definition, used primarily for parameter definitions. 88 | # define crcpp_uint16 uint16_t 89 | # endif 90 | #endif 91 | 92 | #ifndef crcpp_uint32 93 | # ifdef CRCPP_USE_CPP11 94 | /// @brief Unsigned 32-bit integer definition, used primarily for parameter definitions. 95 | # define crcpp_uint32 ::std::uint32_t 96 | # else 97 | /// @brief Unsigned 32-bit integer definition, used primarily for parameter definitions. 98 | # define crcpp_uint32 uint32_t 99 | # endif 100 | #endif 101 | 102 | #ifndef crcpp_uint64 103 | # ifdef CRCPP_USE_CPP11 104 | /// @brief Unsigned 64-bit integer definition, used primarily for parameter definitions. 105 | # define crcpp_uint64 ::std::uint64_t 106 | # else 107 | /// @brief Unsigned 64-bit integer definition, used primarily for parameter definitions. 108 | # define crcpp_uint64 uint64_t 109 | # endif 110 | #endif 111 | 112 | #ifndef crcpp_size 113 | # ifdef CRCPP_USE_CPP11 114 | /// @brief Unsigned size definition, used for specifying data sizes. 115 | # define crcpp_size ::std::size_t 116 | # else 117 | /// @brief Unsigned size definition, used for specifying data sizes. 118 | # define crcpp_size size_t 119 | # endif 120 | #endif 121 | 122 | #ifdef CRCPP_USE_CPP11 123 | /// @brief Compile-time expression definition. 124 | # define crcpp_constexpr constexpr 125 | #else 126 | /// @brief Compile-time expression definition. 127 | # define crcpp_constexpr const 128 | #endif 129 | 130 | #ifdef CRCPP_USE_NAMESPACE 131 | namespace CRCPP 132 | { 133 | #endif 134 | 135 | /** 136 | @brief Static class for computing CRCs. 137 | @note This class supports computation of full and multi-part CRCs, using a bit-by-bit algorithm or a 138 | byte-by-byte lookup table. The CRCs are calculated using as many optimizations as is reasonable. 139 | If compiling with C++11, the constexpr keyword is used liberally so that many calculations are 140 | performed at compile-time instead of at runtime. 141 | */ 142 | class CRC 143 | { 144 | public: 145 | // Forward declaration 146 | template 147 | struct Table; 148 | 149 | /** 150 | @brief CRC parameters. 151 | */ 152 | template 153 | struct Parameters 154 | { 155 | CRCType polynomial; ///< CRC polynomial 156 | CRCType initialValue; ///< Initial CRC value 157 | CRCType finalXOR; ///< Value to XOR with the final CRC 158 | bool reflectInput; ///< true to reflect all input bytes 159 | bool reflectOutput; ///< true to reflect the output CRC (reflection occurs before the final XOR) 160 | 161 | Table MakeTable() const; 162 | }; 163 | 164 | /** 165 | @brief CRC lookup table. After construction, the CRC parameters are fixed. 166 | @note A CRC table can be used for multiple CRC calculations. 167 | */ 168 | template 169 | struct Table 170 | { 171 | // Constructors are intentionally NOT marked explicit. 172 | Table(const Parameters & parameters); 173 | 174 | #ifdef CRCPP_USE_CPP11 175 | Table(Parameters && parameters); 176 | #endif 177 | 178 | const Parameters & GetParameters() const; 179 | 180 | const CRCType * GetTable() const; 181 | 182 | CRCType operator[](unsigned char index) const; 183 | 184 | private: 185 | void InitTable(); 186 | 187 | Parameters parameters; ///< CRC parameters used to construct the table 188 | CRCType table[1 << CHAR_BIT]; ///< CRC lookup table 189 | }; 190 | 191 | // The number of bits in CRCType must be at least as large as CRCWidth. 192 | // CRCType must be an unsigned integer type or a custom type with operator overloads. 193 | template 194 | static CRCType Calculate(const void * data, crcpp_size size, const Parameters & parameters); 195 | 196 | template 197 | static CRCType Calculate(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc); 198 | 199 | template 200 | static CRCType Calculate(const void * data, crcpp_size size, const Table & lookupTable); 201 | 202 | template 203 | static CRCType Calculate(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc); 204 | 205 | // Common CRCs up to 64 bits. 206 | // Note: Check values are the computed CRCs when given an ASCII input of "123456789" (without null terminator) 207 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 208 | static const Parameters< crcpp_uint8, 4> & CRC_4_ITU(); 209 | static const Parameters< crcpp_uint8, 5> & CRC_5_EPC(); 210 | static const Parameters< crcpp_uint8, 5> & CRC_5_ITU(); 211 | static const Parameters< crcpp_uint8, 5> & CRC_5_USB(); 212 | static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000A(); 213 | static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000B(); 214 | static const Parameters< crcpp_uint8, 6> & CRC_6_ITU(); 215 | static const Parameters< crcpp_uint8, 7> & CRC_7(); 216 | #endif 217 | static const Parameters< crcpp_uint8, 8> & CRC_8(); 218 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 219 | static const Parameters< crcpp_uint8, 8> & CRC_8_EBU(); 220 | static const Parameters< crcpp_uint8, 8> & CRC_8_MAXIM(); 221 | static const Parameters< crcpp_uint8, 8> & CRC_8_WCDMA(); 222 | static const Parameters & CRC_10(); 223 | static const Parameters & CRC_10_CDMA2000(); 224 | static const Parameters & CRC_11(); 225 | static const Parameters & CRC_12_CDMA2000(); 226 | static const Parameters & CRC_12_DECT(); 227 | static const Parameters & CRC_12_UMTS(); 228 | static const Parameters & CRC_13_BBC(); 229 | static const Parameters & CRC_15(); 230 | static const Parameters & CRC_15_MPT1327(); 231 | #endif 232 | static const Parameters & CRC_16_ARC(); 233 | static const Parameters & CRC_16_BUYPASS(); 234 | static const Parameters & CRC_16_CCITTFALSE(); 235 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 236 | static const Parameters & CRC_16_CDMA2000(); 237 | static const Parameters & CRC_16_DECTR(); 238 | static const Parameters & CRC_16_DECTX(); 239 | static const Parameters & CRC_16_DNP(); 240 | #endif 241 | static const Parameters & CRC_16_GENIBUS(); 242 | static const Parameters & CRC_16_KERMIT(); 243 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 244 | static const Parameters & CRC_16_MAXIM(); 245 | static const Parameters & CRC_16_MODBUS(); 246 | static const Parameters & CRC_16_T10DIF(); 247 | static const Parameters & CRC_16_USB(); 248 | #endif 249 | static const Parameters & CRC_16_X25(); 250 | static const Parameters & CRC_16_XMODEM(); 251 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 252 | static const Parameters & CRC_17_CAN(); 253 | static const Parameters & CRC_21_CAN(); 254 | static const Parameters & CRC_24(); 255 | static const Parameters & CRC_24_FLEXRAYA(); 256 | static const Parameters & CRC_24_FLEXRAYB(); 257 | static const Parameters & CRC_30(); 258 | #endif 259 | static const Parameters & CRC_32(); 260 | static const Parameters & CRC_32_BZIP2(); 261 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 262 | static const Parameters & CRC_32_C(); 263 | #endif 264 | static const Parameters & CRC_32_MPEG2(); 265 | static const Parameters & CRC_32_POSIX(); 266 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 267 | static const Parameters & CRC_32_Q(); 268 | static const Parameters & CRC_40_GSM(); 269 | static const Parameters & CRC_64(); 270 | #endif 271 | 272 | #ifdef CRCPP_USE_CPP11 273 | CRC() = delete; 274 | CRC(const CRC & other) = delete; 275 | CRC & operator=(const CRC & other) = delete; 276 | CRC(CRC && other) = delete; 277 | CRC & operator=(CRC && other) = delete; 278 | #endif 279 | 280 | private: 281 | #ifndef CRCPP_USE_CPP11 282 | CRC(); 283 | CRC(const CRC & other); 284 | CRC & operator=(const CRC & other); 285 | #endif 286 | 287 | template 288 | static IntegerType Reflect(IntegerType value, crcpp_uint16 numBits); 289 | 290 | template 291 | static CRCType Finalize(CRCType remainder, CRCType finalXOR, bool reflectOutput); 292 | 293 | template 294 | static CRCType UndoFinalize(CRCType remainder, CRCType finalXOR, bool reflectOutput); 295 | 296 | template 297 | static CRCType CalculateRemainder(const void * data, crcpp_size size, const Parameters & parameters, CRCType remainder); 298 | 299 | template 300 | static CRCType CalculateRemainder(const void * data, crcpp_size size, const Table & lookupTable, CRCType remainder); 301 | 302 | template 303 | static crcpp_constexpr IntegerType BoundedConstexprValue(IntegerType x); 304 | }; 305 | 306 | /** 307 | @brief Returns a CRC lookup table construct using these CRC parameters. 308 | @note This function primarily exists to allow use of the auto keyword instead of instantiating 309 | a table directly, since template parameters are not inferred in constructors. 310 | @tparam CRCType Integer type for storing the CRC result 311 | @tparam CRCWidth Number of bits in the CRC 312 | @return CRC lookup table 313 | */ 314 | template 315 | inline CRC::Table CRC::Parameters::MakeTable() const 316 | { 317 | // This should take advantage of RVO and optimize out the copy. 318 | return CRC::Table(*this); 319 | } 320 | 321 | /** 322 | @brief Constructs a CRC table from a set of CRC parameters 323 | @param[in] parameters CRC parameters 324 | @tparam CRCType Integer type for storing the CRC result 325 | @tparam CRCWidth Number of bits in the CRC 326 | */ 327 | template 328 | inline CRC::Table::Table(const Parameters & parameters) : 329 | parameters(parameters) 330 | { 331 | InitTable(); 332 | } 333 | 334 | #ifdef CRCPP_USE_CPP11 335 | /** 336 | @brief Constructs a CRC table from a set of CRC parameters 337 | @param[in] parameters CRC parameters 338 | @tparam CRCType Integer type for storing the CRC result 339 | @tparam CRCWidth Number of bits in the CRC 340 | */ 341 | template 342 | inline CRC::Table::Table(Parameters && parameters) : 343 | parameters(::std::move(parameters)) 344 | { 345 | InitTable(); 346 | } 347 | #endif 348 | 349 | /** 350 | @brief Gets the CRC parameters used to construct the CRC table 351 | @tparam CRCType Integer type for storing the CRC result 352 | @tparam CRCWidth Number of bits in the CRC 353 | @return CRC parameters 354 | */ 355 | template 356 | inline const CRC::Parameters & CRC::Table::GetParameters() const 357 | { 358 | return parameters; 359 | } 360 | 361 | /** 362 | @brief Gets the CRC table 363 | @tparam CRCType Integer type for storing the CRC result 364 | @tparam CRCWidth Number of bits in the CRC 365 | @return CRC table 366 | */ 367 | template 368 | inline const CRCType * CRC::Table::GetTable() const 369 | { 370 | return table; 371 | } 372 | 373 | /** 374 | @brief Gets an entry in the CRC table 375 | @param[in] index Index into the CRC table 376 | @tparam CRCType Integer type for storing the CRC result 377 | @tparam CRCWidth Number of bits in the CRC 378 | @return CRC table entry 379 | */ 380 | template 381 | inline CRCType CRC::Table::operator[](unsigned char index) const 382 | { 383 | return table[index]; 384 | } 385 | 386 | /** 387 | @brief Initializes a CRC table. 388 | @tparam CRCType Integer type for storing the CRC result 389 | @tparam CRCWidth Number of bits in the CRC 390 | */ 391 | template 392 | inline void CRC::Table::InitTable() 393 | { 394 | // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) 395 | static crcpp_constexpr CRCType BIT_MASK((CRCType(1) << (CRCWidth - CRCType(1))) | 396 | ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1))); 397 | 398 | static crcpp_constexpr CRCType SHIFT(CRC::BoundedConstexprValue(CHAR_BIT - CRCWidth)); 399 | 400 | CRCType crc; 401 | unsigned char byte = 0; 402 | 403 | // Loop over each dividend (each possible number storable in an unsigned char) 404 | do 405 | { 406 | crc = CRC::CalculateRemainder(&byte, sizeof(byte), parameters, CRCType(0)); 407 | 408 | // This mask might not be necessary; all unit tests pass with this line commented out, 409 | // but that might just be a coincidence based on the CRC parameters used for testing. 410 | // In any case, this is harmless to leave in and only adds a single machine instruction per loop iteration. 411 | crc &= BIT_MASK; 412 | 413 | if (!parameters.reflectInput && CRCWidth < CHAR_BIT) 414 | { 415 | // Undo the special operation at the end of the CalculateRemainder() 416 | // function for non-reflected CRCs < CHAR_BIT. 417 | crc <<= SHIFT; 418 | } 419 | 420 | table[byte] = crc; 421 | } 422 | while (++byte); 423 | } 424 | 425 | /** 426 | @brief Computes a CRC. 427 | @param[in] data Data over which CRC will be computed 428 | @param[in] size Size of the data 429 | @param[in] parameters CRC parameters 430 | @tparam CRCType Integer type for storing the CRC result 431 | @tparam CRCWidth Number of bits in the CRC 432 | @return CRC 433 | */ 434 | template 435 | inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Parameters & parameters) 436 | { 437 | CRCType remainder = CalculateRemainder(data, size, parameters, parameters.initialValue); 438 | 439 | // No need to mask the remainder here; the mask will be applied in the Finalize() function. 440 | 441 | return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); 442 | } 443 | /** 444 | @brief Appends additional data to a previous CRC calculation. 445 | @note This function can be used to compute multi-part CRCs. 446 | @param[in] data Data over which CRC will be computed 447 | @param[in] size Size of the data 448 | @param[in] parameters CRC parameters 449 | @param[in] crc CRC from a previous calculation 450 | @tparam CRCType Integer type for storing the CRC result 451 | @tparam CRCWidth Number of bits in the CRC 452 | @return CRC 453 | */ 454 | template 455 | inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc) 456 | { 457 | CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); 458 | 459 | remainder = CalculateRemainder(data, size, parameters, remainder); 460 | 461 | // No need to mask the remainder here; the mask will be applied in the Finalize() function. 462 | 463 | return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); 464 | } 465 | 466 | /** 467 | @brief Computes a CRC via a lookup table. 468 | @param[in] data Data over which CRC will be computed 469 | @param[in] size Size of the data 470 | @param[in] lookupTable CRC lookup table 471 | @tparam CRCType Integer type for storing the CRC result 472 | @tparam CRCWidth Number of bits in the CRC 473 | @return CRC 474 | */ 475 | template 476 | inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table & lookupTable) 477 | { 478 | const Parameters & parameters = lookupTable.GetParameters(); 479 | 480 | CRCType remainder = CalculateRemainder(data, size, lookupTable, parameters.initialValue); 481 | 482 | // No need to mask the remainder here; the mask will be applied in the Finalize() function. 483 | 484 | return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); 485 | } 486 | 487 | /** 488 | @brief Appends additional data to a previous CRC calculation using a lookup table. 489 | @note This function can be used to compute multi-part CRCs. 490 | @param[in] data Data over which CRC will be computed 491 | @param[in] size Size of the data 492 | @param[in] lookupTable CRC lookup table 493 | @param[in] crc CRC from a previous calculation 494 | @tparam CRCType Integer type for storing the CRC result 495 | @tparam CRCWidth Number of bits in the CRC 496 | @return CRC 497 | */ 498 | template 499 | inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc) 500 | { 501 | const Parameters & parameters = lookupTable.GetParameters(); 502 | 503 | CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); 504 | 505 | remainder = CalculateRemainder(data, size, lookupTable, remainder); 506 | 507 | // No need to mask the remainder here; the mask will be applied in the Finalize() function. 508 | 509 | return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); 510 | } 511 | 512 | /** 513 | @brief Reflects (i.e. reverses the bits within) an integer value. 514 | @param[in] value Value to reflect 515 | @param[in] numBits Number of bits in the integer which will be reflected 516 | @tparam IntegerType Integer type of the value being reflected 517 | @return Reflected value 518 | */ 519 | template 520 | inline IntegerType CRC::Reflect(IntegerType value, crcpp_uint16 numBits) 521 | { 522 | IntegerType reversedValue(0); 523 | 524 | for (crcpp_uint16 i = 0; i < numBits; ++i) 525 | { 526 | reversedValue = (reversedValue << 1) | (value & 1); 527 | value >>= 1; 528 | } 529 | 530 | return reversedValue; 531 | } 532 | 533 | /** 534 | @brief Computes the final reflection and XOR of a CRC remainder. 535 | @param[in] remainder CRC remainder to reflect and XOR 536 | @param[in] finalXOR Final value to XOR with the remainder 537 | @param[in] reflectOutput true to reflect each byte of the remainder before the XOR 538 | @tparam CRCType Integer type for storing the CRC result 539 | @tparam CRCWidth Number of bits in the CRC 540 | @return Final CRC 541 | */ 542 | template 543 | inline CRCType CRC::Finalize(CRCType remainder, CRCType finalXOR, bool reflectOutput) 544 | { 545 | // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) 546 | static crcpp_constexpr CRCType BIT_MASK = (CRCType(1) << (CRCWidth - CRCType(1))) | 547 | ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1)); 548 | 549 | if (reflectOutput) 550 | { 551 | remainder = Reflect(remainder, CRCWidth); 552 | } 553 | 554 | return (remainder ^ finalXOR) & BIT_MASK; 555 | } 556 | 557 | /** 558 | @brief Undoes the process of computing the final reflection and XOR of a CRC remainder. 559 | @note This function allows for computation of multi-part CRCs 560 | @note Calling UndoFinalize() followed by Finalize() (or vice versa) will always return the original remainder value: 561 | 562 | CRCType x = ...; 563 | CRCType y = Finalize(x, finalXOR, reflectOutput); 564 | CRCType z = UndoFinalize(y, finalXOR, reflectOutput); 565 | assert(x == z); 566 | 567 | @param[in] crc Reflected and XORed CRC 568 | @param[in] finalXOR Final value XORed with the remainder 569 | @param[in] reflectOutput true if the remainder is to be reflected 570 | @tparam CRCType Integer type for storing the CRC result 571 | @tparam CRCWidth Number of bits in the CRC 572 | @return Un-finalized CRC remainder 573 | */ 574 | template 575 | inline CRCType CRC::UndoFinalize(CRCType crc, CRCType finalXOR, bool reflectOutput) 576 | { 577 | // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) 578 | static crcpp_constexpr CRCType BIT_MASK = (CRCType(1) << (CRCWidth - CRCType(1))) | 579 | ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1)); 580 | 581 | crc = (crc & BIT_MASK) ^ finalXOR; 582 | 583 | if (reflectOutput) 584 | { 585 | crc = Reflect(crc, CRCWidth); 586 | } 587 | 588 | return crc; 589 | } 590 | 591 | /** 592 | @brief Computes a CRC remainder. 593 | @param[in] data Data over which the remainder will be computed 594 | @param[in] size Size of the data 595 | @param[in] parameters CRC parameters 596 | @param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation. 597 | @tparam CRCType Integer type for storing the CRC result 598 | @tparam CRCWidth Number of bits in the CRC 599 | @return CRC remainder 600 | */ 601 | template 602 | inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const Parameters & parameters, CRCType remainder) 603 | { 604 | #ifdef CRCPP_USE_CPP11 605 | // This static_assert is put here because this function will always be compiled in no matter what 606 | // the template parameters are and whether or not a table lookup or bit-by-bit algorithm is used. 607 | static_assert(::std::numeric_limits::digits >= CRCWidth, "CRCType is too small to contain a CRC of width CRCWidth."); 608 | #else 609 | // Catching this compile-time error is very important. Sadly, the compiler error will be very cryptic, but it's 610 | // better than nothing. 611 | enum { static_assert_failed_CRCType_is_too_small_to_contain_a_CRC_of_width_CRCWidth = 1 / (::std::numeric_limits::digits >= CRCWidth ? 1 : 0) }; 612 | #endif 613 | 614 | const unsigned char * current = reinterpret_cast(data); 615 | 616 | // Slightly different implementations based on the parameters. The current implementations try to eliminate as much 617 | // computation from the inner loop (looping over each bit) as possible. 618 | if (parameters.reflectInput) 619 | { 620 | CRCType polynomial = CRC::Reflect(parameters.polynomial, CRCWidth); 621 | while (size--) 622 | { 623 | remainder ^= *current++; 624 | 625 | // An optimizing compiler might choose to unroll this loop. 626 | for (crcpp_size i = 0; i < CHAR_BIT; ++i) 627 | { 628 | #ifdef CRCPP_BRANCHLESS 629 | // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: 630 | // if (remainder & 1) 631 | // remainder = (remainder >> 1) ^ polynomial; 632 | // else 633 | // remainder >>= 1; 634 | remainder = (remainder >> 1) ^ ((remainder & 1) * polynomial); 635 | #else 636 | remainder = (remainder & 1) ? ((remainder >> 1) ^ polynomial) : (remainder >> 1); 637 | #endif 638 | } 639 | } 640 | } 641 | else if (CRCWidth >= CHAR_BIT) 642 | { 643 | static crcpp_constexpr CRCType CRC_WIDTH_MINUS_ONE(CRCWidth - CRCType(1)); 644 | #ifndef CRCPP_BRANCHLESS 645 | static crcpp_constexpr CRCType CRC_HIGHEST_BIT_MASK(CRCType(1) << CRC_WIDTH_MINUS_ONE); 646 | #endif 647 | static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CRCWidth - CHAR_BIT)); 648 | 649 | while (size--) 650 | { 651 | remainder ^= (static_cast(*current++) << SHIFT); 652 | 653 | // An optimizing compiler might choose to unroll this loop. 654 | for (crcpp_size i = 0; i < CHAR_BIT; ++i) 655 | { 656 | #ifdef CRCPP_BRANCHLESS 657 | // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: 658 | // if (remainder & CRC_HIGHEST_BIT_MASK) 659 | // remainder = (remainder << 1) ^ parameters.polynomial; 660 | // else 661 | // remainder <<= 1; 662 | remainder = (remainder << 1) ^ (((remainder >> CRC_WIDTH_MINUS_ONE) & 1) * parameters.polynomial); 663 | #else 664 | remainder = (remainder & CRC_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ parameters.polynomial) : (remainder << 1); 665 | #endif 666 | } 667 | } 668 | } 669 | else 670 | { 671 | static crcpp_constexpr CRCType CHAR_BIT_MINUS_ONE(CHAR_BIT - 1); 672 | #ifndef CRCPP_BRANCHLESS 673 | static crcpp_constexpr CRCType CHAR_BIT_HIGHEST_BIT_MASK(CRCType(1) << CHAR_BIT_MINUS_ONE); 674 | #endif 675 | static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CHAR_BIT - CRCWidth)); 676 | 677 | CRCType polynomial = parameters.polynomial << SHIFT; 678 | remainder <<= SHIFT; 679 | 680 | while (size--) 681 | { 682 | remainder ^= *current++; 683 | 684 | // An optimizing compiler might choose to unroll this loop. 685 | for (crcpp_size i = 0; i < CHAR_BIT; ++i) 686 | { 687 | #ifdef CRCPP_BRANCHLESS 688 | // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: 689 | // if (remainder & CHAR_BIT_HIGHEST_BIT_MASK) 690 | // remainder = (remainder << 1) ^ polynomial; 691 | // else 692 | // remainder <<= 1; 693 | remainder = (remainder << 1) ^ (((remainder >> CHAR_BIT_MINUS_ONE) & 1) * polynomial); 694 | #else 695 | remainder = (remainder & CHAR_BIT_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ polynomial) : (remainder << 1); 696 | #endif 697 | } 698 | } 699 | 700 | remainder >>= SHIFT; 701 | } 702 | 703 | return remainder; 704 | } 705 | 706 | /** 707 | @brief Computes a CRC remainder using lookup table. 708 | @param[in] data Data over which the remainder will be computed 709 | @param[in] size Size of the data 710 | @param[in] lookupTable CRC lookup table 711 | @param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation. 712 | @tparam CRCType Integer type for storing the CRC result 713 | @tparam CRCWidth Number of bits in the CRC 714 | @return CRC remainder 715 | */ 716 | template 717 | inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const Table & lookupTable, CRCType remainder) 718 | { 719 | const unsigned char * current = reinterpret_cast(data); 720 | 721 | if (lookupTable.GetParameters().reflectInput) 722 | { 723 | while (size--) 724 | { 725 | #if defined(WIN32) || defined(_WIN32) || defined(WINCE) 726 | // Disable warning about data loss when doing (remainder >> CHAR_BIT) when 727 | // remainder is one byte long. The algorithm is still correct in this case, 728 | // though it's possible that one additional machine instruction will be executed. 729 | # pragma warning (push) 730 | # pragma warning (disable : 4333) 731 | #endif 732 | remainder = (remainder >> CHAR_BIT) ^ lookupTable[static_cast(remainder ^ *current++)]; 733 | #if defined(WIN32) || defined(_WIN32) || defined(WINCE) 734 | # pragma warning (pop) 735 | #endif 736 | } 737 | } 738 | else if (CRCWidth >= CHAR_BIT) 739 | { 740 | static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CRCWidth - CHAR_BIT)); 741 | 742 | while (size--) 743 | { 744 | remainder = (remainder << CHAR_BIT) ^ lookupTable[static_cast((remainder >> SHIFT) ^ *current++)]; 745 | } 746 | } 747 | else 748 | { 749 | static crcpp_constexpr CRCType SHIFT(BoundedConstexprValue(CHAR_BIT - CRCWidth)); 750 | 751 | remainder <<= SHIFT; 752 | 753 | while (size--) 754 | { 755 | // Note: no need to mask here since remainder is guaranteed to fit in a single byte. 756 | remainder = lookupTable[static_cast(remainder ^ *current++)]; 757 | } 758 | 759 | remainder >>= SHIFT; 760 | } 761 | 762 | return remainder; 763 | } 764 | 765 | /** 766 | @brief Function to force a compile-time expression to be >= 0. 767 | @note This function is used to avoid compiler warnings because all constexpr values are evaluated 768 | in a function even in a branch will never be executed. This also means we don't need pragmas 769 | to get rid of warnings, but it still can be computed at compile-time. Win-win! 770 | @param[in] x Compile-time expression to bound 771 | @tparam CRCType Integer type for storing the CRC result 772 | @tparam CRCWidth Number of bits in the CRC 773 | @return Non-negative compile-time expression 774 | */ 775 | template 776 | inline crcpp_constexpr IntegerType CRC::BoundedConstexprValue(IntegerType x) 777 | { 778 | return (x < IntegerType(0)) ? IntegerType(0) : x; 779 | } 780 | 781 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 782 | /** 783 | @brief Returns a set of parameters for CRC-4 ITU. 784 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 785 | @note CRC-4 ITU has the following parameters and check value: 786 | - polynomial = 0x3 787 | - initial value = 0x0 788 | - final XOR = 0x0 789 | - reflect input = true 790 | - reflect output = true 791 | - check value = 0x7 792 | @return CRC-4 ITU parameters 793 | */ 794 | inline const CRC::Parameters & CRC::CRC_4_ITU() 795 | { 796 | static const Parameters parameters = { 0x3, 0x0, 0x0, true, true }; 797 | return parameters; 798 | } 799 | 800 | /** 801 | @brief Returns a set of parameters for CRC-5 EPC. 802 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 803 | @note CRC-5 EPC has the following parameters and check value: 804 | - polynomial = 0x09 805 | - initial value = 0x09 806 | - final XOR = 0x00 807 | - reflect input = false 808 | - reflect output = false 809 | - check value = 0x00 810 | @return CRC-5 EPC parameters 811 | */ 812 | inline const CRC::Parameters & CRC::CRC_5_EPC() 813 | { 814 | static const Parameters parameters = { 0x09, 0x09, 0x00, false, false }; 815 | return parameters; 816 | } 817 | 818 | /** 819 | @brief Returns a set of parameters for CRC-5 ITU. 820 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 821 | @note CRC-5 ITU has the following parameters and check value: 822 | - polynomial = 0x15 823 | - initial value = 0x00 824 | - final XOR = 0x00 825 | - reflect input = true 826 | - reflect output = true 827 | - check value = 0x07 828 | @return CRC-5 ITU parameters 829 | */ 830 | inline const CRC::Parameters & CRC::CRC_5_ITU() 831 | { 832 | static const Parameters parameters = { 0x15, 0x00, 0x00, true, true }; 833 | return parameters; 834 | } 835 | 836 | /** 837 | @brief Returns a set of parameters for CRC-5 USB. 838 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 839 | @note CRC-5 USB has the following parameters and check value: 840 | - polynomial = 0x05 841 | - initial value = 0x1F 842 | - final XOR = 0x1F 843 | - reflect input = true 844 | - reflect output = true 845 | - check value = 0x19 846 | @return CRC-5 USB parameters 847 | */ 848 | inline const CRC::Parameters & CRC::CRC_5_USB() 849 | { 850 | static const Parameters parameters = { 0x05, 0x1F, 0x1F, true, true }; 851 | return parameters; 852 | } 853 | 854 | /** 855 | @brief Returns a set of parameters for CRC-6 CDMA2000-A. 856 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 857 | @note CRC-6 CDMA2000-A has the following parameters and check value: 858 | - polynomial = 0x27 859 | - initial value = 0x3F 860 | - final XOR = 0x00 861 | - reflect input = false 862 | - reflect output = false 863 | - check value = 0x0D 864 | @return CRC-6 CDMA2000-A parameters 865 | */ 866 | inline const CRC::Parameters & CRC::CRC_6_CDMA2000A() 867 | { 868 | static const Parameters parameters = { 0x27, 0x3F, 0x00, false, false }; 869 | return parameters; 870 | } 871 | 872 | /** 873 | @brief Returns a set of parameters for CRC-6 CDMA2000-B. 874 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 875 | @note CRC-6 CDMA2000-A has the following parameters and check value: 876 | - polynomial = 0x07 877 | - initial value = 0x3F 878 | - final XOR = 0x00 879 | - reflect input = false 880 | - reflect output = false 881 | - check value = 0x3B 882 | @return CRC-6 CDMA2000-B parameters 883 | */ 884 | inline const CRC::Parameters & CRC::CRC_6_CDMA2000B() 885 | { 886 | static const Parameters parameters = { 0x07, 0x3F, 0x00, false, false }; 887 | return parameters; 888 | } 889 | 890 | /** 891 | @brief Returns a set of parameters for CRC-6 ITU. 892 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 893 | @note CRC-6 ITU has the following parameters and check value: 894 | - polynomial = 0x03 895 | - initial value = 0x00 896 | - final XOR = 0x00 897 | - reflect input = true 898 | - reflect output = true 899 | - check value = 0x06 900 | @return CRC-6 ITU parameters 901 | */ 902 | inline const CRC::Parameters & CRC::CRC_6_ITU() 903 | { 904 | static const Parameters parameters = { 0x03, 0x00, 0x00, true, true }; 905 | return parameters; 906 | } 907 | 908 | /** 909 | @brief Returns a set of parameters for CRC-7 JEDEC. 910 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 911 | @note CRC-7 JEDEC has the following parameters and check value: 912 | - polynomial = 0x09 913 | - initial value = 0x00 914 | - final XOR = 0x00 915 | - reflect input = false 916 | - reflect output = false 917 | - check value = 0x75 918 | @return CRC-7 JEDEC parameters 919 | */ 920 | inline const CRC::Parameters & CRC::CRC_7() 921 | { 922 | static const Parameters parameters = { 0x09, 0x00, 0x00, false, false }; 923 | return parameters; 924 | } 925 | #endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 926 | 927 | /** 928 | @brief Returns a set of parameters for CRC-8 SMBus. 929 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 930 | @note CRC-8 SMBus has the following parameters and check value: 931 | - polynomial = 0x07 932 | - initial value = 0x00 933 | - final XOR = 0x00 934 | - reflect input = false 935 | - reflect output = false 936 | - check value = 0xF4 937 | @return CRC-8 SMBus parameters 938 | */ 939 | inline const CRC::Parameters & CRC::CRC_8() 940 | { 941 | static const Parameters parameters = { 0x07, 0x00, 0x00, false, false }; 942 | return parameters; 943 | } 944 | 945 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 946 | /** 947 | @brief Returns a set of parameters for CRC-8 EBU (aka CRC-8 AES). 948 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 949 | @note CRC-8 EBU has the following parameters and check value: 950 | - polynomial = 0x1D 951 | - initial value = 0xFF 952 | - final XOR = 0x00 953 | - reflect input = true 954 | - reflect output = true 955 | - check value = 0x97 956 | @return CRC-8 EBU parameters 957 | */ 958 | inline const CRC::Parameters & CRC::CRC_8_EBU() 959 | { 960 | static const Parameters parameters = { 0x1D, 0xFF, 0x00, true, true }; 961 | return parameters; 962 | } 963 | 964 | /** 965 | @brief Returns a set of parameters for CRC-8 MAXIM (aka CRC-8 DOW-CRC). 966 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 967 | @note CRC-8 MAXIM has the following parameters and check value: 968 | - polynomial = 0x31 969 | - initial value = 0x00 970 | - final XOR = 0x00 971 | - reflect input = true 972 | - reflect output = true 973 | - check value = 0xA1 974 | @return CRC-8 MAXIM parameters 975 | */ 976 | inline const CRC::Parameters & CRC::CRC_8_MAXIM() 977 | { 978 | static const Parameters parameters = { 0x31, 0x00, 0x00, true, true }; 979 | return parameters; 980 | } 981 | 982 | /** 983 | @brief Returns a set of parameters for CRC-8 WCDMA. 984 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 985 | @note CRC-8 WCDMA has the following parameters and check value: 986 | - polynomial = 0x9B 987 | - initial value = 0x00 988 | - final XOR = 0x00 989 | - reflect input = true 990 | - reflect output = true 991 | - check value = 0x25 992 | @return CRC-8 WCDMA parameters 993 | */ 994 | inline const CRC::Parameters & CRC::CRC_8_WCDMA() 995 | { 996 | static const Parameters parameters = { 0x9B, 0x00, 0x00, true, true }; 997 | return parameters; 998 | } 999 | 1000 | /** 1001 | @brief Returns a set of parameters for CRC-10 ITU. 1002 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1003 | @note CRC-10 ITU has the following parameters and check value: 1004 | - polynomial = 0x233 1005 | - initial value = 0x000 1006 | - final XOR = 0x000 1007 | - reflect input = false 1008 | - reflect output = false 1009 | - check value = 0x199 1010 | @return CRC-10 ITU parameters 1011 | */ 1012 | inline const CRC::Parameters & CRC::CRC_10() 1013 | { 1014 | static const Parameters parameters = { 0x233, 0x000, 0x000, false, false }; 1015 | return parameters; 1016 | } 1017 | 1018 | /** 1019 | @brief Returns a set of parameters for CRC-10 CDMA2000. 1020 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1021 | @note CRC-10 CDMA2000 has the following parameters and check value: 1022 | - polynomial = 0x3D9 1023 | - initial value = 0x3FF 1024 | - final XOR = 0x000 1025 | - reflect input = false 1026 | - reflect output = false 1027 | - check value = 0x233 1028 | @return CRC-10 CDMA2000 parameters 1029 | */ 1030 | inline const CRC::Parameters & CRC::CRC_10_CDMA2000() 1031 | { 1032 | static const Parameters parameters = { 0x3D9, 0x3FF, 0x000, false, false }; 1033 | return parameters; 1034 | } 1035 | 1036 | /** 1037 | @brief Returns a set of parameters for CRC-11 FlexRay. 1038 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1039 | @note CRC-11 FlexRay has the following parameters and check value: 1040 | - polynomial = 0x385 1041 | - initial value = 0x01A 1042 | - final XOR = 0x000 1043 | - reflect input = false 1044 | - reflect output = false 1045 | - check value = 0x5A3 1046 | @return CRC-11 FlexRay parameters 1047 | */ 1048 | inline const CRC::Parameters & CRC::CRC_11() 1049 | { 1050 | static const Parameters parameters = { 0x385, 0x01A, 0x000, false, false }; 1051 | return parameters; 1052 | } 1053 | 1054 | /** 1055 | @brief Returns a set of parameters for CRC-12 CDMA2000. 1056 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1057 | @note CRC-12 CDMA2000 has the following parameters and check value: 1058 | - polynomial = 0xF13 1059 | - initial value = 0xFFF 1060 | - final XOR = 0x000 1061 | - reflect input = false 1062 | - reflect output = false 1063 | - check value = 0xD4D 1064 | @return CRC-12 CDMA2000 parameters 1065 | */ 1066 | inline const CRC::Parameters & CRC::CRC_12_CDMA2000() 1067 | { 1068 | static const Parameters parameters = { 0xF13, 0xFFF, 0x000, false, false }; 1069 | return parameters; 1070 | } 1071 | 1072 | /** 1073 | @brief Returns a set of parameters for CRC-12 DECT (aka CRC-12 X-CRC). 1074 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1075 | @note CRC-12 DECT has the following parameters and check value: 1076 | - polynomial = 0x80F 1077 | - initial value = 0x000 1078 | - final XOR = 0x000 1079 | - reflect input = false 1080 | - reflect output = false 1081 | - check value = 0xF5B 1082 | @return CRC-12 DECT parameters 1083 | */ 1084 | inline const CRC::Parameters & CRC::CRC_12_DECT() 1085 | { 1086 | static const Parameters parameters = { 0x80F, 0x000, 0x000, false, false }; 1087 | return parameters; 1088 | } 1089 | 1090 | /** 1091 | @brief Returns a set of parameters for CRC-12 UMTS (aka CRC-12 3GPP). 1092 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1093 | @note CRC-12 UMTS has the following parameters and check value: 1094 | - polynomial = 0x80F 1095 | - initial value = 0x000 1096 | - final XOR = 0x000 1097 | - reflect input = false 1098 | - reflect output = true 1099 | - check value = 0xDAF 1100 | @return CRC-12 UMTS parameters 1101 | */ 1102 | inline const CRC::Parameters & CRC::CRC_12_UMTS() 1103 | { 1104 | static const Parameters parameters = { 0x80F, 0x000, 0x000, false, true }; 1105 | return parameters; 1106 | } 1107 | 1108 | /** 1109 | @brief Returns a set of parameters for CRC-13 BBC. 1110 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1111 | @note CRC-13 BBC has the following parameters and check value: 1112 | - polynomial = 0x1CF5 1113 | - initial value = 0x0000 1114 | - final XOR = 0x0000 1115 | - reflect input = false 1116 | - reflect output = false 1117 | - check value = 0x04FA 1118 | @return CRC-13 BBC parameters 1119 | */ 1120 | inline const CRC::Parameters & CRC::CRC_13_BBC() 1121 | { 1122 | static const Parameters parameters = { 0x1CF5, 0x0000, 0x0000, false, false }; 1123 | return parameters; 1124 | } 1125 | 1126 | /** 1127 | @brief Returns a set of parameters for CRC-15 CAN. 1128 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1129 | @note CRC-15 CAN has the following parameters and check value: 1130 | - polynomial = 0x4599 1131 | - initial value = 0x0000 1132 | - final XOR = 0x0000 1133 | - reflect input = false 1134 | - reflect output = false 1135 | - check value = 0x059E 1136 | @return CRC-15 CAN parameters 1137 | */ 1138 | inline const CRC::Parameters & CRC::CRC_15() 1139 | { 1140 | static const Parameters parameters = { 0x4599, 0x0000, 0x0000, false, false }; 1141 | return parameters; 1142 | } 1143 | 1144 | /** 1145 | @brief Returns a set of parameters for CRC-15 MPT1327. 1146 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1147 | @note CRC-15 MPT1327 has the following parameters and check value: 1148 | - polynomial = 0x6815 1149 | - initial value = 0x0000 1150 | - final XOR = 0x0001 1151 | - reflect input = false 1152 | - reflect output = false 1153 | - check value = 0x2566 1154 | @return CRC-15 MPT1327 parameters 1155 | */ 1156 | inline const CRC::Parameters & CRC::CRC_15_MPT1327() 1157 | { 1158 | static const Parameters parameters = { 0x6815, 0x0000, 0x0001, false, false }; 1159 | return parameters; 1160 | } 1161 | #endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1162 | 1163 | /** 1164 | @brief Returns a set of parameters for CRC-16 ARC (aka CRC-16 IBM, CRC-16 LHA). 1165 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1166 | @note CRC-16 ARC has the following parameters and check value: 1167 | - polynomial = 0x8005 1168 | - initial value = 0x0000 1169 | - final XOR = 0x0000 1170 | - reflect input = true 1171 | - reflect output = true 1172 | - check value = 0xBB3D 1173 | @return CRC-16 ARC parameters 1174 | */ 1175 | inline const CRC::Parameters & CRC::CRC_16_ARC() 1176 | { 1177 | static const Parameters parameters = { 0x8005, 0x0000, 0x0000, true, true }; 1178 | return parameters; 1179 | } 1180 | 1181 | /** 1182 | @brief Returns a set of parameters for CRC-16 BUYPASS (aka CRC-16 VERIFONE, CRC-16 UMTS). 1183 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1184 | @note CRC-16 BUYPASS has the following parameters and check value: 1185 | - polynomial = 0x8005 1186 | - initial value = 0x0000 1187 | - final XOR = 0x0000 1188 | - reflect input = false 1189 | - reflect output = false 1190 | - check value = 0xFEE8 1191 | @return CRC-16 BUYPASS parameters 1192 | */ 1193 | inline const CRC::Parameters & CRC::CRC_16_BUYPASS() 1194 | { 1195 | static const Parameters parameters = { 0x8005, 0x0000, 0x0000, false, false }; 1196 | return parameters; 1197 | } 1198 | 1199 | /** 1200 | @brief Returns a set of parameters for CRC-16 CCITT FALSE. 1201 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1202 | @note CRC-16 CCITT FALSE has the following parameters and check value: 1203 | - polynomial = 0x1021 1204 | - initial value = 0xFFFF 1205 | - final XOR = 0x0000 1206 | - reflect input = false 1207 | - reflect output = false 1208 | - check value = 0x29B1 1209 | @return CRC-16 CCITT FALSE parameters 1210 | */ 1211 | inline const CRC::Parameters & CRC::CRC_16_CCITTFALSE() 1212 | { 1213 | static const Parameters parameters = { 0x1021, 0xFFFF, 0x0000, false, false }; 1214 | return parameters; 1215 | } 1216 | 1217 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1218 | /** 1219 | @brief Returns a set of parameters for CRC-16 CDMA2000. 1220 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1221 | @note CRC-16 CDMA2000 has the following parameters and check value: 1222 | - polynomial = 0xC867 1223 | - initial value = 0xFFFF 1224 | - final XOR = 0x0000 1225 | - reflect input = false 1226 | - reflect output = false 1227 | - check value = 0x4C06 1228 | @return CRC-16 CDMA2000 parameters 1229 | */ 1230 | inline const CRC::Parameters & CRC::CRC_16_CDMA2000() 1231 | { 1232 | static const Parameters parameters = { 0xC867, 0xFFFF, 0x0000, false, false }; 1233 | return parameters; 1234 | } 1235 | 1236 | /** 1237 | @brief Returns a set of parameters for CRC-16 DECT-R (aka CRC-16 R-CRC). 1238 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1239 | @note CRC-16 DECT-R has the following parameters and check value: 1240 | - polynomial = 0x0589 1241 | - initial value = 0x0000 1242 | - final XOR = 0x0001 1243 | - reflect input = false 1244 | - reflect output = false 1245 | - check value = 0x007E 1246 | @return CRC-16 DECT-R parameters 1247 | */ 1248 | inline const CRC::Parameters & CRC::CRC_16_DECTR() 1249 | { 1250 | static const Parameters parameters = { 0x0589, 0x0000, 0x0001, false, false }; 1251 | return parameters; 1252 | } 1253 | 1254 | /** 1255 | @brief Returns a set of parameters for CRC-16 DECT-X (aka CRC-16 X-CRC). 1256 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1257 | @note CRC-16 DECT-X has the following parameters and check value: 1258 | - polynomial = 0x0589 1259 | - initial value = 0x0000 1260 | - final XOR = 0x0000 1261 | - reflect input = false 1262 | - reflect output = false 1263 | - check value = 0x007F 1264 | @return CRC-16 DECT-X parameters 1265 | */ 1266 | inline const CRC::Parameters & CRC::CRC_16_DECTX() 1267 | { 1268 | static const Parameters parameters = { 0x0589, 0x0000, 0x0000, false, false }; 1269 | return parameters; 1270 | } 1271 | 1272 | /** 1273 | @brief Returns a set of parameters for CRC-16 DNP. 1274 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1275 | @note CRC-16 DNP has the following parameters and check value: 1276 | - polynomial = 0x3D65 1277 | - initial value = 0x0000 1278 | - final XOR = 0xFFFF 1279 | - reflect input = true 1280 | - reflect output = true 1281 | - check value = 0xEA82 1282 | @return CRC-16 DNP parameters 1283 | */ 1284 | inline const CRC::Parameters & CRC::CRC_16_DNP() 1285 | { 1286 | static const Parameters parameters = { 0x3D65, 0x0000, 0xFFFF, true, true }; 1287 | return parameters; 1288 | } 1289 | #endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1290 | 1291 | /** 1292 | @brief Returns a set of parameters for CRC-16 GENIBUS (aka CRC-16 EPC, CRC-16 I-CODE, CRC-16 DARC). 1293 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1294 | @note CRC-16 GENIBUS has the following parameters and check value: 1295 | - polynomial = 0x1021 1296 | - initial value = 0xFFFF 1297 | - final XOR = 0xFFFF 1298 | - reflect input = false 1299 | - reflect output = false 1300 | - check value = 0xD64E 1301 | @return CRC-16 GENIBUS parameters 1302 | */ 1303 | inline const CRC::Parameters & CRC::CRC_16_GENIBUS() 1304 | { 1305 | static const Parameters parameters = { 0x1021, 0xFFFF, 0xFFFF, false, false }; 1306 | return parameters; 1307 | } 1308 | 1309 | /** 1310 | @brief Returns a set of parameters for CRC-16 KERMIT (aka CRC-16 CCITT, CRC-16 CCITT-TRUE). 1311 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1312 | @note CRC-16 KERMIT has the following parameters and check value: 1313 | - polynomial = 0x1021 1314 | - initial value = 0x0000 1315 | - final XOR = 0x0000 1316 | - reflect input = true 1317 | - reflect output = true 1318 | - check value = 0x2189 1319 | @return CRC-16 KERMIT parameters 1320 | */ 1321 | inline const CRC::Parameters & CRC::CRC_16_KERMIT() 1322 | { 1323 | static const Parameters parameters = { 0x1021, 0x0000, 0x0000, true, true }; 1324 | return parameters; 1325 | } 1326 | 1327 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1328 | /** 1329 | @brief Returns a set of parameters for CRC-16 MAXIM. 1330 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1331 | @note CRC-16 MAXIM has the following parameters and check value: 1332 | - polynomial = 0x8005 1333 | - initial value = 0x0000 1334 | - final XOR = 0xFFFF 1335 | - reflect input = true 1336 | - reflect output = true 1337 | - check value = 0x44C2 1338 | @return CRC-16 MAXIM parameters 1339 | */ 1340 | inline const CRC::Parameters & CRC::CRC_16_MAXIM() 1341 | { 1342 | static const Parameters parameters = { 0x8005, 0x0000, 0xFFFF, true, true }; 1343 | return parameters; 1344 | } 1345 | 1346 | /** 1347 | @brief Returns a set of parameters for CRC-16 MODBUS. 1348 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1349 | @note CRC-16 MODBUS has the following parameters and check value: 1350 | - polynomial = 0x8005 1351 | - initial value = 0xFFFF 1352 | - final XOR = 0x0000 1353 | - reflect input = true 1354 | - reflect output = true 1355 | - check value = 0x4B37 1356 | @return CRC-16 MODBUS parameters 1357 | */ 1358 | inline const CRC::Parameters & CRC::CRC_16_MODBUS() 1359 | { 1360 | static const Parameters parameters = { 0x8005, 0xFFFF, 0x0000, true, true }; 1361 | return parameters; 1362 | } 1363 | 1364 | /** 1365 | @brief Returns a set of parameters for CRC-16 T10-DIF. 1366 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1367 | @note CRC-16 T10-DIF has the following parameters and check value: 1368 | - polynomial = 0x8BB7 1369 | - initial value = 0x0000 1370 | - final XOR = 0x0000 1371 | - reflect input = false 1372 | - reflect output = false 1373 | - check value = 0xD0DB 1374 | @return CRC-16 T10-DIF parameters 1375 | */ 1376 | inline const CRC::Parameters & CRC::CRC_16_T10DIF() 1377 | { 1378 | static const Parameters parameters = { 0x8BB7, 0x0000, 0x0000, false, false }; 1379 | return parameters; 1380 | } 1381 | 1382 | /** 1383 | @brief Returns a set of parameters for CRC-16 USB. 1384 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1385 | @note CRC-16 USB has the following parameters and check value: 1386 | - polynomial = 0x8005 1387 | - initial value = 0xFFFF 1388 | - final XOR = 0xFFFF 1389 | - reflect input = true 1390 | - reflect output = true 1391 | - check value = 0xB4C8 1392 | @return CRC-16 USB parameters 1393 | */ 1394 | inline const CRC::Parameters & CRC::CRC_16_USB() 1395 | { 1396 | static const Parameters parameters = { 0x8005, 0xFFFF, 0xFFFF, true, true }; 1397 | return parameters; 1398 | } 1399 | #endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1400 | 1401 | /** 1402 | @brief Returns a set of parameters for CRC-16 X-25 (aka CRC-16 IBM-SDLC, CRC-16 ISO-HDLC, CRC-16 B). 1403 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1404 | @note CRC-16 X-25 has the following parameters and check value: 1405 | - polynomial = 0x1021 1406 | - initial value = 0xFFFF 1407 | - final XOR = 0xFFFF 1408 | - reflect input = true 1409 | - reflect output = true 1410 | - check value = 0x906E 1411 | @return CRC-16 X-25 parameters 1412 | */ 1413 | inline const CRC::Parameters & CRC::CRC_16_X25() 1414 | { 1415 | static const Parameters parameters = { 0x1021, 0xFFFF, 0xFFFF, true, true }; 1416 | return parameters; 1417 | } 1418 | 1419 | /** 1420 | @brief Returns a set of parameters for CRC-16 XMODEM (aka CRC-16 ZMODEM, CRC-16 ACORN, CRC-16 LTE). 1421 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1422 | @note CRC-16 XMODEM has the following parameters and check value: 1423 | - polynomial = 0x1021 1424 | - initial value = 0x0000 1425 | - final XOR = 0x0000 1426 | - reflect input = false 1427 | - reflect output = false 1428 | - check value = 0x31C3 1429 | @return CRC-16 XMODEM parameters 1430 | */ 1431 | inline const CRC::Parameters & CRC::CRC_16_XMODEM() 1432 | { 1433 | static const Parameters parameters = { 0x1021, 0x0000, 0x0000, false, false }; 1434 | return parameters; 1435 | } 1436 | 1437 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1438 | /** 1439 | @brief Returns a set of parameters for CRC-17 CAN. 1440 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1441 | @note CRC-17 CAN has the following parameters and check value: 1442 | - polynomial = 0x1685B 1443 | - initial value = 0x00000 1444 | - final XOR = 0x00000 1445 | - reflect input = false 1446 | - reflect output = false 1447 | - check value = 0x04F03 1448 | @return CRC-17 CAN parameters 1449 | */ 1450 | inline const CRC::Parameters & CRC::CRC_17_CAN() 1451 | { 1452 | static const Parameters parameters = { 0x1685B, 0x00000, 0x00000, false, false }; 1453 | return parameters; 1454 | } 1455 | 1456 | /** 1457 | @brief Returns a set of parameters for CRC-21 CAN. 1458 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1459 | @note CRC-21 CAN has the following parameters and check value: 1460 | - polynomial = 0x102899 1461 | - initial value = 0x000000 1462 | - final XOR = 0x000000 1463 | - reflect input = false 1464 | - reflect output = false 1465 | - check value = 0x0ED841 1466 | @return CRC-21 CAN parameters 1467 | */ 1468 | inline const CRC::Parameters & CRC::CRC_21_CAN() 1469 | { 1470 | static const Parameters parameters = { 0x102899, 0x000000, 0x000000, false, false }; 1471 | return parameters; 1472 | } 1473 | 1474 | /** 1475 | @brief Returns a set of parameters for CRC-24 OPENPGP. 1476 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1477 | @note CRC-24 OPENPGP has the following parameters and check value: 1478 | - polynomial = 0x864CFB 1479 | - initial value = 0xB704CE 1480 | - final XOR = 0x000000 1481 | - reflect input = false 1482 | - reflect output = false 1483 | - check value = 0x21CF02 1484 | @return CRC-24 OPENPGP parameters 1485 | */ 1486 | inline const CRC::Parameters & CRC::CRC_24() 1487 | { 1488 | static const Parameters parameters = { 0x864CFB, 0xB704CE, 0x000000, false, false }; 1489 | return parameters; 1490 | } 1491 | 1492 | /** 1493 | @brief Returns a set of parameters for CRC-24 FlexRay-A. 1494 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1495 | @note CRC-24 FlexRay-A has the following parameters and check value: 1496 | - polynomial = 0x5D6DCB 1497 | - initial value = 0xFEDCBA 1498 | - final XOR = 0x000000 1499 | - reflect input = false 1500 | - reflect output = false 1501 | - check value = 0x7979BD 1502 | @return CRC-24 FlexRay-A parameters 1503 | */ 1504 | inline const CRC::Parameters & CRC::CRC_24_FLEXRAYA() 1505 | { 1506 | static const Parameters parameters = { 0x5D6DCB, 0xFEDCBA, 0x000000, false, false }; 1507 | return parameters; 1508 | } 1509 | 1510 | /** 1511 | @brief Returns a set of parameters for CRC-24 FlexRay-B. 1512 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1513 | @note CRC-24 FlexRay-B has the following parameters and check value: 1514 | - polynomial = 0x5D6DCB 1515 | - initial value = 0xABCDEF 1516 | - final XOR = 0x000000 1517 | - reflect input = false 1518 | - reflect output = false 1519 | - check value = 0x1F23B8 1520 | @return CRC-24 FlexRay-B parameters 1521 | */ 1522 | inline const CRC::Parameters & CRC::CRC_24_FLEXRAYB() 1523 | { 1524 | static const Parameters parameters = { 0x5D6DCB, 0xABCDEF, 0x000000, false, false }; 1525 | return parameters; 1526 | } 1527 | 1528 | /** 1529 | @brief Returns a set of parameters for CRC-30 CDMA. 1530 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1531 | @note CRC-30 CDMA has the following parameters and check value: 1532 | - polynomial = 0x2030B9C7 1533 | - initial value = 0x3FFFFFFF 1534 | - final XOR = 0x00000000 1535 | - reflect input = false 1536 | - reflect output = false 1537 | - check value = 0x3B3CB540 1538 | @return CRC-30 CDMA parameters 1539 | */ 1540 | inline const CRC::Parameters & CRC::CRC_30() 1541 | { 1542 | static const Parameters parameters = { 0x2030B9C7, 0x3FFFFFFF, 0x00000000, false, false }; 1543 | return parameters; 1544 | } 1545 | #endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1546 | 1547 | /** 1548 | @brief Returns a set of parameters for CRC-32 (aka CRC-32 ADCCP, CRC-32 PKZip). 1549 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1550 | @note CRC-32 has the following parameters and check value: 1551 | - polynomial = 0x04C11DB7 1552 | - initial value = 0xFFFFFFFF 1553 | - final XOR = 0xFFFFFFFF 1554 | - reflect input = true 1555 | - reflect output = true 1556 | - check value = 0xCBF43926 1557 | @return CRC-32 parameters 1558 | */ 1559 | inline const CRC::Parameters & CRC::CRC_32() 1560 | { 1561 | static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true }; 1562 | return parameters; 1563 | } 1564 | 1565 | /** 1566 | @brief Returns a set of parameters for CRC-32 BZIP2 (aka CRC-32 AAL5, CRC-32 DECT-B, CRC-32 B-CRC). 1567 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1568 | @note CRC-32 BZIP2 has the following parameters and check value: 1569 | - polynomial = 0x04C11DB7 1570 | - initial value = 0xFFFFFFFF 1571 | - final XOR = 0xFFFFFFFF 1572 | - reflect input = false 1573 | - reflect output = false 1574 | - check value = 0xFC891918 1575 | @return CRC-32 BZIP2 parameters 1576 | */ 1577 | inline const CRC::Parameters & CRC::CRC_32_BZIP2() 1578 | { 1579 | static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, false, false }; 1580 | return parameters; 1581 | } 1582 | 1583 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1584 | /** 1585 | @brief Returns a set of parameters for CRC-32 C (aka CRC-32 ISCSI, CRC-32 Castagnoli, CRC-32 Interlaken). 1586 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1587 | @note CRC-32 C has the following parameters and check value: 1588 | - polynomial = 0x1EDC6F41 1589 | - initial value = 0xFFFFFFFF 1590 | - final XOR = 0xFFFFFFFF 1591 | - reflect input = true 1592 | - reflect output = true 1593 | - check value = 0xE3069283 1594 | @return CRC-32 C parameters 1595 | */ 1596 | inline const CRC::Parameters & CRC::CRC_32_C() 1597 | { 1598 | static const Parameters parameters = { 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true }; 1599 | return parameters; 1600 | } 1601 | #endif 1602 | 1603 | /** 1604 | @brief Returns a set of parameters for CRC-32 MPEG-2. 1605 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1606 | @note CRC-32 MPEG-2 has the following parameters and check value: 1607 | - polynomial = 0x04C11DB7 1608 | - initial value = 0xFFFFFFFF 1609 | - final XOR = 0x00000000 1610 | - reflect input = false 1611 | - reflect output = false 1612 | - check value = 0x0376E6E7 1613 | @return CRC-32 MPEG-2 parameters 1614 | */ 1615 | inline const CRC::Parameters & CRC::CRC_32_MPEG2() 1616 | { 1617 | static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0x00000000, false, false }; 1618 | return parameters; 1619 | } 1620 | 1621 | /** 1622 | @brief Returns a set of parameters for CRC-32 POSIX. 1623 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1624 | @note CRC-32 POSIX has the following parameters and check value: 1625 | - polynomial = 0x04C11DB7 1626 | - initial value = 0x00000000 1627 | - final XOR = 0xFFFFFFFF 1628 | - reflect input = false 1629 | - reflect output = false 1630 | - check value = 0x765E7680 1631 | @return CRC-32 POSIX parameters 1632 | */ 1633 | inline const CRC::Parameters & CRC::CRC_32_POSIX() 1634 | { 1635 | static const Parameters parameters = { 0x04C11DB7, 0x00000000, 0xFFFFFFFF, false, false }; 1636 | return parameters; 1637 | } 1638 | 1639 | #ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1640 | /** 1641 | @brief Returns a set of parameters for CRC-32 Q. 1642 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1643 | @note CRC-32 Q has the following parameters and check value: 1644 | - polynomial = 0x814141AB 1645 | - initial value = 0x00000000 1646 | - final XOR = 0x00000000 1647 | - reflect input = false 1648 | - reflect output = false 1649 | - check value = 0x3010BF7F 1650 | @return CRC-32 Q parameters 1651 | */ 1652 | inline const CRC::Parameters & CRC::CRC_32_Q() 1653 | { 1654 | static const Parameters parameters = { 0x814141AB, 0x00000000, 0x00000000, false, false }; 1655 | return parameters; 1656 | } 1657 | 1658 | /** 1659 | @brief Returns a set of parameters for CRC-40 GSM. 1660 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1661 | @note CRC-40 GSM has the following parameters and check value: 1662 | - polynomial = 0x0004820009 1663 | - initial value = 0x0000000000 1664 | - final XOR = 0xFFFFFFFFFF 1665 | - reflect input = false 1666 | - reflect output = false 1667 | - check value = 0xD4164FC646 1668 | @return CRC-40 GSM parameters 1669 | */ 1670 | inline const CRC::Parameters & CRC::CRC_40_GSM() 1671 | { 1672 | static const Parameters parameters = { 0x0004820009, 0x0000000000, 0xFFFFFFFFFF, false, false }; 1673 | return parameters; 1674 | } 1675 | 1676 | /** 1677 | @brief Returns a set of parameters for CRC-64 ECMA. 1678 | @note The parameters are static and are delayed-constructed to reduce memory footprint. 1679 | @note CRC-64 ECMA has the following parameters and check value: 1680 | - polynomial = 0x42F0E1EBA9EA3693 1681 | - initial value = 0x0000000000000000 1682 | - final XOR = 0x0000000000000000 1683 | - reflect input = false 1684 | - reflect output = false 1685 | - check value = 0x6C40DF5F0B497347 1686 | @return CRC-64 ECMA parameters 1687 | */ 1688 | inline const CRC::Parameters & CRC::CRC_64() 1689 | { 1690 | static const Parameters parameters = { 0x42F0E1EBA9EA3693, 0x0000000000000000, 0x0000000000000000, false, false }; 1691 | return parameters; 1692 | } 1693 | #endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS 1694 | 1695 | #ifdef CRCPP_USE_NAMESPACE 1696 | } 1697 | #endif 1698 | 1699 | #endif // CRCPP_CRC_H_ 1700 | --------------------------------------------------------------------------------