|
#include <vcl.h> #pragma hdrstop #include <io.h> #include <fcntl.h> #include <sys\stat.h> #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;
#define BUFSIZE 255 //ёмкость буфера
unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE];
//---------------------------------------------------------------------------
HANDLE COMport;
/OVERLAPPED overlapped; OVERLAPPED overlappedwr; //---------------------------------------------------------------------------
int handle;
//---------------------------------------------------------------------------
bool fl=0;
unsigned long counter; //--------------------------------------------------------------------------- void COMOpen(void); void COMClose(void);
//============================================================================= //.............................. объявления потоков ........................... //=============================================================================
//---------------------------------------------------------------------------
//поток для чтения последовательности байтов из COM-порта в буфер class ReadThread : public TThread { private: void __fastcall Printing(); //вывод принятых байтов на экран и в файл protected: void __fastcall Execute(); //основная функция потока public: __fastcall ReadThread(bool CreateSuspended); //конструктор потока };
//---------------------------------------------------------------------------
//поток для записи последовательности байтов из буфера в COM-порт class WriteThread : public TThread { private: void __fastcall Printing(); //вывод состояния на экран protected: void __fastcall Execute(); //основная функция потока public: __fastcall WriteThread(bool CreateSuspended); //конструктор потока };
/*---------------------------Поток чтения с порта-----------------------------*/
ReadThread *reader;
//---------------------------------------------------------------------------
__fastcall ReadThread::ReadThread(bool CreateSuspended) : TThread(CreateSuspended) {} void __fastcall ReadThread::Execute() { COMSTAT comstat; DWORD btr, temp, mask, signal;
overlapped.hEvent = CreateEvent(NULL, true, true, NULL); SetCommMask(COMport, EV_RXCHAR); while(!Terminated) //пока поток не будет прерван, выполняем цикл { WaitCommEvent(COMport, &mask, &overlapped); signal = WaitForSingleObject(overlapped.hEvent, INFINITE); if(signal == WAIT_OBJECT_0) { if(GetOverlappedResult(COMport, &overlapped, &temp, true)) if((mask & EV_RXCHAR)!=0) { ClearCommError(COMport, &temp, &comstat); btr = comstat.cbInQue; if(btr) { ReadFile(COMport, bufrd, btr, &temp, &overlapped); counter+=btr; Synchronize(Printing); } } } } CloseHandle(overlapped.hEvent); /*перед выходом из потока закрыть объект-событие*/ }
//---------------------------------------------------------------------------
void __fastcall ReadThread::Printing() {
Form1->Memo1->Lines->Add((char*)bufrd); //выводим принятую строку в Memo /* Form1->StatusBar1->Panels->Items[2]->Text = "Всего принято " + IntToStr(counter) + " байт"; //выводим счётчик в строке состояния*/
if(Form1->CheckBox3->Checked == true) //если включен режим вывода в файл { write(handle, bufrd, strlen(bufrd)); //записать в файл данные из приёмного буфера } memset(bufrd, 0, BUFSIZE); }
WriteThread *writer;
/*--------------------------поток записи данных в порт-------------------------*/
__fastcall WriteThread::WriteThread(bool CreateSuspended) : TThread(CreateSuspended) {}
//---------------------------------------------------------------------------
void __fastcall WriteThread::Execute() { DWORD temp, signal;
overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL); //создать событие WriteFile(COMport, bufwr, strlen(bufwr), &temp, &overlappedwr); //записать байты в порт signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE); if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlappedwr, &temp, true))) fl = true; else fl = false; Synchronize(Printing); CloseHandle(overlappedwr.hEvent); //перед выходом из потока закрыть объект-событие }
//---------------------------------------------------------------------------
//вывод состояния передачи данных на экран void __fastcall WriteThread::Printing() { if(!fl) //проверяем состояние флажка { Form1->StatusBar1->Panels->Items[0]->Text = "Ошибка передачи"; return; } Form1->StatusBar1->Panels->Items[0]->Text = "Передача прошла успешно"; }
/////////////////////////////////////////////////////////////////////////////// /// форма /// ///////////////////////////////////////////////////////////////////////////////
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { //инициализация элементов формы при запуске программы Form1->Label5->Enabled = false; Form1->Label6->Enabled = false; Form1->Button1->Enabled = false; Form1->CheckBox1->Enabled = false; Form1->CheckBox2->Enabled = false; }
//---------------------------------------------------------------------------
//обработчик нажатия на кнопку "Открыть порт" void __fastcall TForm1::SpeedButton1Click(TObject *Sender) { if(SpeedButton1->Down) { COMOpen();
Form1->ComboBox1->Enabled = false; Form1->ComboBox2->Enabled = false; Form1->Button1->Enabled = true; Form1->CheckBox1->Enabled = true; Form1->CheckBox2->Enabled = true;
Form1->SpeedButton1->Caption = "Закрыть порт"; counter = 0; Form1->CheckBox1Click(Sender); Form1->CheckBox2Click(Sender); }
else { COMClose(); Form1->SpeedButton1->Caption = "Открыть порт"; Form1->StatusBar1->Panels->Items[0]->Text = ""; //очистить первую колонку строки состояния Form1->ComboBox1->Enabled = true; Form1->ComboBox2->Enabled = true; Form1->Button1->Enabled = false; Form1->CheckBox1->Enabled = false; Form1->CheckBox2->Enabled = false; } }
//---------------------------------------------------------------------------
//обработчик закрытия формы void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { if(reader)reader->Terminate(); //завершить поток чтения из порта, проверка if(reader) обязательна, иначе возникают ошибки if(writer)writer->Terminate(); //завершить поток записи в порт, проверка if(writer) обязательна, иначе возникают ошибки if(COMport)CloseHandle(COMport); //закрыть порт if(handle)close(handle); //закрыть файл, в который велась запись принимаемых данных
} //---------------------------------------------------------------------------
//галочка "Сохранить в файл" void __fastcall TForm1::CheckBox3Click(TObject *Sender) { if(Form1->CheckBox3->Checked) //если галочка включена { //активировать соответствующие элементы на форме Form1->Label5->Enabled = true; Form1->Label6->Enabled = true;
//вывести индикатор записи в файл в строке состояния Form1->StatusBar1->Panels->Items[1]->Text = "Вывод в файл!"; }
else //если галочка выключена { //отключить соответствующие элементы на форме Form1->Label5->Enabled = false; Form1->Label6->Enabled = false;
//убрать индикатор записи в файл из строки состояния Form1->StatusBar1->Panels->Items[1]->Text = ""; }
} //---------------------------------------------------------------------------
//кнопка "Передать" void __fastcall TForm1::Button1Click(TObject *Sender) { memset(bufwr,0,BUFSIZE); //очистить программный передающий буфер, чтобы данные не накладывались друг на друга PurgeComm(COMport, PURGE_TXCLEAR); //очистить передающий буфер порта strcpy(bufwr,Form1->Edit1->Text.c_str()); //занести в программный передающий буфер строку из Edit1
writer = new WriteThread(false); //создать и активировать поток записи данных в порт writer->FreeOnTerminate = true; //установить это свойство, чтобы поток автоматически уничтожался после завершения
}
//---------------------------------------------------------------------------
//кнопка "Очистить поле" void __fastcall TForm1::Button3Click(TObject *Sender) { Form1->Memo1->Clear(); //очистить Memo1 }
//---------------------------------------------------------------------------
//галочка "DTR" void __fastcall TForm1::CheckBox1Click(TObject *Sender) { //если установлена - установить линию DTR в единицу, иначе - в ноль if(Form1->CheckBox1->Checked) EscapeCommFunction(COMport, SETDTR); else EscapeCommFunction(COMport, CLRDTR); }
//---------------------------------------------------------------------------
//галочка "RTS" void __fastcall TForm1::CheckBox2Click(TObject *Sender) { //если установлена - установить линию RTS в единицу, иначе - в ноль if(Form1->CheckBox2->Checked) EscapeCommFunction(COMport, SETRTS); else EscapeCommFunction(COMport, CLRRTS); }
//---------------------------------------------------------------------------
//============================================================================= //........................... реализации функций .............................. //=============================================================================
//---------------------------------------------------------------------------
//функция открытия и инициализации порта void COMOpen() { String portname; //имя порта (например, "COM1", "COM2" и т.д.) DCB dcb; //структура для общей инициализации порта DCB COMMTIMEOUTS timeouts; //структура для установки таймаутов portname = Form1->ComboBox1->Text; //получить имя выбранного порта
if(COMport == INVALID_HANDLE_VALUE) //если ошибка открытия порта { Form1->SpeedButton1->Down = false; //отжать кнопку Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось открыть порт"; //вывести сообщение в строке состояния return; }
//инициализация порта
dcb.DCBlength = sizeof(DCB); //в первое поле структуры DCB необходимо занести её длину, она будет использоваться функциями настройки порта для контроля корректности структуры
//считать структуру DCB из порта if(!GetCommState(COMport, &dcb)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { COMClose(); Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось считать DCB"; return; }
//инициализация структуры DCB dcb.BaudRate = StrToInt(Form1->ComboBox2->Text); //задаём скорость передачи 115200 бод dcb.fBinary = TRUE; //включаем двоичный режим обмена dcb.fOutxCtsFlow = FALSE; //выключаем режим слежения за сигналом CTS dcb.fOutxDsrFlow = FALSE; //выключаем режим слежения за сигналом DSR dcb.fDtrControl = DTR_CONTROL_DISABLE; //отключаем использование линии DTR dcb.fDsrSensitivity = FALSE; //отключаем восприимчивость драйвера к состоянию линии DSR dcb.fNull = FALSE; //разрешить приём нулевых байтов dcb.fRtsControl = RTS_CONTROL_DISABLE; //отключаем использование линии RTS dcb.fAbortOnError = FALSE; //отключаем остановку всех операций чтения/записи при ошибке dcb.ByteSize = 8; //задаём 8 бит в байте dcb.Parity = 0; //отключаем проверку чётности dcb.StopBits = 0; //задаём один стоп-бит
//загрузить структуру DCB в порт if(!SetCommState(COMport, &dcb)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { COMClose(); Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось установить DCB"; return; }
//установить таймауты timeouts.ReadIntervalTimeout = 0; //таймаут между двумя символами timeouts.ReadTotalTimeoutMultiplier = 0; //общий таймаут операции чтения timeouts.ReadTotalTimeoutConstant = 0; //константа для общего таймаута операции чтения timeouts.WriteTotalTimeoutMultiplier = 0; //общий таймаут операции записи timeouts.WriteTotalTimeoutConstant = 0; //константа для общего таймаута операции записи
//записать структуру таймаутов в порт if(!SetCommTimeouts(COMport, &timeouts)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { COMClose(); Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось установить тайм-ауты"; return; }
//установить размеры очередей приёма и передачи SetupComm(COMport,2000,2000);
//создать или открыть существующий файл для записи принимаемых данных handle = open("test.txt", O_CREAT | O_APPEND | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE);
if(handle==-1) //если произошла ошибка открытия файла { Form1->StatusBar1->Panels->Items[1]->Text = "Ошибка открытия файла"; //вывести сообщение об этом в командной строке Form1->Label6->Hide(); //спрятать надпись с именем файла Form1->CheckBox3->Checked = false; //сбросить и отключить галочку Form1->CheckBox3->Enabled = false; } else { Form1->StatusBar1->Panels->Items[0]->Text = "Файл открыт успешно"; } //иначе вывести в строке состояния сообщение об успешном открытии файла
PurgeComm(COMport, PURGE_RXCLEAR); //очистить принимающий буфер порта
reader = new ReadThread(false); //создать и запустить поток чтения байтов reader->FreeOnTerminate = true; //установить это свойство потока, чтобы он автоматически уничтожался после завершения
}
//---------------------------------------------------------------------------
//функция закрытия порта void COMClose() { if(writer)writer->Terminate(); //если поток записи работает, завершить его; if(reader)reader->Terminate(); //если поток чтения работает, завершить его; CloseHandle(COMport); //закрыть порт COMport=0; //обнулить переменную для дескриптора порта close(handle); //закрыть файл для записи принимаемых данных handle=0; //обнулить переменную для дескриптора файла }
//---------------------------------------------------------------------------
|