diff --git a/Modem/Modem.cpp b/Modem/Modem.cpp new file mode 100644 index 0000000..3e44c8a --- /dev/null +++ b/Modem/Modem.cpp @@ -0,0 +1,62 @@ +#include "Modem.h" +#include "ui_modem.h" + +#include "Ymodem.h" + +Modem::Modem(QWidget *parent) : + QDialog(parent), + ui(new Ui::Modem) +{ + ui->setupUi(this); + + ym = new Ymodem(this); + connect(ym, &ym->showTransfer, this, &this->showTransfer); + connect(ym, &ym->finished, this, &this->closed); +} + +Modem::~Modem() +{ + delete ui; +} + +void Modem::getFile(QString &name) +{ + name = filename; +} + +void Modem::setFile(QString &name) +{ + filename = name; +} + +void Modem::showTransfer(int total, int remain, float speed) +{ + float p; + QString fmt; + + p = ((total - remain)/(float)total) * 100; + fmt = fmt.fromLocal8Bit("%1%").arg(QString::number(p, 'f', 1)); + ui->progress->setValue((int)p); + ui->progress->setFormat(fmt); +} + +void Modem::startTransfer(char type) +{ + show(); + ym->start(); +} + +void Modem::putData(const QByteArray &data) +{ + ym->put(data); +} + +void Modem::showStatus(const char *s) +{ + ui->lbmsg->setText(s); +} + +void Modem::closed() +{ + emit exitTransfer(); +} diff --git a/Modem/Modem.h b/Modem/Modem.h new file mode 100644 index 0000000..23cd9be --- /dev/null +++ b/Modem/Modem.h @@ -0,0 +1,42 @@ +#ifndef MODEM_H +#define MODEM_H + +#include + +namespace Ui { +class Modem; +} + +class Ymodem; + +class Modem : public QDialog +{ + Q_OBJECT + +public: + explicit Modem(QWidget *parent = 0); + ~Modem(); + + void setFile(QString &name); + void getFile(QString &name); + void startTransfer(char type = 'C'); + void showStatus(const char *s); + +public Q_SLOTS: + void putData(const QByteArray &data); + +private Q_SLOTS: + void showTransfer(int total, int remain, float speed); + void closed(); + +Q_SIGNALS: + void outData(const QByteArray &data); + void exitTransfer(); + +private: + Ui::Modem *ui; + Ymodem *ym; + QString filename; +}; + +#endif // MODEM_H diff --git a/Modem/Ymodem.cpp b/Modem/Ymodem.cpp new file mode 100644 index 0000000..b2de4c9 --- /dev/null +++ b/Modem/Ymodem.cpp @@ -0,0 +1,307 @@ +#include "Ymodem.h" +#include "Modem.h" +#include "crc.h" + +#include +#include +#include + +Ymodem::Ymodem(Modem *parent) +{ + Stage = msFirst; + sn = 0; + isrun = false; + ui = parent; +} + +void Ymodem::close() +{ + isrun = false; + if (!isFinished()) + { + wait(); + } +} + +void Ymodem::time_start() +{ + stx_time = time(NULL); +} + +float Ymodem::speed_clc(int total, int remain) +{ + float s = 0; + int t; + + t = (int)(time(NULL) - stx_time); + s = (total - remain)/(float)t; + + return s; +} + +void Ymodem::put(const QByteArray &data) +{ + msgq_push(data.at(0)); +} + +int Ymodem::makeFirstRsp(string &name, int size, QByteArray &byte) +{ + int len = 133; + ymhead_t *pkt; + uint16_t *sum; + + byte.resize(len); + sn = 0; + pkt = (ymhead_t*)byte.data(); + pkt->start = 0x01; + pkt->sn = 0; + pkt->nsn = 0xFF; + memset(pkt->data, 0, sizeof(pkt->data)); + strcpy(pkt->data, name.c_str()); + sprintf(&pkt->data[name.size() + 1], "%d", size); + + sum = (uint16_t*)(((char*)pkt) + 131); + *sum = crc16(pkt->data, 128); + + return len; +} + +int Ymodem::makeNextRsp(char *data, int size, QByteArray &byte) +{ + int len = 0; + ymhead_t *pkt; + uint16_t *sum; + + byte.resize(3 + 1024 + 2); + pkt = (ymhead_t *)byte.data(); + sn ++; + pkt->start = 0x02; + pkt->sn = sn; + pkt->nsn = 0xFF - sn; + memcpy(pkt->data, data, size); + if (size < 1024) + { + memset(&pkt->data[size], 0, 1024 - size); + } + len = 1024 + 3; + sum = (uint16_t*)(((char*)pkt) + len); + *sum = crc16(pkt->data, 1024); + len += 2; + + return len; +} + +uint16_t Ymodem::crc16(char *data, int size) +{ + uint16_t sum; + + sum = crc16_ccitt(0, (uint8_t*)data, size); + sum = ((sum >> 8) | (sum << 8)); + + return sum; +} + +void Ymodem::msgq_push(int msg) +{ + msgq.push(msg); +} + +bool Ymodem::msgq_get(int &msg) +{ + if (msgq.empty()) + return false; + + msg = msgq.front(); + msgq.pop(); + + return true; +} + +int Ymodem::makeFinishRsp(QByteArray &byte) +{ + int len = 133; + ymhead_t *pkt; + uint16_t *sum; + + byte.resize(len); + + pkt = (ymhead_t*)byte.data(); + pkt->start = 0x01; + pkt->sn = 0; + pkt->nsn = 0xFF; + memset(pkt->data, 0, sizeof(pkt->data)); + + sum = (uint16_t*)(byte.data() + 131); + *sum = crc16(pkt->data, 128); + + return len; +} + +int Ymodem::makeEotRsp(QByteArray &byte) +{ + byte.resize(1); + + byte[0] = mcEOT; + + return 1; +} + +void Ymodem::outData(const QByteArray &data) +{ + emit ui->outData(data); +} + +void Ymodem::showStatus(const char *s) +{ + ui->showStatus(s); +} + +void Ymodem::run() +{ + QString filename; + char fbuf[1024]; + bool isread = false; + QByteArray byte; + int filesize = 0; + QFile file; + string stext; + int remain = 0; + + showStatus("已启动Ymodem"); + ui->getFile(filename); + if (filename.isEmpty()) + { + showStatus("错误:文件名为空"); + goto err; + } + + file.setFileName(filename); + if (!file.open(QFile::ReadOnly)) + { + showStatus("错误:打开文件失败"); + goto err; + } + + msgq_push(mcREQ); + + isrun = true; + while (isrun) + { + int msg = 0; + + msgq_get(msg); + + switch (Stage) + { + case msFirst: + { + switch (msg) + { + case mcREQ: + { + QFileInfo info(filename); + + showStatus("第一次传输请求"); + stext = info.fileName().toStdString(); + remain = file.size(); + filesize = remain; + makeFirstRsp(stext, remain, byte); + outData(byte); + } + break; + case mcACK: + { + Stage = msReady; + } + break; + } + } + break; + case msReady: + { + switch (msg) + { + case mcREQ: + { + showStatus("第二次传输请求"); + Stage = msTrans; + time_start(); + } + break; + } + } + break; + case msTrans: + { + if (!isread) + { + int size; + + size = file.read(fbuf, 1024); + remain -= size; + makeNextRsp(fbuf, size, byte); + + isread = true; + outData(byte); + } + + switch (msg) + { + case mcACK: + float speed; + + isread = false; + speed = speed_clc(filesize, remain); + emit showTransfer(filesize, remain, speed); + if (remain == 0) + { + Stage = msEnding; + msgq_push(mcACK); + } + break; + } + } + break; + case msRepeat: + { + outData(byte); + } + break; + case msEnding: + { + switch (msg) + { + case mcACK: + makeEotRsp(byte); + outData(byte); + Stage = msFinish; + break; + } + } + break; + case msFinish: + { + switch (msg) + { + case mcACK: + makeFinishRsp(byte); + outData(byte); + goto err; + break; + case mcNAK: + makeEotRsp(byte); + outData(byte); + break; + } + } + break; + default: + break; + } + + msleep(10); + } + +err: + showStatus("退出Ymodem"); +} diff --git a/Modem/Ymodem.h b/Modem/Ymodem.h new file mode 100644 index 0000000..a54af28 --- /dev/null +++ b/Modem/Ymodem.h @@ -0,0 +1,88 @@ +#ifndef YMODEM_H +#define YMODEM_H + +#include +#include +#include +#include + +using namespace std; +class Modem; + +class Ymodem : public QThread +{ + Q_OBJECT + +public: + Ymodem(Modem *parent); + + void close(); + void put(const QByteArray &data); + + int makeFirstRsp(string &name, int size, QByteArray &byte); + int makeNextRsp(char *data, int size, QByteArray &byte); + int makeEotRsp(QByteArray &byte); + int makeFinishRsp(QByteArray &byte); + +signals: + void showTransfer(int total, int remain, float speed); + +private: + enum modemWaitfor + { + mwNon = 0x00, + mwReq = 0x43, + mwAck = 0x06, + }; + + enum modemStage + { + msFirst, + msReady, + msTrans, + msRepeat, + msEnding, + msFinish, + }; + + enum modemCode + { + mcSOH = 0x01, + mcSTX = 0x02, + mcEOT = 0x04, + mcACK = 0x06, + mcNAK = 0x15, + mcCAN = 0x18, + mcREQ = 0x43, + }; + + typedef struct + { + uint8_t start; + uint8_t sn; + uint8_t nsn; + char data[128]; + //short crc; + }ymhead_t; + +private: + void run(); + void msgq_push(int msg); + bool msgq_get(int &msg); + uint16_t crc16(char *data, int size); + void time_start(); + float speed_clc(int total, int remain); + void outData(const QByteArray &data); + void showStatus(const char *s); + +private: + enum modemStage Stage; + enum modemWaitfor Wait; + bool isrun; + Modem *ui; + uint8_t sn; + queue msgq; + time_t stx_time; +}; + +#endif // YMODEM_H diff --git a/Modem/crc.h b/Modem/crc.h new file mode 100644 index 0000000..c9bba84 --- /dev/null +++ b/Modem/crc.h @@ -0,0 +1,16 @@ +#ifndef CRC_H +#define CRC_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include + +uint16_t crc16_ccitt(uint16_t crc_start, uint8_t *buf, int len); + +#ifdef __cplusplus +} +#endif + +#endif // CRC_H diff --git a/Modem/crc16.c b/Modem/crc16.c new file mode 100644 index 0000000..c46c99c --- /dev/null +++ b/Modem/crc16.c @@ -0,0 +1,75 @@ +/* + *========================================================================== + * + * crc16.c + * + * 16 bit CRC with polynomial x^16+x^12+x^5+1 + * + *========================================================================== + * SPDX-License-Identifier: eCos-2.0 + *========================================================================== + *#####DESCRIPTIONBEGIN#### + * + * Author(s): gthomas + * Contributors: gthomas,asl + * Date: 2001-01-31 + * Purpose: + * Description: + * + * This code is part of eCos (tm). + * + *####DESCRIPTIONEND#### + * + *========================================================================== + */ + +#include "crc.h" + +/* Table of CRC constants - implements x^16+x^12+x^5+1 */ +static const uint16_t crc16_tab[] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, +}; + +uint16_t crc16_ccitt(uint16_t crc_start, uint8_t *buf, int len) +{ + int i; + uint16_t cksum; + + cksum = crc_start; + for (i = 0; i < len; i++) + cksum = crc16_tab[((cksum>>8) ^ *buf++) & 0xff] ^ (cksum << 8); + + return cksum; +} diff --git a/Modem/modem.ui b/Modem/modem.ui new file mode 100644 index 0000000..cdd15a0 --- /dev/null +++ b/Modem/modem.ui @@ -0,0 +1,48 @@ + + + Modem + + + + 0 + 0 + 400 + 300 + + + + Ymodem + + + + + 60 + 210 + 281 + 23 + + + + 0 + + + %p% + + + + + + 10 + 274 + 351 + 21 + + + + + + + + + + diff --git a/QTermWidget/QTermScreen.cpp b/QTermWidget/QTermScreen.cpp new file mode 100644 index 0000000..09e64d7 --- /dev/null +++ b/QTermWidget/QTermScreen.cpp @@ -0,0 +1,189 @@ +#include "QTermScreen.h" + +#include + +QTermScreen::QTermScreen(QWidget *parent): + QPlainTextEdit(parent) +{ + QPalette p = palette(); + p.setColor(QPalette::Base, Qt::black); + p.setColor(QPalette::Text, Qt::white); + setPalette(p); + setLineWrapMode(NoWrap); +} + +void QTermScreen::CursorStartOfLine() +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::StartOfBlock); + setTextCursor(tc); +} + +void QTermScreen::CursorNewLine() +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::EndOfBlock); + if (tc.atEnd()) + { + tc.insertBlock(); + } + else + { + tc.movePosition(QTextCursor::NextBlock); + } + + setTextCursor(tc); +} + +void QTermScreen::SelectRight(int n) +{ + QTextCursor tc = textCursor(); + + if (!tc.atBlockEnd()) + { + tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, n); + setTextCursor(tc); + } +} + +void QTermScreen::CursorUp(int n) +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::Up, QTextCursor::MoveAnchor, n); + setTextCursor(tc); +} + +void QTermScreen::CursorDown(int n) +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, n); + setTextCursor(tc); +} + +void QTermScreen::CursorLeft(int n) +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, n); + setTextCursor(tc); +} + +void QTermScreen::CursorRight(int n) +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, n); + setTextCursor(tc); +} + +void QTermScreen::CursorHome(int row, int column) +{ + QTextCursor tc = cursorForPosition(QPoint(0, 0)); + + for (int i = 0; i < row - 1; i ++) + { + tc.movePosition(QTextCursor::Down); + } + for (int i = 0; i < column - 1; i ++) + { + tc.movePosition(QTextCursor::Right); + } + setTextCursor( tc ); +} + +void QTermScreen::DisplayForeground(QColor &color) +{ + QTextCharFormat fmt; + + fmt.setForeground(color); + QTextCursor cursor = textCursor(); + cursor.mergeCharFormat(fmt); + setTextCursor(cursor); +} + +void QTermScreen::DisplayBackground(QColor &color) +{ + QTextCharFormat fmt; + + fmt.setBackground(color); + QTextCursor cursor = textCursor(); + cursor.mergeCharFormat(fmt); + setTextCursor(cursor); +} + +QColor QTermScreen::GetColor(int col) +{ + QColor color[8] = + { + "black", "red", "green", "yellow", + "blue", "magenta", "cyan", "white" + }; + + if (col >= 0 && col <= 7) + { + return color[col]; + } + else + { + return color[0]; + } +} + +void QTermScreen::DisplayReset() +{ + QColor color; + + color = GetColor(0); + DisplayBackground(color); + color = GetColor(7); + DisplayForeground(color); +} + +void QTermScreen::EraseEndOfLine() +{ + QTextCursor tc = textCursor(); + tc.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + tc.removeSelectedText(); + setTextCursor(tc); +} + +void QTermScreen::EraseStartOfLine() +{ + QTextCursor tc = textCursor(); + tc.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor); + tc.removeSelectedText(); + setTextCursor(tc); +} + +void QTermScreen::EraseEntireLine() +{ + QTextCursor tc = textCursor(); + tc.select(QTextCursor::BlockUnderCursor); + tc.removeSelectedText(); +} + +void QTermScreen::EraseDown() +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + tc.removeSelectedText(); +} + +void QTermScreen::EraseUp() +{ + QTextCursor tc = textCursor(); + + tc.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); + tc.removeSelectedText(); +} + +void QTermScreen::EraseScreen() +{ + EraseDown(); + EraseUp(); +} diff --git a/QTermWidget/QTermScreen.h b/QTermWidget/QTermScreen.h new file mode 100644 index 0000000..d309e9a --- /dev/null +++ b/QTermWidget/QTermScreen.h @@ -0,0 +1,41 @@ +#ifndef QTERMSCREEN_H +#define QTERMSCREEN_H + +#include + +class QTermScreen : public QPlainTextEdit +{ + Q_OBJECT + +public: + QTermScreen(QWidget *parent = Q_NULLPTR); + +public: + void CursorStartOfLine(); + void CursorNewLine(); + void CursorUp(int n = 1); + void CursorDown(int n = 1); + void CursorLeft(int n = 1); + void CursorRight(int n = 1); + void CursorHome(int row = 0, int column = 0); + +public: + QColor GetColor(int c); + + void DisplayReset(); + void DisplayForeground(QColor &color); + void DisplayBackground(QColor &color); + +public: + void EraseEndOfLine(); + void EraseStartOfLine(); + void EraseEntireLine(); + void EraseDown(); + void EraseUp(); + void EraseScreen(); + +public: + void SelectRight(int n = 1); +}; + +#endif // QTERMSCREEN_H diff --git a/QTermWidget/QTermWidget.cpp b/QTermWidget/QTermWidget.cpp new file mode 100644 index 0000000..98a4609 --- /dev/null +++ b/QTermWidget/QTermWidget.cpp @@ -0,0 +1,295 @@ +#include "QTermWidget.h" + +QTermWidget::QTermWidget(QWidget *parent): + QTermScreen(parent) +{ + m_Mode = 0; + setAcceptDrops(false); +} + +void QTermWidget::putData(const QByteArray &data) +{ + if (data.size() == 0) + return; + + for (int i = 0; i < data.size(); i ++) + { + recvChar(data[i]); + } +} + +void QTermWidget::recvChar(char ch) +{ + switch (m_Mode) + { + case 2: + { + switch (ch) + { + case 'A': + case 'B': + case 'C': + case 'D': + case 'H': + { + m_Mode = 0; + moveCursor(ch); + }break; + case 'J': + case 'K': + { + m_Mode = 0; + + eraseText(ch); + }break; + case 'm': + { + m_Mode = 0; + setDisplay(); + }break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ';': + { + m_Param.push_back(ch); + }break; + default: + { + m_Mode = 0; + }break; + } + }break; + case 1: + { + switch (ch) + { + case '[': + { + m_Mode = 2; + }break; + default: + { + m_Mode = 0; + }break; + } + }break; + default: + { + switch (ch) + { + case '\e': + { + m_Mode = 1; + m_Param.clear(); + }break; + case 0x0D: + { + CursorStartOfLine(); + }break; + case 0x0A: + { + CursorNewLine(); + }break; + case 0x08: + { + CursorLeft(); + }break; + case 0x07: + { + + }break; + default: + { + QByteArray t; + t[0]=ch; + SelectRight(); + insertPlainText(t); + }break; + } + }break; + } +} + +void QTermWidget::mousePressEvent(QMouseEvent *e) +{ + Q_UNUSED(e) + setFocus(); +} + +void QTermWidget::keyPressEvent(QKeyEvent *e) +{ + QByteArray byte; + + lastkey = e->key(); + + switch (lastkey) + { + case Qt::Key_Backspace: + byte[0] = 0x08; + break; + case Qt::Key_Left: + byte[0] = 0x1B; byte[1] = 0x5B, byte[2] = 0x44; + break; + case Qt::Key_Right: + byte[0] = 0x1B; byte[1] = 0x5B, byte[2] = 0x43; + break; + case Qt::Key_Up: + byte[0] = 0x1B; byte[1] = 0x5B, byte[2] = 0x41; + break; + case Qt::Key_Down: + byte[0] = 0x1B; byte[1] = 0x5B, byte[2] = 0x42; + break; + case Qt::Key_Enter: + break; + case Qt::Key_Return: + default: + byte = e->text().toLocal8Bit(); + break; + } + + if (byte.size() != 0) + { + emit outData(byte); + } +} + +void QTermWidget::parseParam(QVector ¶m, int np, int defval) +{ + if (m_Param.isEmpty()) + { + for (int i = 0; i < np; i ++) + { + param.push_back(defval); + } + return; + } + + m_Param.append(';'); + + QString tmp; + for (int i = 0; i < m_Param.count(); i ++) + { + QChar ch = m_Param.at(i); + + if (ch == ';') + { + int v; + + v = tmp.toInt(); + param.push_back(v); + tmp.clear(); + continue; + } + tmp.push_back(ch); + } +} + +void QTermWidget::eraseText(char ch) +{ + QVector p; + + parseParam(p); + if (ch == 'J') + { + switch (p[0]) + { + case 0: + { + EraseDown(); + }break; + case 1: + { + EraseUp(); + }break; + case 2: + { + EraseScreen(); + }break; + } + } + else + { + switch (p[0]) + { + case 0: + { + EraseEndOfLine(); + }break; + case 1: + { + EraseStartOfLine(); + }break; + case 2: + { + EraseEntireLine(); + }break; + } + } +} + +void QTermWidget::setDisplay() +{ + QVector p; + + parseParam(p); + + for(int i = 0; i < p.count(); i ++) + { + int v = p[i]; + + switch (v) + { + case 0: + { + DisplayReset(); + }break; + default: + { + if (v >= 30 && v <= 37) + { + QColor c = GetColor(v - 30); + DisplayForeground(c); + } + if (v >= 40 && v <= 47) + { + QColor c = GetColor(v - 40); + DisplayBackground(c); + } + }break; + } + } +} + +void QTermWidget::moveCursor(char ch) +{ + QVector p; + + parseParam(p, 2, 1); + + switch (ch) + { + case 'A': + CursorUp(p[0]); + break; + case 'B': + CursorDown(p[0]); + break; + case 'C': + CursorLeft(p[0]); + break; + case 'D': + CursorRight(p[0]); + break; + case 'H': + CursorHome(p[0], p[1]); + break; + } +} diff --git a/QTermWidget/QTermWidget.h b/QTermWidget/QTermWidget.h new file mode 100644 index 0000000..7e9c934 --- /dev/null +++ b/QTermWidget/QTermWidget.h @@ -0,0 +1,37 @@ +#ifndef QTERMWIDGET_H +#define QTERMWIDGET_H + +#include "QTermScreen.h" + +class QTermWidget : public QTermScreen +{ + Q_OBJECT + +public: + QTermWidget(QWidget *parent = Q_NULLPTR); + +public slots: + void putData(const QByteArray &data); + +signals: + void outData(const QByteArray &data); + +protected: + virtual void mousePressEvent(QMouseEvent *e); + virtual void keyPressEvent(QKeyEvent *e); + +private: + void recvChar(char ch); + void parseParam(QVector ¶m, int np = 1, int defval = 0); + void eraseText(char ch); + void moveCursor(char ch); + void setDisplay(); + +private: + int m_Mode; + QString m_Param; + bool m_sel; + int lastkey; +}; + +#endif // QTERMWIDGET_H diff --git a/SendSave/SSWorker.cpp b/SendSave/SSWorker.cpp new file mode 100644 index 0000000..3beaafa --- /dev/null +++ b/SendSave/SSWorker.cpp @@ -0,0 +1,138 @@ +#include "SSWorker.h" + +#include +#include +#include +#include "SendSave.h" + +#include +#include +#include +using namespace std; + +SSWorker::SSWorker(SendSave *parent) +{ + ui = parent; +} + +SSWorker::~SSWorker() +{ + delete dbSS; + delete query; +} + +bool SSWorker::dbInit() +{ + dbSS = new QSqlDatabase; + + *dbSS = QSqlDatabase::addDatabase("QSQLITE"); + dbSS->setDatabaseName("save.dblite"); + if (dbSS->open()) + { + query = new QSqlQuery(*dbSS); + return true; + } + + return false; +} + +void SSWorker::dbNewTable() +{ + QString str = "CREATE TABLE sendlist" + "(" + "sn VARCHAR," + "name VARCHAR," + "type VARCHAR," + "value VARCHAR," + "endline VARCHAR" + ");"; + + query->exec(str); +} + +void SSWorker::dbAddRow(QString &sn, QString &name, QString &type, QString &value, QString &endline) +{ + QString str; + ostringstream tmp; + + tmp << "INSERT INTO sendlist VALUES(" + << "'" << sn.toStdString() << "'," + << "'" << name.toStdString() << "'," + << "'" << type.toStdString() << "'," + << "'" << value.toStdString() << "'," + << "'" << endline.toStdString() << "'" + << ");"; + + str = QString::fromStdString(tmp.str()); + + query->exec(str); +} + +void SSWorker::dbUpdateRow(QString &sn, int col, QString &val) +{ + string head = "UPDATE sendlist SET "; + QString str; + ostringstream temp; + + temp << head; + + switch (col) + { + case 0: + temp << "name = '" << val.toStdString() << "'"; + break; + case 1: + temp << "value = '" << val.toStdString() << "'"; + break; + case 2: + temp << "endline = '" << val.toStdString() << "'"; + break; + default: + break; + } + + temp << " WHERE sn = '" << sn.toStdString() << "'"; + + str = str.fromStdString(temp.str()); + query->prepare(str); + + query->exec(); +} + +void SSWorker::dbDelAll() +{ + string head = "DELETE FROM sendlist;"; + QString str; + ostringstream temp; + + temp << head; + str = str.fromStdString(temp.str()); + query->exec(str); +} + +void SSWorker::dbQuery() +{ + query->exec("SELECT * FROM sendlist;"); + + while(query->next()) + { + QString name; + QString type; + QString value; + QString endline; + + name = query->value(1).toString(); + type = query->value(2).toString(); + value = query->value(3).toString(); + endline = query->value(4).toString(); + + ui->tableAddRow(name, type, value, endline); + } +} + +void SSWorker::run() +{ + dbInit(); + dbNewTable(); + dbQuery(); +} diff --git a/SendSave/SSWorker.h b/SendSave/SSWorker.h new file mode 100644 index 0000000..6efcf8a --- /dev/null +++ b/SendSave/SSWorker.h @@ -0,0 +1,34 @@ +#ifndef SSWORKER_H +#define SSWORKER_H + +#include + +class QSqlDatabase; +class SendSave; +class QSqlQuery; + +class SSWorker : public QThread +{ +public: + SSWorker(SendSave *parent); + ~SSWorker(); + +private: + void run(); + + bool dbInit(); + void dbNewTable(); + void dbQuery(); + +public: + void dbAddRow(QString &sn, QString &name, QString &type, QString &value, QString &endline); + void dbUpdateRow(QString &sn, int col, QString &val); + void dbDelAll(); + +private: + QSqlDatabase *dbSS; + SendSave *ui; + QSqlQuery *query; +}; + +#endif // SSWORKER_H diff --git a/SendSave/SendSave.cpp b/SendSave/SendSave.cpp new file mode 100644 index 0000000..9a2b744 --- /dev/null +++ b/SendSave/SendSave.cpp @@ -0,0 +1,214 @@ +#include "SendSave.h" +#include "ui_SendSave.h" +#include "SSWorker.h" + +#include + +#include +#include +using namespace std; + +SendSave::SendSave(QWidget *parent) : + QDialog(parent), + ui(new Ui::SendSave) +{ + ui->setupUi(this); + + tableInit(); + + worker = new SSWorker(this); + worker->start(); +} + +SendSave::~SendSave() +{ + delete ui; + delete worker; +} + +void SendSave::tableInit() +{ + ui->tbSave->setColumnCount(3); + + QStringList header; + + header << "名称" << "内容" << "换行符"; + ui->tbSave->setHorizontalHeaderLabels(header); + + ui->tbSave->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->tbSave->horizontalHeader()->resizeSection(0, 60); + ui->tbSave->horizontalHeader()->resizeSection(1, 160); + + QHeaderView *vh; + + vh = ui->tbSave->verticalHeader(); + connect(vh, SIGNAL(sectionClicked(int)), this, SLOT(VHeaderClicked(int))); +} + +void SendSave::VHeaderClicked(int index) +{ + QByteArray buf; + QString value; + QString endline; + QTableWidgetItem *item; + + if (index >= ui->tbSave->rowCount() || index < 0) + return; + + item = ui->tbSave->item(index, 1); + value = item->text(); + item = ui->tbSave->item(index, 2); + endline = item->text(); + + dataMake(buf, value, endline); + if (buf.size()) + { + emit outData(buf); + } +} + +void SendSave::tableAddRow(QString &name, QString &type, QString &value, QString &endline) +{ + int row; + + row = ui->tbSave->rowCount(); + ui->tbSave->insertRow(row); + QTableWidgetItem *item = new QTableWidgetItem[3]; + + item->setText(name); + ui->tbSave->setItem(row, 0, item); + item ++; + + item->setText(value); + ui->tbSave->setItem(row, 1, item); + item ++; + + item->setText(endline); + ui->tbSave->setItem(row, 2, item); + + setBtName(row, name); +} + +void SendSave::on_send1_clicked() +{ + VHeaderClicked(0); + hide(); +} + +void SendSave::on_send2_clicked() +{ + VHeaderClicked(1); + hide(); +} + +void SendSave::on_send3_clicked() +{ + VHeaderClicked(2); + hide(); +} + +void SendSave::on_add_clicked() +{ + QString sn; + QString type = "ascii"; + QString endline = "\\n"; + QString value = "test"; + + sn.sprintf("%d", ui->tbSave->rowCount() + 1); + tableAddRow(sn, type, value, endline); + worker->dbAddRow(sn, sn, type, value, endline); +} + +void SendSave::on_tbSave_itemChanged(QTableWidgetItem *item) +{ + QString sn; + QString val; + + sn.sprintf("%d", item->row() + 1); + val = item->text(); + worker->dbUpdateRow(sn, item->column(), val); + + if (item->column() == 0) + { + setBtName(item->row(), val); + } +} + +void SendSave::setBtName(int row, QString name) +{ + if (row > 2) + return; + + switch (row) + { + case 0: + ui->send1->setText(name); + break; + case 1: + ui->send2->setText(name); + break; + case 2: + ui->send3->setText(name); + break; + } +} + +void SendSave::on_clear_clicked() +{ + int row = ui->tbSave->rowCount(); + + worker->dbDelAll(); + + for (int i = 0; i < row; i ++) + { + ui->tbSave->removeRow(0); + } +} + +void SendSave::dataMake(QByteArray &buf, QString &value, QString &endline) +{ + if (value.isEmpty()) + return; + + buf = value.toStdString().c_str(); + int r, n; + r = endline.count("\\r"); + n = endline.count("\\n"); + + for (int i = 0; i < r; i++) + { + buf.append('\r'); + } + + for (int i = 0; i < n; i++) + { + buf.append('\n'); + } +} + +void SendSave::on_send_clicked() +{ + int sel = ui->tbSave->currentRow(); + + VHeaderClicked(sel); +} + +QToolButton* SendSave::toolButton(int index) +{ + QToolButton* bt = NULL; + + switch (index) + { + case 0: + bt = ui->send1; + break; + case 1: + bt = ui->send2; + break; + case 2: + bt = ui->send3; + break; + } + + return bt; +} diff --git a/SendSave/SendSave.h b/SendSave/SendSave.h new file mode 100644 index 0000000..a38bb49 --- /dev/null +++ b/SendSave/SendSave.h @@ -0,0 +1,55 @@ +#ifndef SENDSAVE_H +#define SENDSAVE_H + +#include + +namespace Ui { +class SendSave; +} + +class SSWorker; +class QTableWidgetItem; +class QToolButton; + +class SendSave : public QDialog +{ + Q_OBJECT + +public: + explicit SendSave(QWidget *parent = 0); + ~SendSave(); + + void tableAddRow(QString &name, QString &type, QString &value, QString &endline); + QToolButton* toolButton(int index = 0); + +signals: + void outData(const QByteArray &data); + +private: + void tableInit(); + void dataMake(QByteArray &buf, QString &value, QString &endline); + void setBtName(int row, QString name); + +private slots: + void on_send1_clicked(); + + void on_send2_clicked(); + + void on_send3_clicked(); + + void on_add_clicked(); + + void on_tbSave_itemChanged(QTableWidgetItem *item); + + void on_clear_clicked(); + + void VHeaderClicked(int index); + + void on_send_clicked(); + +private: + Ui::SendSave *ui; + SSWorker *worker; +}; + +#endif // SENDSAVE_H diff --git a/SendSave/SendSave.ui b/SendSave/SendSave.ui new file mode 100644 index 0000000..7b4938c --- /dev/null +++ b/SendSave/SendSave.ui @@ -0,0 +1,66 @@ + + + SendSave + + + + 0 + 0 + 356 + 244 + + + + 发送列表 + + + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + 发送 + + + + + + + + + + + + + + + 清空 + + + + + + + + diff --git a/images/application-exit.png b/images/application-exit.png new file mode 100644 index 0000000..32be6b3 Binary files /dev/null and b/images/application-exit.png differ diff --git a/images/clear.png b/images/clear.png new file mode 100644 index 0000000..aa612f1 Binary files /dev/null and b/images/clear.png differ diff --git a/images/connect.png b/images/connect.png new file mode 100644 index 0000000..dd5a51e Binary files /dev/null and b/images/connect.png differ diff --git a/images/disconnect.png b/images/disconnect.png new file mode 100644 index 0000000..fd58f7a Binary files /dev/null and b/images/disconnect.png differ diff --git a/images/settings.png b/images/settings.png new file mode 100644 index 0000000..3d1042e Binary files /dev/null and b/images/settings.png differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..d328ca1 --- /dev/null +++ b/main.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + qRegisterMetaType("string"); + + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..49de35f --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "settingsdialog.h" +#include "SendSave/SendSave.h" +#include +#include +#include +#include +#include +#include "Modem/Modem.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow), + m_modemEn(false) +{ + ui->setupUi(this); + + term = new QTermWidget(this); + + setCentralWidget(term); + setAcceptDrops(true); + + serial = new QSerialPort(this); + + settings = new SettingsDialog; + + ui->actionConnect->setEnabled(true); + ui->actionDisconnect->setEnabled(false); + ui->actionQuit->setEnabled(true); + ui->actionConfigure->setEnabled(true); + + status = new QLabel; + ui->statusBar->addWidget(status); + + initActionsConnections(); + + connect(serial, static_cast(&QSerialPort::error), + this, &MainWindow::handleError); + + connect(serial, &QSerialPort::readyRead, this, &MainWindow::readData); + connect(term, &term->outData, this, &MainWindow::writeData); + + dlgSS = new SendSave; + statusBar()->addWidget(ui->toolButton); + + connect(dlgSS, &dlgSS->outData, this, &MainWindow::writeData); + + statusBar()->addWidget(dlgSS->toolButton(0)); + statusBar()->addWidget(dlgSS->toolButton(1)); + statusBar()->addWidget(dlgSS->toolButton(2)); + + modem = new Modem(this); + connect(modem, &modem->outData, this, &MainWindow::writeData); + + modemCheck = new QTimer; + modemCheck->setSingleShot(true); + connect(modemCheck, SIGNAL(timeout()), this, SLOT(startModem())); + + connect(modem, &modem->exitTransfer, this, &this->exitTransfer); +} + +MainWindow::~MainWindow() +{ + delete settings; + delete ui; + delete dlgSS; + delete modem; +} + +void MainWindow::startModem() +{ + QString filename; + + modem->getFile(filename); + + if (filename.isEmpty()) + { + showStatus(string("请拖入文件")); + } + else + { + m_modemEn = true; + modem->startTransfer(); + } +} + +void MainWindow::exitTransfer() +{ + m_modemEn = false; + modem->hide(); +} + +void MainWindow::openSerialPort() +{ + SettingsDialog::Settings p = settings->settings(); + serial->setPortName(p.name); + serial->setBaudRate(p.baudRate); + serial->setDataBits(p.dataBits); + serial->setParity(p.parity); + serial->setStopBits(p.stopBits); + serial->setFlowControl(p.flowControl); + if (serial->open(QIODevice::ReadWrite)) + { + ui->actionConnect->setEnabled(false); + ui->actionDisconnect->setEnabled(true); + ui->actionConfigure->setEnabled(false); + showStatusMessage(tr("连接到 %1") + .arg(p.name)); + } + else + { + showStatus(string("打开出错")); + } +} + +void MainWindow::dropEvent(QDropEvent *event) +{ + QList urls; + + urls = event->mimeData()->urls(); + if (urls.isEmpty()) + return; + + QString filename = urls.first().toLocalFile(); + modem->setFile(filename); + + emit showStatus(filename.toStdString()); +} + +void MainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + //如果为文件,则支持拖放 + if (event->mimeData()->hasFormat("text/uri-list")) + event->acceptProposedAction(); +} + +void MainWindow::showStatus(string s) +{ + QString qs; + + qs = qs.fromStdString(s); + statusBar()->showMessage(qs, 2000); +} + +void MainWindow::closeSerialPort() +{ + if (serial->isOpen()) + serial->close(); + + ui->actionConnect->setEnabled(true); + ui->actionDisconnect->setEnabled(false); + ui->actionConfigure->setEnabled(true); + showStatus(string("已断开")); +} + +void MainWindow::about() +{ + QMessageBox::about(this, tr("版本:1.0.2 作者:heyuanjie"), + tr("将文件拖入窗口,收到'C'后进入Ymodem模式")); +} + +void MainWindow::writeData(const QByteArray &data) +{ + serial->write(data); +} + +void MainWindow::readData() +{ + QByteArray data = serial->readAll(); + + if (m_modemEn) + { + modem->putData(data); + } + else + { + modemCheck->stop(); + if (data.at(data.size()- 1) == 'C') + { + modemCheck->start(20); + } + + term->putData(data); + } + + QString tmp; + + for (int i = 0; i < data.size(); i ++) + { + QString ch; + tmp += ch.sprintf("0x%02X, ", (uint8_t)data[i]); + } + //qDebug(tmp.toStdString().c_str()); +} + +void MainWindow::handleError(QSerialPort::SerialPortError error) +{ + if (error == QSerialPort::ResourceError) + { + QMessageBox::critical(this, tr("Critical Error"), serial->errorString()); + closeSerialPort(); + } +} + +void MainWindow::initActionsConnections() +{ + connect(ui->actionConnect, &QAction::triggered, this, &MainWindow::openSerialPort); + connect(ui->actionDisconnect, &QAction::triggered, this, &MainWindow::closeSerialPort); + connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::close); + connect(ui->actionConfigure, &QAction::triggered, settings, &MainWindow::show); + connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::about); + connect(ui->actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt); +} + +void MainWindow::showStatusMessage(const QString &message) +{ + status->setText(message); +} + +void MainWindow::on_toolButton_clicked() +{ + dlgSS->show(); +} + +void MainWindow::on_actionClear_triggered() +{ + term->clear(); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..aec9075 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +#include +#include +#include +#include + +using namespace std; + +#include "QTermWidget/QTermWidget.h" + +QT_BEGIN_NAMESPACE + +class QLabel; +class SendSave; + +namespace Ui { +class MainWindow; +} + +QT_END_NAMESPACE + +class SettingsDialog; +class Modem; +class QTimer; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void openSerialPort(); + void closeSerialPort(); + void about(); + void writeData(const QByteArray &data); + void readData(); + void startModem(); + void handleError(QSerialPort::SerialPortError error); + void showStatus(string s); + void exitTransfer(); + void on_toolButton_clicked(); + + void on_actionClear_triggered(); + +protected: + virtual void dropEvent(QDropEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + +private: + void initActionsConnections(); + +private: + void showStatusMessage(const QString &message); + + Ui::MainWindow *ui; + QLabel *status; + SettingsDialog *settings; + QSerialPort *serial; + SendSave *dlgSS; + QTermWidget *term; + Modem *modem; + bool m_modemEn; + QTimer *modemCheck; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..f4fc0ff --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,185 @@ + + + MainWindow + + + + 0 + 0 + 861 + 693 + + + + + Consolas + 12 + + + + QyTerm + + + + + + + + + + 保存 + + + + + + + + + 0 + 0 + 861 + 29 + + + + + Calls + + + + + + + + + Tools + + + + + + + Help + + + + + + + + + + + TopToolBarArea + + + false + + + + + + + + + + 14 + + + + + + &About + + + About program + + + Alt+A + + + + + About Qt + + + + + + :/images/connect.png:/images/connect.png + + + C&onnect + + + Connect to serial port + + + Ctrl+O + + + + + + :/images/disconnect.png:/images/disconnect.png + + + &Disconnect + + + Disconnect from serial port + + + Ctrl+D + + + + + + :/images/settings.png:/images/settings.png + + + &Configure + + + Configure serial port + + + Alt+C + + + + + + :/images/clear.png:/images/clear.png + + + C&lear + + + Clear data + + + Alt+L + + + + + + :/images/application-exit.png:/images/application-exit.png + + + &Quit + + + Ctrl+Q + + + + + + + + + diff --git a/settingsdialog.cpp b/settingsdialog.cpp new file mode 100644 index 0000000..4ae6f84 --- /dev/null +++ b/settingsdialog.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "settingsdialog.h" +#include "ui_settingsdialog.h" + +#include +#include +#include + +QT_USE_NAMESPACE + +SettingsDialog::SettingsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SettingsDialog) +{ + ui->setupUi(this); + + intValidator = new QIntValidator(0, 4000000, this); + + ui->baudRateBox->setInsertPolicy(QComboBox::NoInsert); + + connect(ui->applyButton, SIGNAL(clicked()), + this, SLOT(apply())); + connect(ui->serialPortInfoListBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(showPortInfo(int))); + connect(ui->baudRateBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(checkCustomBaudRatePolicy(int))); + + fillPortsParameters(); + fillPortsInfo(); + + updateSettings(); +} + +SettingsDialog::~SettingsDialog() +{ + delete ui; +} + +SettingsDialog::Settings SettingsDialog::settings() const +{ + return currentSettings; +} + +void SettingsDialog::showPortInfo(int idx) +{ + if (idx != -1) + { + QStringList list = ui->serialPortInfoListBox->itemData(idx).toStringList(); + ui->descriptionLabel->setText(tr("描述: %1").arg(list.at(1))); + } +} + +void SettingsDialog::apply() +{ + updateSettings(); + hide(); +} + +void SettingsDialog::checkCustomBaudRatePolicy(int idx) +{ + bool isCustomBaudRate = !ui->baudRateBox->itemData(idx).isValid(); + ui->baudRateBox->setEditable(isCustomBaudRate); + if (isCustomBaudRate) + { + ui->baudRateBox->clearEditText(); + QLineEdit *edit = ui->baudRateBox->lineEdit(); + edit->setValidator(intValidator); + } +} + +void SettingsDialog::fillPortsParameters() +{ + ui->baudRateBox->addItem(QStringLiteral("9600"), QSerialPort::Baud9600); + ui->baudRateBox->addItem(QStringLiteral("19200"), QSerialPort::Baud19200); + ui->baudRateBox->addItem(QStringLiteral("38400"), QSerialPort::Baud38400); + ui->baudRateBox->addItem(QStringLiteral("115200"), QSerialPort::Baud115200); + ui->baudRateBox->addItem(QStringLiteral("自定义")); + ui->baudRateBox->setCurrentIndex(3); + + ui->dataBitsBox->addItem(QStringLiteral("5"), QSerialPort::Data5); + ui->dataBitsBox->addItem(QStringLiteral("6"), QSerialPort::Data6); + ui->dataBitsBox->addItem(QStringLiteral("7"), QSerialPort::Data7); + ui->dataBitsBox->addItem(QStringLiteral("8"), QSerialPort::Data8); + ui->dataBitsBox->setCurrentIndex(3); + + ui->parityBox->addItem(QStringLiteral("None"), QSerialPort::NoParity); + ui->parityBox->addItem(QStringLiteral("Even"), QSerialPort::EvenParity); + ui->parityBox->addItem(QStringLiteral("Odd"), QSerialPort::OddParity); + ui->parityBox->addItem(QStringLiteral("Mark"), QSerialPort::MarkParity); + ui->parityBox->addItem(QStringLiteral("Space"), QSerialPort::SpaceParity); + + ui->stopBitsBox->addItem(QStringLiteral("1"), QSerialPort::OneStop); + ui->stopBitsBox->addItem(QStringLiteral("2"), QSerialPort::TwoStop); + + ui->flowControlBox->addItem(QStringLiteral("None"), QSerialPort::NoFlowControl); + ui->flowControlBox->addItem(QStringLiteral("RTS/CTS"), QSerialPort::HardwareControl); + ui->flowControlBox->addItem(QStringLiteral("XON/XOFF"), QSerialPort::SoftwareControl); +} + +void SettingsDialog::fillPortsInfo() +{ + static const QString blankString = QObject::tr("N/A"); + QString description; + QStringList list; + + ui->serialPortInfoListBox->clear(); + + list << QString(tr("刷新")) + << QString(tr("点击更新列表")); + ui->serialPortInfoListBox->addItem(list.first(), list); + + foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) + { + QStringList list; + description = info.description(); + + list << info.portName() + << (!description.isEmpty() ? description : blankString); + + ui->serialPortInfoListBox->addItem(list.first(), list); + } + + if (ui->serialPortInfoListBox->count() != 1) + { + ui->serialPortInfoListBox->setCurrentIndex(1); + } +} + +void SettingsDialog::updateSettings() +{ + currentSettings.name = ui->serialPortInfoListBox->currentText(); + + if (ui->baudRateBox->currentIndex() == 4) + { + currentSettings.baudRate = ui->baudRateBox->currentText().toInt(); + } + else + { + currentSettings.baudRate = static_cast( + ui->baudRateBox->itemData(ui->baudRateBox->currentIndex()).toInt()); + } + + currentSettings.stringBaudRate = QString::number(currentSettings.baudRate); + + currentSettings.dataBits = static_cast( + ui->dataBitsBox->itemData(ui->dataBitsBox->currentIndex()).toInt()); + currentSettings.stringDataBits = ui->dataBitsBox->currentText(); + + currentSettings.parity = static_cast( + ui->parityBox->itemData(ui->parityBox->currentIndex()).toInt()); + currentSettings.stringParity = ui->parityBox->currentText(); + + currentSettings.stopBits = static_cast( + ui->stopBitsBox->itemData(ui->stopBitsBox->currentIndex()).toInt()); + currentSettings.stringStopBits = ui->stopBitsBox->currentText(); + + currentSettings.flowControl = static_cast( + ui->flowControlBox->itemData(ui->flowControlBox->currentIndex()).toInt()); + currentSettings.stringFlowControl = ui->flowControlBox->currentText(); +} + +void SettingsDialog::on_serialPortInfoListBox_activated(int index) +{ + if (index == 0) + { + fillPortsInfo(); + } +} diff --git a/settingsdialog.h b/settingsdialog.h new file mode 100644 index 0000000..a78284c --- /dev/null +++ b/settingsdialog.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include +#include + +QT_USE_NAMESPACE + +QT_BEGIN_NAMESPACE + +namespace Ui { +class SettingsDialog; +} + +class QIntValidator; + +QT_END_NAMESPACE + +class SettingsDialog : public QDialog +{ + Q_OBJECT + +public: + struct Settings + { + QString name; + qint32 baudRate; + QString stringBaudRate; + QSerialPort::DataBits dataBits; + QString stringDataBits; + QSerialPort::Parity parity; + QString stringParity; + QSerialPort::StopBits stopBits; + QString stringStopBits; + QSerialPort::FlowControl flowControl; + QString stringFlowControl; + bool localEchoEnabled; + }; + + explicit SettingsDialog(QWidget *parent = 0); + ~SettingsDialog(); + + Settings settings() const; + +private slots: + void showPortInfo(int idx); + void apply(); + void checkCustomBaudRatePolicy(int idx); + + void on_serialPortInfoListBox_activated(int index); + +private: + void fillPortsParameters(); + void fillPortsInfo(); + void updateSettings(); + +private: + Ui::SettingsDialog *ui; + Settings currentSettings; + QIntValidator *intValidator; +}; + +#endif // SETTINGSDIALOG_H diff --git a/settingsdialog.ui b/settingsdialog.ui new file mode 100644 index 0000000..bcc7a39 --- /dev/null +++ b/settingsdialog.ui @@ -0,0 +1,123 @@ + + + SettingsDialog + + + + 0 + 0 + 327 + 263 + + + + 设置 + + + + + + + + Qt::Horizontal + + + + 96 + 20 + + + + + + + + 应用 + + + + + + + + + 端口选择 + + + + + + + + + 描述: + + + + + + + + + + 参数设置 + + + + + + 波特率 + + + + + + + + + + 数据位 + + + + + + + + + + 校验 + + + + + + + + + + 停止位 + + + + + + + + + + 流控 + + + + + + + + + + + + + + diff --git a/terminal.pro b/terminal.pro new file mode 100644 index 0000000..f7bab2a --- /dev/null +++ b/terminal.pro @@ -0,0 +1,36 @@ +QT += widgets serialport sql + +TARGET = QTerm +TEMPLATE = app + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + settingsdialog.cpp \ + SendSave/SendSave.cpp \ + SendSave/SSWorker.cpp \ + QTermWidget/QTermScreen.cpp \ + QTermWidget/QTermWidget.cpp \ + Modem/Modem.cpp \ + Modem/Ymodem.cpp \ + Modem/crc16.c + +HEADERS += \ + mainwindow.h \ + settingsdialog.h \ + SendSave/SendSave.h \ + SendSave/SSWorker.h \ + QTermWidget/QTermScreen.h \ + QTermWidget/QTermWidget.h \ + Modem/Modem.h \ + Modem/Ymodem.h \ + Modem/crc.h + +FORMS += \ + mainwindow.ui \ + settingsdialog.ui \ + SendSave/SendSave.ui \ + Modem/modem.ui + +RESOURCES += \ + terminal.qrc diff --git a/terminal.qrc b/terminal.qrc new file mode 100644 index 0000000..7465cf7 --- /dev/null +++ b/terminal.qrc @@ -0,0 +1,9 @@ + + + images/connect.png + images/disconnect.png + images/application-exit.png + images/settings.png + images/clear.png + +