From 6eb6d6065747e0845a29c2577ca4351d0c200f7a Mon Sep 17 00:00:00 2001 From: KruFFT Date: Wed, 24 Jul 2024 19:57:16 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B0=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=D0=B0=20?= =?UTF-8?q?=D1=82=D0=B8=D0=BF=D0=B0=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D0=B0.=20=D0=9E=D0=BF=D1=82=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BA=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- README.md | 8 +- wxCAN-Sniffer/Application.cpp | 10 + wxCAN-Sniffer/CircularFrameBuffer.cpp | 10 +- wxCAN-Sniffer/CircularFrameBuffer.h | 6 +- wxCAN-Sniffer/Common.h | 6 +- wxCAN-Sniffer/FormMain.cpp | 852 +++++++++++++++++--------- wxCAN-Sniffer/FormMain.h | 83 +-- wxCAN-Sniffer/FramesContainer.h | 10 +- wxCAN-Sniffer/Info.plist | 16 + wxCAN-Sniffer/wxCAN-Sniffer.vcxproj | 3 + 11 files changed, 655 insertions(+), 351 deletions(-) create mode 100644 wxCAN-Sniffer/Info.plist diff --git a/CMakeLists.txt b/CMakeLists.txt index 161de1e..71912e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ message(STATUS "wxWidgets sources: " ${wxWidgets_SOURCE_DIR}) # Building if(APPLE) add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SRCS}) - set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) + set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${Sources}/Info.plist) else() add_executable(${PROJECT_NAME} WIN32 ${SRCS} ${Sources}/${PROJECT_NAME}.manifest) endif() diff --git a/README.md b/README.md index 456ae10..d221a3b 100644 --- a/README.md +++ b/README.md @@ -114,10 +114,16 @@ git clone https://github.com/wxWidgets/wxWidgets.git 3. Обновить необходимые зависимости: ``` cd wxWidgets -git submodule update --init src/stc/scintilla git submodule update --init src/stc/lexilla +git submodule update --init src/stc/scintilla +git submodule update --init src/expat +git submodule update --init src/jpeg +git submodule update --init src/png +git submodule update --init src/tiff +git submodule update --init src/zlib git submodule update --init 3rdparty/catch git submodule update --init 3rdparty/nanosvg +git submodule update --init 3rdparty/pcre ``` 4. Подготовить директорию `./gtk-build` для сборки и запустить настройку: ``` diff --git a/wxCAN-Sniffer/Application.cpp b/wxCAN-Sniffer/Application.cpp index d1f83f4..7655cc4 100644 --- a/wxCAN-Sniffer/Application.cpp +++ b/wxCAN-Sniffer/Application.cpp @@ -8,6 +8,16 @@ bool Application::OnInit() //locale.AddCatalog(GetAppDir() + wxT("\\.")); } + // определение системной темы, если тёмная + /*if (wxSystemSettings::GetAppearance().AreAppsDark()) + { + + } + else + { + + }*/ + auto form = new FormMain(); form->Show(true); SetTopWindow(form); diff --git a/wxCAN-Sniffer/CircularFrameBuffer.cpp b/wxCAN-Sniffer/CircularFrameBuffer.cpp index e6fa7fd..41e9a43 100644 --- a/wxCAN-Sniffer/CircularFrameBuffer.cpp +++ b/wxCAN-Sniffer/CircularFrameBuffer.cpp @@ -4,12 +4,12 @@ CircularFrameBuffer::CircularFrameBuffer(size_t windowSize) { // размер буфера должен быть минимум в два раза больше размера окна - bufferSize = windowSize * 2; - buffer = new uint32_t[bufferSize + 1] { 0 }; + bufferSize = windowSize * 4; + buffer = new float[bufferSize + 1] { 0 }; frameSize = windowSize; frameBegin = 0; frameEnd = frameSize; - frameSizeBytesCount = bufferSize * sizeof(uint32_t); + frameSizeBytesCount = bufferSize * sizeof(float); } // Деструктор @@ -31,7 +31,7 @@ void CircularFrameBuffer::Clear() } // Добавить новое значение со сдвигом при необходимости -void CircularFrameBuffer::Add(uint32_t value) +void CircularFrameBuffer::Add(float value) { // если достигнут предел массива - надо сдвинуть данные if (frameEnd >= bufferSize) @@ -47,7 +47,7 @@ void CircularFrameBuffer::Add(uint32_t value) } // Вернуть указатель на начало кадра -uint32_t* CircularFrameBuffer::Frame() +float* CircularFrameBuffer::Frame() { return &buffer[frameBegin]; } diff --git a/wxCAN-Sniffer/CircularFrameBuffer.h b/wxCAN-Sniffer/CircularFrameBuffer.h index 49ff8b4..6f84d70 100644 --- a/wxCAN-Sniffer/CircularFrameBuffer.h +++ b/wxCAN-Sniffer/CircularFrameBuffer.h @@ -9,12 +9,12 @@ class CircularFrameBuffer ~CircularFrameBuffer(); void Clear(); - void Add(uint32_t value); - uint32_t* Frame(); + void Add(float value); + float* Frame(); size_t FrameSize(); private: - uint32_t* buffer = nullptr; // массив данных + float* buffer = nullptr; // массив данных size_t bufferSize; // размер массива данных size_t frameSize; // размер окна данных size_t frameBegin; // начало окна данных diff --git a/wxCAN-Sniffer/Common.h b/wxCAN-Sniffer/Common.h index b0ca52c..875fa92 100644 --- a/wxCAN-Sniffer/Common.h +++ b/wxCAN-Sniffer/Common.h @@ -15,7 +15,7 @@ #define MEMCOPY(dest, source, size) memcpy(dest, source, size); #endif -#define CAPTION wxT("CAN Sniffer 2.2.1 beta 1") +#define CAPTION wxT("CAN Sniffer 2.2.1 beta 2") #define SIGNATURE_DWORD 0x55AA55AA // сигнатура пакета (big-endian) #define UDP_PORT 0xAA55 // UDP порт @@ -85,9 +85,11 @@ struct LogFile #define FORMAT_HEX3 wxT("%03X") #define FORMAT_HEX8 wxT("%08X") #define FORMAT_INT wxT("%i") +#define FORMAT_UINT wxT("%u") #define FORMAT_INT0 wxT("%0i") #define FORMAT_INT3 wxT("%03i") -#define FORMAT_FLOAT wxT("%1.6f") +#define FORMAT_FLOAT1_0 wxT("%1.0f") +#define FORMAT_FLOAT1_3 wxT("%1.3f") #define ERROR_CAPTION wxT("Ошибка") #define ERROR_SERIAL wxT("Невозможно работать с этим последовательным портом") diff --git a/wxCAN-Sniffer/FormMain.cpp b/wxCAN-Sniffer/FormMain.cpp index 292dbb6..714bbaf 100644 --- a/wxCAN-Sniffer/FormMain.cpp +++ b/wxCAN-Sniffer/FormMain.cpp @@ -5,26 +5,8 @@ wxDEFINE_EVENT(wxEVT_SERIAL_PORT_THREAD_UPDATE, wxThreadEvent); wxDEFINE_EVENT(wxEVT_SERIAL_PORT_THREAD_EXIT, wxThreadEvent); wxDEFINE_EVENT(wxEVT_SERIAL_PORT_THREAD_MESSAGE, wxThreadEvent); -// Таблица событий +// Таблица событий (только событие для UDP-сокета) wxBEGIN_EVENT_TABLE(FormMain, wxFrame) - EVT_CLOSE(FormMain::OnClose) - EVT_BUTTON(ID_BUTON_CONNECT_DISCONNECT, FormMain::ButtonConnectDisconnect_OnClick) - EVT_BUTTON(ID_BUTTON_ADD, FormMain::FormMain::ButtonAdd_OnClick) - EVT_BUTTON(ID_BUTTON_REMOVE, FormMain::ButtonRemove_OnClick) - EVT_BUTTON(ID_BUTTON_REMOVE_ALL, FormMain::ButtonRemoveAll_OnClick) - EVT_BUTTON(ID_BUTTON_SEND, FormMain::ButtonSend_OnClick) - EVT_BUTTON(ID_BUTTON_CLEAR_LOG, FormMain::ButtonClearCANLog_OnClick) - EVT_GRID_CMD_SELECT_CELL(ID_GRID_CAN_VIEW, FormMain::GridCANView_OnSelectCell) - EVT_CHOICE(ID_COMBO_EXT, FormMain::ComboExt_OnChoice) - EVT_CHOICE(ID_COMBO_SEP, FormMain::ComboSep_OnChoice) - EVT_CHECKBOX(ID_CHECKBOX_LOG_ENABLE, FormMain::CheckLogEnable_OnClick) - EVT_CHECKBOX(ID_CHECKBOX_DEC, FormMain::CheckDec_OnClick) - EVT_CHECKBOX(ID_CHECKBOX_SINGLE, FormMain::CheckSingle_OnClick) - EVT_CHECKBOX(ID_CHECKBOX_ENDIAN, FormMain::CheckEndian_OnClick) - EVT_CHECKBOX(ID_CHECKBOX_ASCII, FormMain::CheckASCII_OnClick) - EVT_TEXT_ENTER(ID_TEXT_DEC_WORD_MUL, FormMain::TextDecWordMul_OnEnter) - EVT_TEXT_ENTER(ID_TEXT_CAN_ANSWER_ID, FormMain::TextCANAnswerID_OnEnter) - EVT_TIMER(ID_MAIN_TIMER, FormMain::MainTimer_OnTimer) EVT_SOCKET(ID_UDP_SOCKET, FormMain::UDPSocket_OnEvent) wxEND_EVENT_TABLE() @@ -35,7 +17,7 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition #ifdef __WINDOWS__ this->SetIcon(wxICON(wxicon)); #endif - this->SetSizeHints(this->FromDIP(wxSize(1200, 600))); + this->SetSizeHints(FromDIP(wxSize(1240, 600))); // главный сайзер окна auto sizerMain = new wxBoxSizer(wxHORIZONTAL); @@ -48,7 +30,7 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition // левый верхний сайзер auto sizerLeftTop = new wxStaticBoxSizer(new wxStaticBox(panelLeftTop, wxID_ANY, wxT("Просмотр пакетов")), wxVERTICAL); { - gridCANView = new wxGrid(panelLeftTop, ID_GRID_CAN_VIEW); + gridCANView = new wxGrid(panelLeftTop, wxID_ANY); // параметры сетки gridCANView->CreateGrid(0, 11); gridCANView->EnableEditing(false); @@ -57,12 +39,12 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition gridCANView->SetMargins(0, 0); // параметры столбцов gridCANView->EnableDragColMove(false); - gridCANView->EnableDragColSize(false); - gridCANView->SetColLabelSize(this->FromDIP(20)); + gridCANView->EnableDragColSize(true); + gridCANView->SetColLabelSize(FromDIP(20)); gridCANView->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); // параметры строк gridCANView->EnableDragRowSize(false); - gridCANView->SetRowLabelSize(this->FromDIP(40)); + gridCANView->SetRowLabelSize(FromDIP(40)); gridCANView->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); gridCANView->SetDefaultCellAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); // заполнение таблицы @@ -78,65 +60,65 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition gridCANView->SetColLabelValue(9, wxT("Байт 6")); gridCANView->SetColLabelValue(10, wxT("Байт 7")); // установка ширины столбцов - for (size_t iCol = 0; iCol < 11; iCol++) + gridCANView->SetColSize(0, FromDIP(100)); + for (size_t iCol = 1; iCol < 11; iCol++) { - gridCANView->SetColSize(iCol, this->FromDIP(60)); + gridCANView->SetColSize(iCol, FromDIP(60)); } + // внешний вид gridCANView->SetSelectionMode(wxGrid::wxGridSelectionModes::wxGridSelectNone); - sizerLeftTop->Add(gridCANView, 1, wxEXPAND, 0); - - panelLeftTop->SetSizer(sizerLeftTop); } + sizerLeftTop->Add(gridCANView, 1, wxEXPAND, 0); + panelLeftTop->SetSizer(sizerLeftTop); + // левый нижний сайзер auto sizerLeftBottom = new wxStaticBoxSizer(new wxStaticBox(panelLeftBottom, wxID_ANY, wxT("Тестовая отправка пакета и просмотр ответа")), wxVERTICAL); { // сайзер с текстовыми полями ввода данных CAN-пакета auto sizerLeftBottomText = new wxBoxSizer(wxHORIZONTAL); { - auto labelCAN = new wxStaticText(panelLeftBottom, wxID_ANY, wxT("CAN:"), wxDefaultPosition, this->FromDIP(wxSize(37, 20))); + auto labelCAN = new wxStaticText(panelLeftBottom, wxID_ANY, wxT("CAN:"), wxDefaultPosition, FromDIP(wxSize(37, 20))); labelCAN->Wrap(-1); sizerLeftBottomText->Add(labelCAN, 0, wxLEFT | wxTOP, 2); - textCANID = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("7E0"), wxDefaultPosition, this->FromDIP(wxSize(51, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANID = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("7E0"), wxDefaultPosition, FromDIP(wxSize(51, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANID, 0, wxEXPAND, 0); - textCANLength = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("8"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANLength = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("8"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANLength, 0, wxEXPAND, 0); - textCANByte1 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("05"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte1 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("05"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte1, 0, wxEXPAND, 0); - textCANByte2 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("2F"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte2 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("2F"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte2, 0, wxEXPAND, 0); - textCANByte3 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("00"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte3 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("00"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte3, 0, wxEXPAND, 0); - textCANByte4 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("0A"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte4 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("0A"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte4, 0, wxEXPAND, 0); - textCANByte5 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("06"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte5 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("06"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte5, 0, wxEXPAND, 0); - textCANByte6 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("FF"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte6 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("FF"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte6, 0, wxEXPAND, 0); - textCANByte7 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("00"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte7 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("00"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte7, 0, wxEXPAND, 0); - textCANByte8 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("00"), wxDefaultPosition, this->FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); + textCANByte8 = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("00"), wxDefaultPosition, FromDIP(wxSize(50, 20)), wxTE_CENTRE | wxBORDER_SIMPLE); sizerLeftBottomText->Add(textCANByte8, 0, wxEXPAND, 0); - - sizerLeftBottom->Add(sizerLeftBottomText, 0, wxEXPAND, 0); } + sizerLeftBottom->Add(sizerLeftBottomText, 0, wxEXPAND, 0); // сайзер с кнопками управления отправкой и журналом ответа auto sizerLeftBottomButtons = new wxBoxSizer(wxHORIZONTAL); { - buttonSend = new wxButton(panelLeftBottom, ID_BUTTON_SEND, wxT("Отправить CAN-пакет")); + buttonSend = new wxButton(panelLeftBottom, wxID_ANY, wxT("Отправить CAN-пакет")); sizerLeftBottomButtons->Add(buttonSend, 0, wxALL, 4); auto labelCANFromID = new wxStaticText(panelLeftBottom, wxID_ANY, wxT("Отображать ответ от:"), wxDefaultPosition, wxDefaultSize); labelCANFromID->Wrap(-1); sizerLeftBottomButtons->Add(labelCANFromID, 0, wxALL, 9); - textCANAnswerID = new wxTextCtrl(panelLeftBottom, ID_TEXT_CAN_ANSWER_ID, wxT("7E8"), wxDefaultPosition, this->FromDIP(wxSize(51, 20)), wxTE_CENTRE | wxTE_PROCESS_ENTER | wxBORDER_SIMPLE); + textCANAnswerID = new wxTextCtrl(panelLeftBottom, wxID_ANY, wxT("7E8"), wxDefaultPosition, FromDIP(wxSize(51, 20)), wxTE_CENTRE | wxTE_PROCESS_ENTER | wxBORDER_SIMPLE); sizerLeftBottomButtons->Add(textCANAnswerID, 0, wxALL, 7); // спейсер между кнопками sizerLeftBottomButtons->Add(0, 0, 1, wxEXPAND, 0); - buttonClearCANLog = new wxButton(panelLeftBottom, ID_BUTTON_CLEAR_LOG, wxT("Очистить ответ")); + buttonClearCANLog = new wxButton(panelLeftBottom, wxID_ANY, wxT("Очистить ответ")); sizerLeftBottomButtons->Add(buttonClearCANLog, 0, wxALL, 4); - - sizerLeftBottom->Add(sizerLeftBottomButtons, 0, wxEXPAND, 0); } + sizerLeftBottom->Add(sizerLeftBottomButtons, 0, wxEXPAND, 0); gridCANLog = new wxGrid(panelLeftBottom, wxID_ANY); // параметры сетки @@ -148,11 +130,11 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition // параметры столбцов gridCANLog->EnableDragColMove(false); gridCANLog->EnableDragColSize(false); - gridCANLog->SetColLabelSize(this->FromDIP(20)); + gridCANLog->SetColLabelSize(FromDIP(20)); gridCANLog->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); // параметры строк gridCANLog->EnableDragRowSize(false); - gridCANLog->SetRowLabelSize(this->FromDIP(40)); + gridCANLog->SetRowLabelSize(FromDIP(40)); gridCANLog->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); gridCANLog->SetDefaultCellAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); // заполнение таблицы @@ -169,18 +151,16 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition // установка ширины столбцов for (size_t iCol = 0; iCol < 10; iCol++) { - gridCANLog->SetColSize(iCol, this->FromDIP(60)); + gridCANLog->SetColSize(iCol, FromDIP(60)); } gridCANLog->SetSelectionMode(wxGrid::wxGridSelectionModes::wxGridSelectNone); sizerLeftBottom->Add(gridCANLog, 1, wxEXPAND, 0); - - panelLeftBottom->SetSizer(sizerLeftBottom); } + panelLeftBottom->SetSizer(sizerLeftBottom); splitterLeft->SplitHorizontally(panelLeftTop, panelLeftBottom, -1); - splitterLeft->SetMinimumPaneSize(this->FromDIP(30)); - - // ширина левой области + splitterLeft->SetMinimumPaneSize(FromDIP(30)); + // пропорция задаёт ширину левой области sizerMain->Add(splitterLeft, 1, wxALL | wxEXPAND, 4); // правый сайзер @@ -189,7 +169,7 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition // последовательный порт, кнопка управления и статистика буфера auto sizerControls = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, wxT("Управление")), wxHORIZONTAL); { - comboBoxSerialPort = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, this->FromDIP(wxSize(90, 22)), 0, nullptr, wxTE_CENTRE | wxBORDER_SIMPLE); + comboBoxSerialPort = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, FromDIP(wxSize(90, 22)), 0, nullptr, wxTE_CENTRE | wxBORDER_SIMPLE); auto ports = ThreadedSerialPort::Enumerate(); wxString serialPortToolTip; if (ports.size() > 0) @@ -218,9 +198,9 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition { comboBoxSerialPort->SetToolTip(wxT("Последовательный порт")); } - sizerControls->Add(comboBoxSerialPort, 25, wxALL, 2); + sizerControls->Add(comboBoxSerialPort, 2, wxALL, 2); - comboBoxSerialSpeed = new wxComboBox(this, wxID_ANY, wxT("500000"), wxDefaultPosition, this->FromDIP(wxSize(90, 22)), 0, nullptr, wxTE_CENTRE | wxBORDER_SIMPLE); + comboBoxSerialSpeed = new wxComboBox(this, wxID_ANY, wxT("500000"), wxDefaultPosition, FromDIP(wxSize(90, 22)), 0, nullptr, wxTE_CENTRE | wxBORDER_SIMPLE); comboBoxSerialSpeed->Append(wxT("57600")); comboBoxSerialSpeed->Append(wxT("115200")); comboBoxSerialSpeed->Append(wxT("250000")); @@ -228,219 +208,245 @@ FormMain::FormMain() : wxFrame(nullptr, ID_MAIN_FORM, CAPTION, wxDefaultPosition comboBoxSerialSpeed->Append(wxT("1000000")); comboBoxSerialSpeed->Append(wxT("2000000")); comboBoxSerialSpeed->SetToolTip(wxT("Скорость соединения")); - sizerControls->Add(comboBoxSerialSpeed, 25, wxALL, 2); + sizerControls->Add(comboBoxSerialSpeed, 2, wxALL, 2); - buttonConnectDisconnect = new wxButton(this, ID_BUTON_CONNECT_DISCONNECT, wxT("Подключить"), wxDefaultPosition, this->FromDIP(wxSize(80, 25))); + buttonConnectDisconnect = new wxButton(this, wxID_ANY, wxT("Подключить"), wxDefaultPosition, FromDIP(wxSize(80, 25))); buttonConnectDisconnect->SetFocus(); - sizerControls->Add(buttonConnectDisconnect, 25, wxALL, 0); + sizerControls->Add(buttonConnectDisconnect, 2, wxALL, 0); - textFPS = new wxTextCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, this->FromDIP(wxSize(50, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); + textFPS = new wxTextCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, FromDIP(wxSize(50, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); textFPS->SetToolTip(wxT("пакетов/с")); - sizerControls->Add(textFPS, 12, wxALL, 2); + sizerControls->Add(textFPS, 1, wxALL, 2); - textBPS = new wxTextCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, this->FromDIP(wxSize(50, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); + textBPS = new wxTextCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, FromDIP(wxSize(50, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); textBPS->SetToolTip(wxT("байтов/с (исключая служебную информацию)")); - sizerControls->Add(textBPS, 13, wxALL, 2); - - sizerRight->Add(sizerControls, 0, wxALL | wxEXPAND, 2); + sizerControls->Add(textBPS, 1, wxALL, 2); } + sizerRight->Add(sizerControls, 0, wxALL | wxEXPAND, 2); // журнал, кнопки управления логом и его параметры - auto sizerLog = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, wxT("Запись в журнал и фильтр")), wxVERTICAL); + paneLog = new wxCollapsiblePane(this, wxID_ANY, "Запись в журнал", wxDefaultPosition, wxDefaultSize, wxCP_NO_TLW_RESIZE | wxCP_DEFAULT_STYLE); + paneLog->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [this](wxCollapsiblePaneEvent&) + { + Layout(); + Refresh(); + }); { - checkLogEnable = new wxCheckBox(this, ID_CHECKBOX_LOG_ENABLE, wxT("Вести запись в журнал")); - checkLogEnable->SetValue(logEnable); - sizerLog->Add(checkLogEnable, 0, wxALL, 5); - - auto sizerLogButtonsList = new wxBoxSizer(wxHORIZONTAL); + auto pane = paneLog->GetPane(); + auto sizerLog = new wxBoxSizer(wxVERTICAL); { - // кнопки журнала - auto sizerLogButtons = new wxBoxSizer(wxVERTICAL); + checkLogEnable = new wxCheckBox(pane, wxID_ANY, wxT("Вести запись в журнал")); + checkLogEnable->SetValue(logEnable); + sizerLog->Add(checkLogEnable, 0, wxALL, 5); + + auto sizerLogButtonsList = new wxBoxSizer(wxHORIZONTAL); { - buttonAdd = new wxButton(this, ID_BUTTON_ADD, wxT("Добавить ID в фильтр >>")); - sizerLogButtons->Add(buttonAdd, 1, wxALL | wxEXPAND, 2); + // кнопки журнала + auto sizerLogButtons = new wxBoxSizer(wxVERTICAL); + { + buttonAdd = new wxButton(pane, wxID_ANY, wxT("Добавить ID в фильтр >>")); + sizerLogButtons->Add(buttonAdd, 1, wxALL | wxEXPAND, 2); - buttonRemove = new wxButton(this, ID_BUTTON_REMOVE, wxT("Убрать ID из фильтра <<")); - sizerLogButtons->Add(buttonRemove, 1, wxALL | wxEXPAND, 2); + buttonRemove = new wxButton(pane, wxID_ANY, wxT("Убрать ID из фильтра <<")); + sizerLogButtons->Add(buttonRemove, 1, wxALL | wxEXPAND, 2); - buttonRemoveAll = new wxButton(this, ID_BUTTON_REMOVE_ALL, wxT("Очистить фильтр")); - sizerLogButtons->Add(buttonRemoveAll, 1, wxALL | wxEXPAND, 2); + buttonRemoveAll = new wxButton(pane, wxID_ANY, wxT("Очистить фильтр")); + sizerLogButtons->Add(buttonRemoveAll, 1, wxALL | wxEXPAND, 2); - // ширина кнопок фильтров - sizerLogButtonsList->Add(sizerLogButtons, 60, wxALL, 2); + // ширина кнопок фильтров + sizerLogButtonsList->Add(sizerLogButtons, 6, wxALL, 2); + } + // список кадров журнала + listLog = new wxListBox(pane, wxID_ANY); + // ширина списка фильтров + sizerLogButtonsList->Add(listLog, 4, wxALL | wxEXPAND, 4); } - // список кадров журнала - listLog = new wxListBox(this, wxID_ANY);//, wxDefaultPosition, this->FromDIP(wxSize(-1, -1))); - // ширина списка фильтров - sizerLogButtonsList->Add(listLog, 40, wxALL | wxEXPAND, 4); - sizerLog->Add(sizerLogButtonsList, 0, wxEXPAND, 2); - } - - // настройки типа файла журнала - auto sizerLogType = new wxBoxSizer(wxHORIZONTAL); - { - auto labelExt = new wxStaticText(this, wxID_ANY, wxT("Тип файла:")); - labelExt->Wrap(-1); - sizerLogType->Add(labelExt, 0, wxALL, 8); - - wxArrayString comboExtChoices; - comboExtChoices.Add(wxT(".csv")); - comboExtChoices.Add(wxT(".log")); - comboExt = new wxChoice(this, ID_COMBO_EXT, wxDefaultPosition, wxDefaultSize, comboExtChoices); - comboExt->SetSelection(0); - logExt = wxT(".csv"); - sizerLogType->Add(comboExt, 0, wxALL, 2); - - auto labelSep = new wxStaticText(this, wxID_ANY, wxT("Разделитель:")); - labelSep->Wrap(-1); - sizerLogType->Add(labelSep, 0, wxALL, 8); - - wxArrayString comboSepChoices; - comboSepChoices.Add(wxT(";")); - comboSepChoices.Add(wxT("Tab")); - comboSepChoices.Add(wxT("-")); - comboSepChoices.Add(wxT("_")); - comboSepChoices.Add(wxT("Space")); - - comboSep = new wxChoice(this, ID_COMBO_SEP, wxDefaultPosition, wxDefaultSize, comboSepChoices); - comboSep->SetSelection(0); - logSeparator = wxT(";"); - sizerLogType->Add(comboSep, 0, wxALL, 2); + // настройки типа файла журнала + auto sizerLogType = new wxBoxSizer(wxHORIZONTAL); + { + auto labelExt = new wxStaticText(pane, wxID_ANY, wxT("Тип файла:")); + labelExt->Wrap(-1); + sizerLogType->Add(labelExt, 0, wxALL, 8); + + wxArrayString comboExtChoices; + comboExtChoices.Add(wxT(".csv")); + comboExtChoices.Add(wxT(".log")); + choiceExt = new wxChoice(pane, wxID_ANY, wxDefaultPosition, wxDefaultSize, comboExtChoices); + choiceExt->SetSelection(0); + logExt = wxT(".csv"); + sizerLogType->Add(choiceExt, 0, wxALL, 2); + + auto labelSep = new wxStaticText(pane, wxID_ANY, wxT("Разделитель:")); + labelSep->Wrap(-1); + sizerLogType->Add(labelSep, 0, wxALL, 8); + + wxArrayString comboSepChoices; + comboSepChoices.Add(wxT(";")); + comboSepChoices.Add(wxT("Tab")); + comboSepChoices.Add(wxT("-")); + comboSepChoices.Add(wxT("_")); + comboSepChoices.Add(wxT("Space")); + + choiceSep = new wxChoice(pane, wxID_ANY, wxDefaultPosition, wxDefaultSize, comboSepChoices); + choiceSep->SetSelection(0); + logSeparator = wxT(";"); + sizerLogType->Add(choiceSep, 0, wxALL, 2); + } sizerLog->Add(sizerLogType, 0, wxALIGN_CENTER, 2); - } - - // параметры сохранения данных в лог - auto sizerLogParameters = new wxBoxSizer(wxVERTICAL); - { - checkSingle = new wxCheckBox(this, ID_CHECKBOX_SINGLE, wxT("Сохранение данных в один файл")); - checkSingle->SetValue(logSingle); - sizerLogParameters->Add(checkSingle, 0, wxALL, 5); - checkDec = new wxCheckBox(this, ID_CHECKBOX_DEC, wxT("Десятичный вывод данных")); - checkDec->SetValue(logDecimal); - sizerLogParameters->Add(checkDec, 0, wxALL, 5); - checkASCII = new wxCheckBox(this, ID_CHECKBOX_ASCII, wxT("Добавлять ASCII данные")); - checkASCII->SetValue(logASCII); - sizerLogParameters->Add(checkASCII, 0, wxALL, 5); + // параметры сохранения данных в лог + auto sizerLogParameters = new wxBoxSizer(wxVERTICAL); + { + checkSingle = new wxCheckBox(pane, wxID_ANY, wxT("Сохранение данных в один файл")); + checkSingle->SetValue(logSingle); + sizerLogParameters->Add(checkSingle, 0, wxALL, 5); + checkDec = new wxCheckBox(pane, wxID_ANY, wxT("Десятичный вывод данных")); + checkDec->SetValue(logDecimal); + sizerLogParameters->Add(checkDec, 0, wxALL, 5); + checkASCII = new wxCheckBox(pane, wxID_ANY, wxT("Добавлять ASCII данные")); + checkASCII->SetValue(logASCII); + sizerLogParameters->Add(checkASCII, 0, wxALL, 5); + } sizerLog->Add(sizerLogParameters, 0, wxALIGN_LEFT, 2); + + pane->SetSizer(sizerLog); } - sizerRight->Add(sizerLog, 0, wxALL | wxEXPAND, 2); + sizerLog->SetSizeHints(pane); } + sizerRight->Add(paneLog, 0, wxALL | wxEXPAND, 4); // элементы для наглядного представления чисел auto sizerDecoders = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, wxT("Декодированные значения")), wxVERTICAL); { - // отображение двоичного байта - auto sizerDecoderBinByte = new wxBoxSizer(wxHORIZONTAL); + // выбор типа данных для отображения и порядка следования байтов + auto sizerDataType = new wxBoxSizer(wxHORIZONTAL); { - auto labelBinByte = new wxStaticText(this, wxID_ANY, wxT("Двоичный байт:"), wxDefaultPosition, this->FromDIP(wxSize(120, -1))); - labelBinByte->Wrap(-1); - sizerDecoderBinByte->Add(labelBinByte, 0, wxALL | wxEXPAND, 3); - textBinByte = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, this->FromDIP(wxSize(200, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); - sizerDecoderBinByte->Add(textBinByte, 0, wxALL | wxEXPAND, 0); - sizerDecoders->Add(sizerDecoderBinByte, 0, wxALIGN_CENTER | wxALL, 2); + auto labelDataType = new wxStaticText(this, wxID_ANY, wxT("Тип данных:"), wxDefaultPosition, wxDefaultSize); + labelDataType->Wrap(-1); + sizerDataType->Add(labelDataType, 1, wxALL, 3); + wxArrayString comboDataTypeChoices; + comboDataTypeChoices.Add(TEXT_UINT8); + comboDataTypeChoices.Add(TEXT_UINT16); + comboDataTypeChoices.Add(TEXT_UINT32); + comboDataTypeChoices.Add(TEXT_INT8); + comboDataTypeChoices.Add(TEXT_INT16); + comboDataTypeChoices.Add(TEXT_INT32); + comboDataTypeChoices.Add(TEXT_FLOAT); + choiceDataType = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, comboDataTypeChoices); + choiceDataType->Select(0); + sizerDataType->Add(choiceDataType, 1, wxALL, 0); + sizerDataType->Add(0, 0, 1, wxALL, 0); + checkEndian = new wxCheckBox(this, wxID_ANY, wxT("Big-endian")); + checkEndian->SetValue(bigEndian); + checkEndian->Disable(); + sizerDataType->Add(checkEndian, 1, wxALL, 5); } + sizerDecoders->Add(sizerDataType, 0, wxALL | wxEXPAND, 2); - // отображение десятичного байта - auto sizerDecoderDecByte = new wxBoxSizer(wxHORIZONTAL); + // отображение двоичного байта + auto sizerDecoderBinary = new wxBoxSizer(wxHORIZONTAL); { - auto labelDecByte = new wxStaticText(this, wxID_ANY, wxT("Десятичный байт:"), wxDefaultPosition, this->FromDIP(wxSize(120, -1))); - labelDecByte->Wrap(-1); - sizerDecoderDecByte->Add(labelDecByte, 0, wxALL | wxEXPAND, 3); - textDecByte = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, this->FromDIP(wxSize(200, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); - sizerDecoderDecByte->Add(textDecByte, 0, wxALL | wxEXPAND, 0); - sizerDecoders->Add(sizerDecoderDecByte, 0, wxALIGN_CENTER | wxALL, 2); + auto labelBinary = new wxStaticText(this, wxID_ANY, wxT("Двоичный вид:"), wxDefaultPosition, wxDefaultSize); + labelBinary->Wrap(-1); + sizerDecoderBinary->Add(labelBinary, 1, wxALL, 3); + textBin = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); + sizerDecoderBinary->Add(textBin, 3, wxALL, 0); } + sizerDecoders->Add(sizerDecoderBinary, 0, wxALL | wxEXPAND, 2); - // выбор big endian или little endian - checkEndian = new wxCheckBox(this, ID_CHECKBOX_ENDIAN, wxT("Последовательность байтов big-endian")); - checkEndian->SetValue(bigEndian); - sizerDecoders->Add(checkEndian, 0, wxALL, 5); - - // отображение десятичного слова - auto sizerDecoderDecWord = new wxBoxSizer(wxHORIZONTAL); + // отображение десятичного байта + auto sizerDecoderDecimal = new wxBoxSizer(wxHORIZONTAL); { - auto labelDecWord = new wxStaticText(this, wxID_ANY, wxT("Десятичное слово:"), wxDefaultPosition, this->FromDIP(wxSize(120, -1))); - labelDecWord->Wrap(-1); - sizerDecoderDecWord->Add(labelDecWord, 0, wxALL | wxEXPAND, 3); - textDecWord = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, this->FromDIP(wxSize(200, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); - sizerDecoderDecWord->Add(textDecWord, 0, wxALL | wxEXPAND, 0); - sizerDecoders->Add(sizerDecoderDecWord, 0, wxALIGN_CENTER | wxALL, 2); + auto labelDecimal = new wxStaticText(this, wxID_ANY, wxT("Десятичный вид:"), wxDefaultPosition, wxDefaultSize); + labelDecimal->Wrap(-1); + sizerDecoderDecimal->Add(labelDecimal, 1, wxALL, 3); + textDec = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); + sizerDecoderDecimal->Add(textDec, 3, wxALL, 0); } + sizerDecoders->Add(sizerDecoderDecimal, 0, wxALL | wxEXPAND, 2); // множитель десятичного слова - auto sizerDecoderWordMul = new wxBoxSizer(wxHORIZONTAL); + auto sizerDecimalMul = new wxBoxSizer(wxHORIZONTAL); { - auto labelDecWordMul = new wxStaticText(this, wxID_ANY, wxT("Множитель слова:"), wxDefaultPosition, this->FromDIP(wxSize(120, -1))); - labelDecWordMul->Wrap(-1); - sizerDecoderWordMul->Add(labelDecWordMul, 0, wxALL | wxEXPAND, 3); - textDecWordMul = new wxTextCtrl(this, ID_TEXT_DEC_WORD_MUL, wxString::Format(wxT("%1.6f"), mul), wxDefaultPosition, this->FromDIP(wxSize(200, 22)), wxTE_CENTRE | wxTE_PROCESS_ENTER | wxBORDER_SIMPLE); - sizerDecoderWordMul->Add(textDecWordMul, 0, wxALL | wxEXPAND, 0); - sizerDecoders->Add(sizerDecoderWordMul, 0, wxALIGN_CENTER | wxALL, 2); + auto labelDecimalMul = new wxStaticText(this, wxID_ANY, wxT("Множитель:"), wxDefaultPosition, wxDefaultSize); + labelDecimalMul->Wrap(-1); + sizerDecimalMul->Add(labelDecimalMul, 1, wxALL, 3); + textDecWordMul = new wxTextCtrl(this, wxID_ANY, wxString::Format(FORMAT_FLOAT1_3, mul), wxDefaultPosition, wxDefaultSize, wxTE_CENTRE | wxTE_PROCESS_ENTER | wxBORDER_SIMPLE); + sizerDecimalMul->Add(textDecWordMul, 3, wxALL, 0); } + sizerDecoders->Add(sizerDecimalMul, 0, wxALL | wxEXPAND, 2); // результат умножения десятичного слова - auto sizerDecoderDecWordResult = new wxBoxSizer(wxHORIZONTAL); + auto sizerDecimalResult = new wxBoxSizer(wxHORIZONTAL); { - auto labelDecWordResult = new wxStaticText(this, wxID_ANY, wxT("Результат:"), wxDefaultPosition, this->FromDIP(wxSize(120, -1))); - labelDecWordResult->Wrap(-1); - sizerDecoderDecWordResult->Add(labelDecWordResult, 0, wxALL | wxEXPAND, 3); - textDecWordResult = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, this->FromDIP(wxSize(200, 22)), wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); - sizerDecoderDecWordResult->Add(textDecWordResult, 0, wxALL | wxEXPAND, 0); - sizerDecoders->Add(sizerDecoderDecWordResult, 0, wxALIGN_CENTER | wxALL, 2); + auto labelDecimalResult = new wxStaticText(this, wxID_ANY, wxT("Результат:"), wxDefaultPosition, wxDefaultSize); + labelDecimalResult->Wrap(-1); + sizerDecimalResult->Add(labelDecimalResult, 1, wxALL, 3); + textDecimalResult = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_CENTRE | wxTE_READONLY | wxBORDER_SIMPLE); + sizerDecimalResult->Add(textDecimalResult, 3, wxALL, 0); } - - sizerRight->Add(sizerDecoders, 0, wxALL | wxEXPAND, 2); + sizerDecoders->Add(sizerDecimalResult, 0, wxALL | wxEXPAND, 2); } + sizerRight->Add(sizerDecoders, 0, wxALL | wxEXPAND, 2); // панель для графика - drawPanel = new wxPanel(this, ID_DRAW_PANEL, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + drawPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + drawPanel->SetBackgroundStyle(wxBG_STYLE_PAINT); drawPanel->SetBackgroundColour(wxColour(255, 255, 255)); + sizerRight->Add(drawPanel, 1, wxALL | wxEXPAND, 2); - // ширина правой области - sizerMain->Add(sizerRight, 0, wxALL | wxEXPAND, 2); } + // ширина правой области + sizerMain->Add(sizerRight, 0, wxALL | wxEXPAND, 2); } this->SetSizer(sizerMain); this->SetAutoLayout(true); this->Layout(); this->Center(wxCENTER_ON_SCREEN); - this->SetDoubleBuffered(true); + //this->SetDoubleBuffered(true); this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); - // привязка событий (так нравится больше, но переделал на таблицу событий в начале кода, так как не смог сделать событие для UDP-сокета) - //buttonConnectDisconnect->Bind(wxEVT_BUTTON, &FormMain::ButtonConDiscon_OnClick, this); - //buttonAdd->Bind(wxEVT_BUTTON, &FormMain::ButtonAdd_OnClick, this); - //buttonRemove->Bind(wxEVT_BUTTON, &FormMain::ButtonRemove_OnClick, this); - //buttonRemoveAll->Bind(wxEVT_BUTTON, &FormMain::ButtonRemoveAll_OnClick, this); - //buttonSend->Bind(wxEVT_BUTTON, &FormMain::ButtonSend_OnClick, this); - //buttonClearCANLog->Bind(wxEVT_BUTTON, &FormMain::ButtonClearCANLog_OnClick, this); - //gridCANView->Bind(wxEVT_GRID_SELECT_CELL, &FormMain::GridCANView_OnSelectCell, this); - //comboExt->Bind(wxEVT_CHOICE, &FormMain::ComboExt_OnChoice, this); - //comboSep->Bind(wxEVT_CHOICE, &FormMain::ComboSep_OnChoice, this); - //checkDec->Bind(wxEVT_CHECKBOX, &FormMain::CheckDec_OnClick, this); - //checkSingle->Bind(wxEVT_CHECKBOX, &FormMain::CheckSingle_OnClick, this); - //checkEndian->Bind(wxEVT_CHECKBOX, &FormMain::CheckEndian_OnClick, this); - //checkASCII->Bind(wxEVT_CHECKBOX, &FormMain::CheckASCII_OnClick, this); - //textDecWordMul->Bind(wxEVT_TEXT_ENTER, &FormMain::TextDecWordMul_OnEnter, this); - //textCANAnswerID->Bind(wxEVT_TEXT_ENTER, &FormMain::TextCANAnswerID_OnEnter, this); - //this->Bind(wxEVT_TIMER, &FormMain::MainTimer_OnTimer, this, ID_MAIN_TIMER); - - // эту привязку событий оставил, так как иначе придётся делать наследование от wxPanel + // привязка событий + this->Bind(wxEVT_CLOSE_WINDOW, &FormMain::OnClose, this, ID_MAIN_FORM); + buttonConnectDisconnect->Bind(wxEVT_BUTTON, &FormMain::ButtonConnectDisconnect_OnClick, this); + buttonAdd->Bind(wxEVT_BUTTON, &FormMain::ButtonAdd_OnClick, this); + buttonRemove->Bind(wxEVT_BUTTON, &FormMain::ButtonRemove_OnClick, this); + buttonRemoveAll->Bind(wxEVT_BUTTON, &FormMain::ButtonRemoveAll_OnClick, this); + buttonSend->Bind(wxEVT_BUTTON, &FormMain::ButtonSend_OnClick, this); + buttonClearCANLog->Bind(wxEVT_BUTTON, &FormMain::ButtonClearCANLog_OnClick, this); + gridCANView->Bind(wxEVT_GRID_SELECT_CELL, &FormMain::GridCANView_OnSelectCell, this); + checkLogEnable->Bind(wxEVT_CHECKBOX, &FormMain::CheckLogEnable_OnClick, this); + choiceExt->Bind(wxEVT_CHOICE, &FormMain::ChoiceExt_OnChoice, this); + choiceSep->Bind(wxEVT_CHOICE, &FormMain::ChoiceSep_OnChoice, this); + checkDec->Bind(wxEVT_CHECKBOX, &FormMain::CheckDec_OnClick, this); + checkSingle->Bind(wxEVT_CHECKBOX, &FormMain::CheckSingle_OnClick, this); + choiceDataType->Bind(wxEVT_CHOICE, &FormMain::ChoiceDataType_OnChoice, this); + checkEndian->Bind(wxEVT_CHECKBOX, &FormMain::CheckEndian_OnClick, this); + checkASCII->Bind(wxEVT_CHECKBOX, &FormMain::CheckASCII_OnClick, this); + textDecWordMul->Bind(wxEVT_TEXT_ENTER, &FormMain::TextDecWordMul_OnEnter, this); + textCANAnswerID->Bind(wxEVT_TEXT_ENTER, &FormMain::TextCANAnswerID_OnEnter, this); + + // события панели графика drawPanel->Bind(wxEVT_PAINT, &FormMain::DrawPanel_OnPaint, this); drawPanel->Bind(wxEVT_SIZE, &FormMain::DrawPanel_OnSize, this); drawPanel->Bind(wxEVT_ERASE_BACKGROUND, &FormMain::DrawPanel_OnEraseBackground, this); drawFrameSize = drawPanel->GetClientSize().GetWidth(); drawData = new CircularFrameBuffer(drawFrameSize); - // событие от фонового потока COM-порта, а это не смог нормально описать в таблице событий + // событие от фонового потока COM-порта this->Bind(wxEVT_SERIAL_PORT_THREAD_UPDATE, &FormMain::Thread_OnUpdate, this); this->Bind(wxEVT_SERIAL_PORT_THREAD_EXIT, &FormMain::Thread_OnExit, this); this->Bind(wxEVT_SERIAL_PORT_THREAD_MESSAGE, &FormMain::Thread_OnMessage, this); + // так и не понял, как прикрепить обработчик события для сокета, поэтому он отдельно в таблице событий выше + //this->Bind(wxEVT_SOCKET, &FormMain::UDPSocket_OnEvent, this, ID_UDP_SOCKET); + + // событие таймера + this->Bind(wxEVT_TIMER, &FormMain::MainTimer_OnTimer, this, ID_MAIN_TIMER); + // настройка и запуск таймера timerMain = new wxTimer(this, ID_MAIN_TIMER); timerMain->Start(TIMER_INTERVAL); @@ -647,53 +653,11 @@ void FormMain::ProcessCANFrame(CANFrameIn& frame) } } -// Добавление полученных данных в очередь на отрисовку -void FormMain::AddToDraw() +// Выбран другой тип данных для отображения +void FormMain::ChoiceDataType_OnChoice(wxCommandEvent& event) { - if (rowToView >= 0 && colToView >= 0) - { - // если полученных данных ещё нет - if (rowToView >= frames.Size()) - { - return; - } - - // добавить полученные данные в очередь на отрисовку - if (drawData && colToView >= 0) - { - auto vFrame = frames.GetFrame(rowToView); - uint8_t firstByte = vFrame.frame.data[colToView]; - uint8_t secondByte = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; - // выбор между big endian и little endian - uint32_t value = bigEndian ? (firstByte << 8) + secondByte : (secondByte << 8) + firstByte; - uint32_t mulValue = (double)value * mul; - drawData->Add(mulValue); - } - } -} - -// Отображение выделенной ячейки в разных форматах -void FormMain::ShowNumbers() -{ - if (rowToView >= 0 && colToView >= 0) - { - // если полученных данных ещё нет - if (rowToView >= frames.Size()) - { - return; - } - - auto vFrame = frames.GetFrame(rowToView); - uint8_t firstByte = vFrame.frame.data[colToView]; - uint8_t secondByte = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; - textBinByte->ChangeValue(ToBinary(firstByte)); - textDecByte->ChangeValue(wxString::Format(FORMAT_INT, firstByte)); - // выбор между big endian и little endian - uint32_t value = bigEndian ? (firstByte << 8) + secondByte : (secondByte << 8) + firstByte; - textDecWord->ChangeValue(wxString::Format(FORMAT_INT, value)); - uint32_t mulValue = (double)value * mul; - textDecWordResult->ChangeValue(wxString::Format(FORMAT_INT, mulValue)); - } + dataType = (DataTypes)event.GetSelection(); + checkEndian->Enable(dataType != DataTypes::UInt8 && dataType != DataTypes::Int8); } // Обновляет список ID для записи в log @@ -710,15 +674,19 @@ void FormMain::RefreshListLog() // При нажатии Enter в поле ввода множителя - обработать его и запомнить void FormMain::TextDecWordMul_OnEnter(wxCommandEvent& event) { - textDecWordMul->GetValue().ToDouble(&mul); - - if (mul == 0) - mul = 1.0; - else if (mul > 10000) - mul = 10000.0; + double newMul; + if (textDecWordMul->GetValue().ToDouble(&newMul)) + { + float newFloatMul = (float)newMul; + if (newFloatMul == 0) + mul = 1.0; + else if (newFloatMul > 10000) + mul = 10000.0; + else + mul = newFloatMul; + } - textDecWordMul->ChangeValue(wxString::Format(FORMAT_FLOAT, mul)); - drawMaxValue = 0; + textDecWordMul->ChangeValue(wxString::Format(FORMAT_FLOAT1_3, mul)); } // Добавить ID в список фильтра для записи в log @@ -769,13 +737,13 @@ void FormMain::CheckLogEnable_OnClick(wxCommandEvent& event) } // Выбор расширения файла -void FormMain::ComboExt_OnChoice(wxCommandEvent& event) +void FormMain::ChoiceExt_OnChoice(wxCommandEvent& event) { logExt = event.GetString(); } // Выбор разделителя в log-файле -void FormMain::ComboSep_OnChoice(wxCommandEvent& event) +void FormMain::ChoiceSep_OnChoice(wxCommandEvent& event) { auto value = event.GetString(); if (value == wxT("Tab")) @@ -981,18 +949,12 @@ void FormMain::GridCANView_OnSelectCell(wxGridEvent& event) rowToView = -1; colToView = -1; - textBinByte->ChangeValue(wxT("")); - textDecByte->ChangeValue(wxT("")); - textDecWord->ChangeValue(wxT("")); + textBin->ChangeValue(wxT("")); + textDec->ChangeValue(wxT("")); + textDecimalResult->ChangeValue(wxT("")); } else { - if (drawData) - { - drawData->Clear(); - drawDataBegin = 0; - drawMaxValue = 0; - } // показать числа в разных форматах ShowNumbers(); } @@ -1005,15 +967,63 @@ wxString FormMain::ToBinary(uint8_t value) for (size_t counter = 0; counter < 4; counter++) { - if (value & 0x80) binaryString += wxT('1'); - else binaryString += wxT('0'); + binaryString += (value & 0x80) ? wxT('1') : wxT('0'); value <<= 1; } binaryString += wxT('_'); for (size_t counter = 0; counter < 4; counter++) { - if (value & 0x80) binaryString += wxT('1'); - else binaryString += wxT('0'); + binaryString += (value & 0x80) ? wxT('1') : wxT('0'); + value <<= 1; + } + return binaryString; +} + +// Преобразовывает 16-бит слово в двоичное представление +wxString FormMain::ToBinary(uint16_t value) +{ + wxString binaryString; + + for (size_t counter = 0; counter < 8; counter++) + { + binaryString += (value & 0x8000) ? wxT('1') : wxT('0'); + value <<= 1; + } + binaryString += wxT('_'); + for (size_t counter = 0; counter < 8; counter++) + { + binaryString += (value & 0x8000) ? wxT('1') : wxT('0'); + value <<= 1; + } + return binaryString; +} + +// Преобразовывает 32-бит слово в двоичное представление +wxString FormMain::ToBinary(uint32_t value) +{ + wxString binaryString; + + for (size_t counter = 0; counter < 8; counter++) + { + binaryString += (value & 0x80000000) ? wxT('1') : wxT('0'); + value <<= 1; + } + binaryString += wxT('_'); + for (size_t counter = 0; counter < 8; counter++) + { + binaryString += (value & 0x80000000) ? wxT('1') : wxT('0'); + value <<= 1; + } + binaryString += wxT('_'); + for (size_t counter = 0; counter < 8; counter++) + { + binaryString += (value & 0x80000000) ? wxT('1') : wxT('0'); + value <<= 1; + } + binaryString += wxT('_'); + for (size_t counter = 0; counter < 8; counter++) + { + binaryString += (value & 0x80000000) ? wxT('1') : wxT('0'); value <<= 1; } return binaryString; @@ -1036,7 +1046,7 @@ void FormMain::MainTimer_OnTimer(wxTimerEvent& event) ShowNumbers(); // это вызовет событие OnPaint для панели - drawPanel->Refresh(true, &drawRectangle); + drawPanel->Refresh(); } // Обновить данные CAN-пакетов в таблице, вызывается по таймеру @@ -1072,17 +1082,43 @@ void FormMain::RefreshGridCANView() { // вывод пустых ячеек gridCANView->SetCellValue(iFrame, iData + 3, wxT(" ")); - gridCANView->SetCellBackgroundColour(iFrame, iData + 3, wxColor(DEFAULT_COLOR)); + gridCANView->SetCellBackgroundColour(iFrame, iData + 3, wxColour(DEFAULT_COLOR)); } } } // раскраска выделенных ячеек if (colToView >= 0) { - gridCANView->SetCellBackgroundColour(rowToView, colToView + 3, wxColor(SELECTED_COLOR)); - if (colToView < 7) + gridCANView->SetCellBackgroundColour(rowToView, colToView + 3, wxColour(SELECTED_COLOR)); + switch (dataType) { - gridCANView->SetCellBackgroundColour(rowToView, colToView + 4, wxColor(SELECTED_COLOR)); + case DataTypes::UInt16: + case DataTypes::Int16: + if (colToView < 7) + { + gridCANView->SetCellBackgroundColour(rowToView, colToView + 4, wxColour(SELECTED_COLOR)); + } + break; + + case DataTypes::UInt32: + case DataTypes::Int32: + case DataTypes::Float: + if (colToView < 5) + { + gridCANView->SetCellBackgroundColour(rowToView, colToView + 4, wxColour(SELECTED_COLOR)); + gridCANView->SetCellBackgroundColour(rowToView, colToView + 5, wxColour(SELECTED_COLOR)); + gridCANView->SetCellBackgroundColour(rowToView, colToView + 6, wxColour(SELECTED_COLOR)); + } + else if (colToView < 6) + { + gridCANView->SetCellBackgroundColour(rowToView, colToView + 4, wxColour(SELECTED_COLOR)); + gridCANView->SetCellBackgroundColour(rowToView, colToView + 5, wxColour(SELECTED_COLOR)); + } + else if (colToView < 7) + { + gridCANView->SetCellBackgroundColour(rowToView, colToView + 4, wxColour(SELECTED_COLOR)); + } + break; } } // обновить отображение таблицы @@ -1090,13 +1126,223 @@ void FormMain::RefreshGridCANView() } } +// Отображение выделенной ячейки в разных форматах +void FormMain::ShowNumbers() +{ + if (rowToView >= 0 && colToView >= 0) + { + // если полученных данных ещё нет + if (rowToView >= frames.Size()) + { + return; + } + + auto vFrame = frames.GetFrame(rowToView); + + switch (dataType) + { + case DataTypes::UInt8: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + textBin->ChangeValue(ToBinary(byte1)); + textDec->ChangeValue(wxString::Format(FORMAT_UINT, byte1)); + uint32_t mulValue = (float)byte1 * mul; + textDecimalResult->ChangeValue(wxString::Format(FORMAT_UINT, mulValue)); + break; + } + + case DataTypes::UInt16: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + // выбор между big endian и little endian + uint16_t value = bigEndian ? (byte1 << 8) + byte2 : (byte2 << 8) + byte1; + textBin->ChangeValue(ToBinary((uint16_t)value)); + textDec->ChangeValue(wxString::Format(FORMAT_UINT, value)); + uint32_t mulValue = (float)value * mul; + textDecimalResult->ChangeValue(wxString::Format(FORMAT_UINT, mulValue)); + break; + } + + case DataTypes::UInt32: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + uint8_t byte3 = colToView < 6 ? vFrame.frame.data[colToView + 2] : 0; + uint8_t byte4 = colToView < 5 ? vFrame.frame.data[colToView + 3] : 0; + // выбор между big endian и little endian + uint32_t value = bigEndian ? (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4 : (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; + textBin->ChangeValue(ToBinary(value)); + textDec->ChangeValue(wxString::Format(FORMAT_UINT, value)); + uint32_t mulValue = (float)value * mul; + textDecimalResult->ChangeValue(wxString::Format(FORMAT_UINT, mulValue)); + break; + } + + case DataTypes::Int8: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + textBin->ChangeValue(ToBinary(byte1)); + textDec->ChangeValue(wxString::Format(FORMAT_INT, (int8_t)byte1)); + int32_t mulValue = (float)((int8_t)byte1) * mul; + textDecimalResult->ChangeValue(wxString::Format(FORMAT_INT, mulValue)); + break; + } + + case DataTypes::Int16: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + // выбор между big endian и little endian + uint16_t value = bigEndian ? (byte1 << 8) + byte2 : (byte2 << 8) + byte1; + textBin->ChangeValue(ToBinary((uint16_t)value)); + textDec->ChangeValue(wxString::Format(FORMAT_INT, (int16_t)value)); + int32_t mulValue = (float)((int16_t)value) * mul; + textDecimalResult->ChangeValue(wxString::Format(FORMAT_INT, mulValue)); + break; + } + + case DataTypes::Int32: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + uint8_t byte3 = colToView < 6 ? vFrame.frame.data[colToView + 2] : 0; + uint8_t byte4 = colToView < 5 ? vFrame.frame.data[colToView + 3] : 0; + // выбор между big endian и little endian + uint32_t value = bigEndian ? (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4 : (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; + textBin->ChangeValue(ToBinary(value)); + textDec->ChangeValue(wxString::Format(FORMAT_INT, (int32_t)value)); + int32_t mulValue = (float)((int32_t)value) * mul; + textDecimalResult->ChangeValue(wxString::Format(FORMAT_INT, mulValue)); + break; + } + + case DataTypes::Float: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + uint8_t byte3 = colToView < 6 ? vFrame.frame.data[colToView + 2] : 0; + uint8_t byte4 = colToView < 5 ? vFrame.frame.data[colToView + 3] : 0; + // выбор между big endian и little endian + uint32_t value = bigEndian ? (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4 : (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; + textBin->ChangeValue(ToBinary(value)); + auto floatValue = *(float*)((uint32_t*)&value); + textDec->ChangeValue(wxString::Format(FORMAT_FLOAT1_3, floatValue)); + float mulValue = floatValue * mul; + textDecimalResult->ChangeValue(wxString::Format(FORMAT_FLOAT1_3, mulValue)); + break; + } + } + } +} + +// Добавление полученных данных в очередь на отрисовку +void FormMain::AddToDraw() +{ + if (rowToView >= 0 && colToView >= 0) + { + // если полученных данных ещё нет + if (rowToView >= frames.Size()) + { + return; + } + + // добавить полученные данные в очередь на отрисовку + if (drawData && colToView >= 0) + { + auto vFrame = frames.GetFrame(rowToView); + + switch (dataType) + { + case DataTypes::UInt8: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + float mulValue = (float)byte1 * mul; + drawData->Add(mulValue); + break; + } + + case DataTypes::UInt16: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + // выбор между big endian и little endian + uint16_t value = bigEndian ? (byte1 << 8) + byte2 : (byte2 << 8) + byte1; + float mulValue = (float)value * mul; + drawData->Add(mulValue); + break; + } + + case DataTypes::UInt32: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + uint8_t byte3 = colToView < 6 ? vFrame.frame.data[colToView + 2] : 0; + uint8_t byte4 = colToView < 5 ? vFrame.frame.data[colToView + 3] : 0; + // выбор между big endian и little endian + uint32_t value = bigEndian ? (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4 : (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; + float mulValue = (float)value * mul; + drawData->Add(mulValue); + break; + } + + case DataTypes::Int8: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + float mulValue = (float)((int8_t)byte1) * mul; + drawData->Add(mulValue); + break; + } + + case DataTypes::Int16: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + // выбор между big endian и little endian + uint16_t value = bigEndian ? (byte1 << 8) + byte2 : (byte2 << 8) + byte1; + float mulValue = (float)((int16_t)value) * mul; + drawData->Add(mulValue); + break; + } + + case DataTypes::Int32: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + uint8_t byte3 = colToView < 6 ? vFrame.frame.data[colToView + 2] : 0; + uint8_t byte4 = colToView < 5 ? vFrame.frame.data[colToView + 3] : 0; + // выбор между big endian и little endian + uint32_t value = bigEndian ? (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4 : (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; + float mulValue = (float)((int32_t)value) * mul; + drawData->Add(mulValue); + break; + } + + case DataTypes::Float: + { + uint8_t byte1 = vFrame.frame.data[colToView]; + uint8_t byte2 = colToView < 7 ? vFrame.frame.data[colToView + 1] : 0; + uint8_t byte3 = colToView < 6 ? vFrame.frame.data[colToView + 2] : 0; + uint8_t byte4 = colToView < 5 ? vFrame.frame.data[colToView + 3] : 0; + // выбор между big endian и little endian + uint32_t value = bigEndian ? (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4 : (byte4 << 24) + (byte3 << 16) + (byte2 << 8) + byte1; + float mulValue = *(float*)((uint32_t*)&value) * mul; + drawData->Add(mulValue); + break; + } + } + } + } +} + // Событие отрисовки в панели графика void FormMain::DrawPanel_OnPaint(wxPaintEvent& event) { //wxPaintDC dc(drawPanel); - wxBufferedPaintDC dc(drawPanel); // с буферной отрисовкой не мерцает - + //wxBufferedPaintDC dc(drawPanel); + wxAutoBufferedPaintDC dc(drawPanel); PrepareDC(dc); + auto drawRectangle = drawPanel->GetClientRect(); // нарисовать рамку и фон dc.SetPen(blackPen); @@ -1104,33 +1350,47 @@ void FormMain::DrawPanel_OnPaint(wxPaintEvent& event) if (drawData && colToView >= 0) { - float drawMul = (drawMaxValue != 0) ? (float)drawRectangle.height / (float)drawMaxValue : 1.0; + float* frame = drawData->Frame(); - dc.SetPen(graphPen); + float minValue = 0; + float maxValue = 0; + // поиск наибольшего значения для графика + for (size_t index = 0; index < drawFrameSize; index++) + { + float nextValue = *(frame + index); + if (nextValue < minValue) minValue = nextValue; + if (nextValue > maxValue) maxValue = nextValue; + } - uint32_t* frame = drawData->Frame(); + // вычисление масштабного коэффициента + float height = (float)drawRectangle.height; + float scaleFactor = -height / (maxValue - minValue); - for (size_t index = 1; index < drawFrameSize; index++) - { - // рисовать отмасштабированную линию - wxCoord y1 = (wxCoord)((float)drawRectangle.height - (float)(*(frame + index - 1)) * drawMul); - wxCoord y2 = (wxCoord)((float)drawRectangle.height - (float)(*(frame + index)) * drawMul); - dc.DrawLine(index, y1, index, y2); + // нарисовать осевую линию по нулю + wxCoord y = (-minValue) * scaleFactor + height; + dc.DrawLine(0, y, drawRectangle.width, y); - // сохранение наибольшего значения для следующей итерации - if (*(frame + index) > drawMaxValue) - { - drawMaxValue = *(frame + index); - } + // рисовать отмасштабированный график + dc.SetPen(graphPen); + y = (*frame - minValue) * scaleFactor + height; + for (size_t index = 1; index < drawFrameSize; index++) + { + wxCoord yy = (*(frame + index) - minValue) * scaleFactor + height; + dc.DrawLine(index - 1, y, index, yy); + y = yy; } + + auto fontMetrics = dc.GetFontMetrics(); + dc.DrawText(wxString::Format(FORMAT_FLOAT1_0, maxValue), fontMetrics.internalLeading, 0); + dc.DrawText(wxString::Format(FORMAT_FLOAT1_0, minValue), fontMetrics.internalLeading, drawRectangle.height - fontMetrics.height - fontMetrics.descent); } } // Изменение размеров панели графика void FormMain::DrawPanel_OnSize(wxSizeEvent& event) { - drawRectangle = drawPanel->GetClientRect(); - this->Refresh(true, &drawRectangle); + //drawRectangle = drawPanel->GetClientRect(); + //this->Refresh(true, &drawRectangle); //event.Skip(); } diff --git a/wxCAN-Sniffer/FormMain.h b/wxCAN-Sniffer/FormMain.h index 160c7da..c4bc145 100644 --- a/wxCAN-Sniffer/FormMain.h +++ b/wxCAN-Sniffer/FormMain.h @@ -3,39 +3,23 @@ #include "Common.h" #include #include +#include #include #include #include "ThreadedSerialPort.h" #include "CircularFrameBuffer.h" #include "FramesContainer.h" -#define DRAW_COLOR 0x0000FF // red (BGR) -#define TIMER_INTERVAL 40 // интервал срабатывания таймера обновления данных на экране (около 25 кадров/с) +#define DRAW_COLOR 0xFF0000FFlu // (ABGR) красный +#define TIMER_INTERVAL 40 // интервал срабатывания таймера обновления данных на экране (около 25 кадров/с) -// Идентификаторы необходимых объектов -enum IDs -{ - ID_MAIN_FORM = wxID_HIGHEST + 1, - ID_MAIN_TIMER, - ID_BUTON_CONNECT_DISCONNECT, - ID_CHECKBOX_LOG_ENABLE, - ID_BUTTON_ADD, - ID_BUTTON_REMOVE, - ID_BUTTON_REMOVE_ALL, - ID_BUTTON_SEND, - ID_BUTTON_CLEAR_LOG, - ID_GRID_CAN_VIEW, - ID_COMBO_EXT, - ID_COMBO_SEP, - ID_CHECKBOX_SINGLE, - ID_CHECKBOX_DEC, - ID_CHECKBOX_ENDIAN, - ID_CHECKBOX_ASCII, - ID_DRAW_PANEL, - ID_TEXT_DEC_WORD_MUL, - ID_TEXT_CAN_ANSWER_ID, - ID_UDP_SOCKET -}; +#define TEXT_UINT8 wxT("UInt8") +#define TEXT_UINT16 wxT("UInt16") +#define TEXT_UINT32 wxT("UInt32") +#define TEXT_INT8 wxT("Int8") +#define TEXT_INT16 wxT("Int16") +#define TEXT_INT32 wxT("Int32") +#define TEXT_FLOAT wxT("Float") //  Класс окна class FormMain : public wxFrame @@ -51,14 +35,15 @@ class FormMain : public wxFrame void ButtonRemoveAll_OnClick(wxCommandEvent& event); void ButtonSend_OnClick(wxCommandEvent& event); void ButtonClearCANLog_OnClick(wxCommandEvent& event); - void ComboExt_OnChoice(wxCommandEvent& event); - void ComboSep_OnChoice(wxCommandEvent& event); + void ChoiceExt_OnChoice(wxCommandEvent& event); + void ChoiceSep_OnChoice(wxCommandEvent& event); void CheckLogEnable_OnClick(wxCommandEvent& event); void CheckDec_OnClick(wxCommandEvent& event); void CheckSingle_OnClick(wxCommandEvent& event); void CheckASCII_OnClick(wxCommandEvent& event); void MainTimer_OnTimer(wxTimerEvent& event); void GridCANView_OnSelectCell(wxGridEvent& event); + void ChoiceDataType_OnChoice(wxCommandEvent& event); void CheckEndian_OnClick(wxCommandEvent& event); void TextDecWordMul_OnEnter(wxCommandEvent& event); void TextCANAnswerID_OnEnter(wxCommandEvent& event); @@ -94,25 +79,46 @@ class FormMain : public wxFrame wxTextCtrl* textFPS; wxTextCtrl* textBPS; wxButton* buttonConnectDisconnect; + wxCollapsiblePane* paneLog; wxButton* buttonAdd; wxButton* buttonRemove; wxButton* buttonRemoveAll; wxListBox* listLog; - wxChoice* comboExt; - wxChoice* comboSep; + wxChoice* choiceExt; + wxChoice* choiceSep; wxCheckBox* checkLogEnable; wxCheckBox* checkDec; wxCheckBox* checkSingle; wxCheckBox* checkASCII; - wxTextCtrl* textBinByte; - wxTextCtrl* textDecByte; + wxChoice* choiceDataType; + wxTextCtrl* textBin; + wxTextCtrl* textDec; wxCheckBox* checkEndian; - wxTextCtrl* textDecWord; wxTextCtrl* textDecWordMul; - wxTextCtrl* textDecWordResult; + wxTextCtrl* textDecimalResult; wxPanel* drawPanel; wxTimer* timerMain; + // Идентификаторы необходимых объектов + enum IDs + { + ID_MAIN_FORM = wxID_HIGHEST + 1, + ID_MAIN_TIMER, + ID_UDP_SOCKET + }; + + // Типы данных для преобразования и графика + enum DataTypes + { + UInt8 = 0, + UInt16, + UInt32, + Int8, + Int16, + Int32, + Float + }; + ThreadedSerialPort* serialPort = nullptr; // последовательный порт в отдельном потоке FramesContainer frames; // список отображаемых на экране пакетов @@ -130,15 +136,14 @@ class FormMain : public wxFrame int32_t rowToView = -1; // номер строки выбранной ячейки для отображения данных о ней int32_t colToView = -1; // номер столбца выбранной ячейки для отображения данных о ней - double mul = 0.125; // множитель для отображаемых чисел + float mul = 1.0; // множитель для отображаемых чисел + DataTypes dataType = DataTypes::UInt8; // тип данных для отображения wxPen blackPen = *wxBLACK; // кисть рамки для отрисовки графика - wxPen graphPen = wxPen(wxColour(DRAW_COLOR, 0, 0), 3); // кисть для отрисовки графика заданной ширины - wxRect drawRectangle; // область отрисовки графика + wxPen graphPen = wxPen(wxColour(DRAW_COLOR), 3); // кисть для отрисовки графика заданной ширины CircularFrameBuffer* drawData = nullptr; // круговой массив данных для отрисовки size_t drawFrameSize; // размер кадра отрисовки (равен ширине области панель) uint32_t drawDataBegin = 0; // начало данных в массиве - uint32_t drawMaxValue = 0; // наибольшее рисуемое значение для масштабирования графика uint32_t answerID = 0x7E8; // ID пакета, от которого будут отображаться данные bool bigEndian = true; // порядок следования байтов в слове big-endian @@ -153,6 +158,8 @@ class FormMain : public wxFrame void FlushLogs(); void LogWriteLine(wxFFile* file, CANFrameIn& frame); wxString ToBinary(uint8_t value); + wxString ToBinary(uint16_t value); + wxString ToBinary(uint32_t value); void AddToDraw(); void ShowNumbers(); void UDPSocket_SendFrame(CANFrameOut& frame); diff --git a/wxCAN-Sniffer/FramesContainer.h b/wxCAN-Sniffer/FramesContainer.h index d78aab3..059dc31 100644 --- a/wxCAN-Sniffer/FramesContainer.h +++ b/wxCAN-Sniffer/FramesContainer.h @@ -2,11 +2,11 @@ #include "Common.h" -#define FRAMES_DATA_RESERV 1000 // количество элементов для резерва в векторе -#define NEW_COLOR 0xFF00FF00 // (ABGR) зелёный - для выделения новых данных -#define CHANGE_COLOR 0xFF0000FF // (ABGR) красный - для выделения изменяемых данных -#define DEFAULT_COLOR 0xFFFFFFFF // (ABGR) белый - цвет ячейки по умолчанию -#define SELECTED_COLOR 0xFFFFB080 // (ABGR) голубой - цвет выделенных ячеек +#define FRAMES_DATA_RESERV 1000 // количество элементов для резерва в векторе +#define NEW_COLOR 0xFF00FF00lu // (ABGR) зелёный - для выделения новых данных +#define CHANGE_COLOR 0xFF0000FFlu // (ABGR) красный - для выделения изменяемых данных +#define DEFAULT_COLOR 0xFFFFFFFFlu // (ABGR) белый - цвет ячейки по умолчанию +#define SELECTED_COLOR 0xFFE3A04Clu // (ABGR) голубой - цвет выделенных ячеек class FramesContainer { diff --git a/wxCAN-Sniffer/Info.plist b/wxCAN-Sniffer/Info.plist new file mode 100644 index 0000000..67b02d2 --- /dev/null +++ b/wxCAN-Sniffer/Info.plist @@ -0,0 +1,16 @@ + + + + + CFBundleIdentifier + ru.krufft.can_sniffer + CFBundleDevelopmentRegion + ru-RU + CFBundlePackageType + APPL + NSPrincipalClass + NSApplication + NSHighResolutionCapable + + + diff --git a/wxCAN-Sniffer/wxCAN-Sniffer.vcxproj b/wxCAN-Sniffer/wxCAN-Sniffer.vcxproj index db1d7ce..bde5854 100644 --- a/wxCAN-Sniffer/wxCAN-Sniffer.vcxproj +++ b/wxCAN-Sniffer/wxCAN-Sniffer.vcxproj @@ -188,6 +188,9 @@ + + +