//--------------------------------------------------------------------------- //#pragma hdrstop //#include "stdafx.h" //--------------------------------------------------------------------------- #include "ComPort.h" #include #include #if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) //#define WIN32_LEAN_AND_MEAN //По моему это для выбора функции поиска файлов по умолчанию //#define NOMINMAX #include //#include #include //#include #else #include // standard input / output functions #include // string function definitions #include // UNIX standard function definitions #include // File control definitions #include // Error number definitions #include // POSIX terminal control definitionss #include // time calls #endif //#include #include //--------------------------------------------------------------------------- #if defined( _BORLAND ) #pragma package(smart_init) #endif //--------------------------------------------------------------------------- /*template std::string toString2(T val) { std::ostringstream oss; oss << val; return oss.str(); }*/ //--------------------------------------------------------------------------- /*std::string getComName(int num) { // if(num<10) return "COM"+IntToStr(num); // else return "\\\\.\\COM"+toString2(num); }*/ //------------------------------------------------------------------------------ ComPort::ComPort() { //m_time=0; hCom=0; ComNumber=1; BaudRate=115200; bOpen=false; } //------------------------------------------------------------------------------ ComPort::~ComPort() { Close(); } //------------------------------------------------------------------------------ void ComPort::CheckBaudRate() { if(BaudRate==0) BaudRate=1200; if(BaudRate==1) BaudRate=2400; if(BaudRate==2) BaudRate=4800; if(BaudRate==3) BaudRate=9600; if(BaudRate==4) BaudRate=19200; if(BaudRate==5) BaudRate=38400; if(BaudRate==6) BaudRate=57600; if(BaudRate==7) BaudRate=115200; } //------------------------------------------------------------------------------ bool ComPort::Open(std::string ComNumber) { if(hCom!=0) Close(); //Если открыт ком порт закроем #if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) this->ComNumber=ComNumber; std::string port="\\\\.\\COM"; port+=ComNumber; hCom = CreateFileA( port.c_str(), GENERIC_READ | GENERIC_WRITE, // Доступ для чтения и записи 0, // Без совместного использования NULL, // Без защиты OPEN_EXISTING, // Только если существует FILE_ATTRIBUTE_NORMAL, // Без дополнительных атрибутов NULL // Без шаблона файла ); if(hCom == INVALID_HANDLE_VALUE) bOpen=false; else bOpen=true; #else hCom = open(ComNumber.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); if(hCom== -1) { //printf("Unable to open /dev/ttyS0. \n"); std::cout << "Unable to open " << ComNumber << std::endl; bOpen=false; }else { fcntl(hCom, F_SETFL, 0); //printf("port is open.\n"); bOpen=true; } #endif return bOpen; } //------------------------------------------------------------------------------ bool ComPort::Open(std::wstring ComNumber) { std::string str( ComNumber.begin(), ComNumber.end() ); return Open(str); } //------------------------------------------------------------------------------ bool ComPort::Close() { bool result=true; #if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) if(bOpen){ if(CloseHandle(hCom)) { hCom=0; bOpen=false; } } #else if(close(hCom) == -1) { hCom=0; result=false; }else { hCom=0; bOpen=false; result=true; } #endif return result; } //------------------------------------------------------------------------------ bool ComPort::SetupDCB(int BaudRate,int ByteSize) { this->BaudRate = BaudRate; CheckBaudRate(); //из 1,2,3... в 1200,2400,4800... #if defined(WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) int RxBufferSize = 2048; int TxBufferSize = 2048; if (!SetupComm(hCom, RxBufferSize, TxBufferSize)) return false; DCB dcb; //Описание в https://ru.wikibooks.org/wiki/COM-порт_в_Windows_(программирование) memset((void *)&dcb, (int)0, (size_t)sizeof(dcb)); dcb.DCBlength = sizeof(DCB); if(!GetCommState(hCom, &dcb)){ //Берём текущие настройки из винды return false; } dcb.BaudRate = BaudRate; dcb.ByteSize = ByteSize; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fAbortOnError = FALSE; // Задает игнорирование всех операций чтения/записи при возникновении ошибки. Если это поле равно TRUE, драйвер прекращает все операции чтения/записи для порта при возникновении ошибки. Продолжать работать с портом можно будет только после устранения причины ошибки и вызова функции ClearCommError. dcb.fDtrControl = DTR_CONTROL_ENABLE; // Задает режим управления обменом для сигнала DTR. dcb.fRtsControl = RTS_CONTROL_ENABLE; // Задает режим управления потоком для сигнала RTS dcb.fBinary = TRUE; // Win32 не поддерживает недвоичный режим, поэтому данное поле всегда должно быть равно 1 dcb.fParity = FALSE; // Включает режим контроля четности. Если это поле равно TRUE, то выполняется проверка четности, при ошибке, в вызывающую программу, выдается соответствующий код завершения. dcb.fInX = FALSE; // Задает использование XON/XOFF управления потоком при приеме. Если это поле равно TRUE, то драйвер передает символ XoffChar, когда в приемном буфере находится более XoffLim, и XonChar, когда в приемном буфере остается менее XonLim символов. dcb.fOutX = FALSE; // Задает использование XON/XOFF управления потоком при передаче. Если это поле равно TRUE, то передача останавливается при приеме символа XoffChar, и возобновляется при приеме символа XonChar dcb.XonChar = 0; // Tx and Rx XON character dcb.XoffChar = (unsigned char)0xFF; // Tx and Rx XOFF character dcb.fErrorChar = FALSE; // error replacement character dcb.fNull = FALSE; //Определяет действие выполняемое при приеме нулевого байта. Если это поле TRUE, то нулевые байты отбрасываются при передаче. dcb.fOutxCtsFlow = FALSE; //Включает режим слежения за сигналом [[|CTS]]. Если это поле равно [[|TRUE]] и сигнал [[|CTS]] сброшен, передача данных приостанавливается до установки сигнала CTS. Это позволяет подключеному к компьютеру прибору приостановить поток передаваемой в него информации, если он не успевает ее обрабатывать. dcb.fOutxDsrFlow = FALSE; //Включает режим слежения за сигналом [[|DSR]]. Если это поле равно TRUE и сигнал DSR сброшен, передача данных прекращается до установки сигнала DSR. dcb.XonLim = 128; //Задает минимальное число символов в приемном буфере перед посылкой символа XON. dcb.XoffLim = 128; //Определяет максимальное количество байт в приемном буфере перед посылкой символа XOFF. Максимально допустимое количество байт в буфере вычисляется вычитанием данного значения из размера приемного буфера в байтах. if(!SetCommState(hCom, &dcb)) return false; #else #endif return true; } //------------------------------------------------------------------------------ //num - номер настроек под разное оборудование (num=1 то атоловские настройки для ком порта) bool ComPort::Setup(int num) { CheckBaudRate(); //из 1,2,3... в 1200,2400,4800... #if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) int RxBufferSize = 2048; int TxBufferSize = 2048; if(!SetupComm(hCom, RxBufferSize, TxBufferSize)) return false; DCB dcb; memset(&dcb,0,sizeof(dcb)); dcb.DCBlength = sizeof (DCB); GetCommState(hCom,&dcb); //Берём текущие настройки из винды dcb.BaudRate=BaudRate; if(num==-1) //Настройки для Фрезерного станка с ЧПУ { dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fAbortOnError = TRUE; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fBinary = TRUE; dcb.fParity = FALSE; dcb.fInX = FALSE; dcb.fOutX = FALSE; dcb.XonChar = 0; dcb.XoffChar = (unsigned char)0xFF; dcb.fErrorChar = FALSE; dcb.fNull = FALSE; //Определяет действие выполняемое при приеме нулевого байта. Если это поле TRUE, то нулевые байты отбрасываются при передаче. dcb.fOutxCtsFlow = FALSE; //Включает режим слежения за сигналом [[|CTS]]. Если это поле равно [[|TRUE]] и сигнал [[|CTS]] сброшен, передача данных приостанавливается до установки сигнала CTS. Это позволяет подключеному к компьютеру прибору приостановить поток передаваемой в него информации, если он не успевает ее обрабатывать. dcb.fOutxDsrFlow = FALSE; //Включает режим слежения за сигналом [[|DSR]]. Если это поле равно TRUE и сигнал DSR сброшен, передача данных прекращается до установки сигнала DSR. dcb.XonLim = 128; //Задает минимальное число символов в приемном буфере перед посылкой символа XON. dcb.XoffLim = 128; //Определяет максимальное количество байт в приемном буфере перед посылкой символа XOFF. Максимально допустимое количество байт в буфере вычисляется вычитанием данного значения из размера приемного буфера в байтах. } else if(num==0) //Настройки для ПОРТ 300 100 { //if(!GetCommState(hCom, &dcb)) return false; dcb.fBinary=1; //dcb.fDtrControl=DTR_CONTROL_ENABLE; //Без этого 0x03 не принималось с принтера а потом начала принимать и без... dcb.fRtsControl=RTS_CONTROL_ENABLE; dcb.XonLim=2048; dcb.XoffLim=512; dcb.ByteSize=8; dcb.XonChar=17; dcb.XoffChar=19; }else if(num==1) //Настройки для Аура-01ФР-KZ { dcb.DCBlength = sizeof (DCB); dcb.fBinary=1; dcb.XonLim=2048; dcb.XoffLim=512; dcb.ByteSize=8; dcb.XonChar=17; dcb.XoffChar=19; }else if(num==2) //Настройки для CashCode { //if(!GetCommState(hCom, &dcb)) return false; dcb.ByteSize=8; dcb.Parity=NOPARITY; dcb.StopBits=ONESTOPBIT; dcb.fDtrControl=DTR_CONTROL_ENABLE; }else if(num==3) //Настройки для дисплея покупателя WINCOR NIXDORF { dcb.ByteSize=8; dcb.fBinary=1; //Проверка чётности dcb.fParity=TRUE; dcb.Parity=ODDPARITY; dcb.StopBits=ONESTOPBIT; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fDtrControl = DTR_CONTROL_DISABLE; //dcb.fDtrControl=DTR_CONTROL_ENABLE; }else //Свои настройки { if(!GetCommState(hCom, &dcb)) return false; //Берём текущие настройки dcb.fBinary = TRUE; // В винде только двоичный режим всегда 1 dcb.fParity = TRUE; // Если этот член структуры - ИСТИНА (TRUE), выполняется проверка четности и сообщается об ошибках... dcb.ByteSize = 8; // Number of bits/byte, 4-8 dcb.Parity = NOPARITY; // Используемая схема четности. (EVENPARITY Проверка по четности MARKPARITY Проверка четности по метке NOPARITY Без проверки четности ODDPARITY Проверка по нечетности SPACEPARITY Проверка четности по паузе) dcb.fTXContinueOnXoff = FALSE; // Если FALSE то будет следить за переполнением принимающего буфера. dcb.fNull = TRUE; dcb.StopBits = ONESTOPBIT; /*EFlowControl fc; switch (fc) { case ENoFlowControl: // No HandShaking { dcb.fOutxCtsFlow = FALSE; // Disable CTS(Clear To Send) monitoring dcb.fOutxDsrFlow = FALSE; // Disable DSR(Data Set Ready) monitoring dcb.fDtrControl = DTR_CONTROL_DISABLE; //Сигнал DTR (готовности терминала к передаче данных) управления потоком данных. Этот член структуры может быть одним из следующих значений. //DTR_CONTROL_ENABLE Включает линию DTR, когда устройство открывается и оставляет ее включенной. //DTR_CONTROL_HANDSHAKE Отключает линию DTR, когда устройство открывается и оставляет ее заблокированной. //DTR_CONTROL_DISABLE Включает процедуру установления связи DTR. Если процедура установления связи включена, она является ошибкой для приложения, которое корректировать линию, используя функцию EscapeCommFunction. dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send) monitoring dcb.fOutX = FALSE; // Disable XON/XOFF for transmission (Управление потоком (это своойство есть в гипертерминале)) dcb.fInX = FALSE; // Disable XON/XOFF for receiving break; } case EXonXoffFlowControl: // Software Handshaking { dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fOutX = TRUE; dcb.fInX = TRUE; dcb.XonChar = 0x11; dcb.XoffChar = 0x13; dcb.XoffLim = 100; dcb.XonLim = 100; break; } case EFullHardwareFlowControl: // Hardware Handshaking {*/ dcb.fOutxCtsFlow = TRUE; dcb.fOutxDsrFlow = TRUE; dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fOutX = FALSE; dcb.fInX = FALSE; /*} case ECtsRtsFlowControl: { dcb.fOutxCtsFlow = TRUE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case ECtsDtrFlowControl: { dcb.fOutxCtsFlow = TRUE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case EDsrRtsFlowControl: { dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = TRUE; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case EDsrDtrFlowControl: { dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = TRUE; dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } default: { RETAILMSG(1,(_T("CSerial::Setup - %s flow control assigned Failed!!"), sPort)); return; } }*/ } if(!SetCommState(hCom, &dcb)) return false; #else int result=-1; struct termios tty; // structure to store the port settings in memset (&tty, 0, sizeof tty); if (tcgetattr (hCom, &tty) != 0) { std::cout << "Error read serial port config." << std::endl; return false; } switch(BaudRate) { case 1200: result = cfsetospeed(&tty, B1200); break; case 1800: result = cfsetospeed(&tty, B1800); break; case 2400: result = cfsetospeed(&tty, B2400); break; case 4800: result = cfsetospeed(&tty, B4800); break; case 9600: result = cfsetospeed(&tty, B9600); break; case 19200: result = cfsetospeed(&tty, B19200); break; case 38400: result = cfsetospeed(&tty, B38400); break; case 57600: result = cfsetospeed(&tty, B57600); break; case 115200: result = cfsetospeed(&tty, B115200); break; default: cfsetospeed(&tty, BaudRate); } if(result == -1) { std::cout << "Error set baud rate \"" << BaudRate << "\"." << std::endl; } if(num==0) //Настройки для ПОРТ 300 100 { //Отключаю "канонический" режим те. возможность редактирования в буфере до получения символа /r или /n tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*tty.c_lflag &= ~ICANON; // Don't canonicalise tty.c_lflag &= ~ECHO; // Don't echo tty.c_lflag &= ~ECHOK; // Don't echo tty.c_lflag &= ~ECHOE;*/ //Similarly, to disable hardware flow control: //tty.c_cflag &= ~CNEW_RTSCTS; // set no parity, stop bits, data bits tty.c_cflag &= ~PARENB; tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CSIZE; tty.c_cflag |= CS8; //Размер байта /* tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars // disable IGNBRK for mismatched speed tests; otherwise receive break // as \000 chars tty.c_iflag &= ~IGNBRK; // disable break processing tty.c_lflag = 0; // no signaling chars, no echo, // no canonical processing tty.c_oflag = 0; // no remapping, no delays tty.c_cc[VMIN] = 0; // read doesn't block tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, // enable reading tty.c_cflag &= ~(PARENB | PARODD); // shut off parity tty.c_cflag |= 0; //parity; no parity tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CRTSCTS; */ } if(tcsetattr(hCom, TCSANOW, &tty) != 0) { std::cout << "Error set attributes." << std::endl; return -1; } #endif return true; } //------------------------------------------------------------------------------ //Если time=0 то не ждет данные и с разу выдает все что в буфере //Если задать миллисекунды то это время доожидания следующего байта (не ставить меньше 10 миллисекунд) //Операция чтения работает асинхронно те. не ждёт данные за временем нужно следить самому ! (читать байты в цикле с задержкой) //Подробное оисание: http://www.vsokovikov.narod.ru/New_MSDN_API/Comm_res/str_commtimeouts.htm //time - время в миллисекундах (не ставить меньше 10 миллисекунд) bool ComPort::SetTimeout(unsigned long time) { #if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) COMMTIMEOUTS CommTimeouts; CommTimeouts.ReadIntervalTimeout = time; //Максимальное время, которое допускается для интервала между поступлением двух символов в миллисекундах (отсчёт после первого символа) CommTimeouts.ReadTotalTimeoutMultiplier = 0; //Множитель умножается на число проч. байтов получаются милисекунды которые прибовляются к нижнему CommTimeouts.ReadTotalTimeoutConstant = time; //Это время простоя прибавляется к (ReadTotalTimeoutMultiplier * кол-во прочитанных байт) CommTimeouts.WriteTotalTimeoutMultiplier = 0; //Множитель умножается на число зап. байтов получаются милисекунды которые прибовляются к нижнему CommTimeouts.WriteTotalTimeoutConstant = 0; //Это время простоя для записи прибавляется к (WriteTotalTimeoutMultiplier * кол-во записанных байт) /* CommTimeouts.ReadIntervalTimeout = MAXDWORD; //Максимальное время, которое допускается для интервала между поступлением двух символов CommTimeouts.ReadTotalTimeoutMultiplier = 0; //Множитель умножается на число проч. байтов получаются милисекунды которые прибовляются к нижнему CommTimeouts.ReadTotalTimeoutConstant = time; //Это время простоя прибавляется к (ReadTotalTimeoutMultiplier * кол-во прочитанных байт) CommTimeouts.WriteTotalTimeoutMultiplier = 0; //Множитель умножается на число зап. байтов получаются милисекунды которые прибовляются к нижнему CommTimeouts.WriteTotalTimeoutConstant = time; //Это время простоя для записи прибавляется к (WriteTotalTimeoutMultiplier * кол-во записанных байт) */ return SetCommTimeouts(hCom, &CommTimeouts)!=0; //В MSDN так написанно #else struct termios termios; tcgetattr(hCom, &termios); termios.c_cc[VMIN] = 0; //Не учитываем кол-во байт а только время termios.c_cc[VTIME] = time/10.0f; //Время в 0.1 секунду поэтому разделил на 10 tcsetattr(hCom, TCSANOW, &termios); #endif return true; } //------------------------------------------------------------------------------ //Записать буфер в COM порт unsigned long ComPort::Write(const void* lpBuffer,unsigned long nNumberOfBytesToWrite) { if (nNumberOfBytesToWrite == 0) return 0; //А то через блютуз подвисало unsigned long lpNumberOfBytesWritten=0; #if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) WriteFile(hCom, lpBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL); #else lpNumberOfBytesWritten = write(hCom,lpBuffer,nNumberOfBytesToWrite); #endif return lpNumberOfBytesWritten; } //------------------------------------------------------------------------------ //Записать строку в COM порт unsigned long ComPort::WriteString(std::string str) { return Write(str.c_str(),str.length()); } //------------------------------------------------------------------------------ //Записать 1 байт в COM порт unsigned char ComPort::WriteChar(signed char ch) { return (unsigned char)Write(&ch,1); } //------------------------------------------------------------------------------ unsigned char ComPort::WriteUChar(unsigned char ch) { return (unsigned char)Write(&ch,1); } //------------------------------------------------------------------------------ unsigned char ComPort::WriteUInt(unsigned int val) { return (unsigned char)Write(&val,4); } //------------------------------------------------------------------------------ //Прочитать байты из COM порта в буфер int ComPort::Read(void* lpBuffer,unsigned long nNumberOfBytesToRead) { int result=0; if (nNumberOfBytesToRead == 0) return 0; #if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__) unsigned long lpNumberOfBytesRead; BOOL error = ReadFile(hCom, lpBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL); if (!error) { result=-1; // Указание на ошибку }else{ result = lpNumberOfBytesRead; } #else result = read(hCom, lpBuffer, nNumberOfBytesToRead); #endif return result; } //------------------------------------------------------------------------------ //Так как может выдавать данные порциями int ComPort::ReadAll(void* lpBuffer, unsigned long nNumberOfBytesToRead) { if (nNumberOfBytesToRead == 0) return 0; DWORD len=0; int pos = 0; while (true) { ReadFile(hCom, lpBuffer, nNumberOfBytesToRead, &len, NULL); if (len <= 0) break; pos += len; nNumberOfBytesToRead -= len; if (nNumberOfBytesToRead == 0) break; } return pos; } //------------------------------------------------------------------------------ //Читать до символа и этот символ в результат не входит int ComPort::ReadUntilChar(void* lpBuffer, unsigned long maxLen, char suffix,bool* error){ *error=true; if(maxLen == 0) return 0; unsigned long pos=0; char ch; while (true) { if(Read(&ch, 1)!=1){ break; }else{ if(ch==suffix){ *error=false; break; } ((char*)lpBuffer)[pos]=ch; pos++; if(maxLen==pos){ break; } } } return pos; } //------------------------------------------------------------------------------ //Прочитать байт из ком порта unsigned char ComPort::ReadUInt1(bool* b) { unsigned char result=0; if(Read(&result, 1)!=1) *b=false; else *b=true; return result; } //------------------------------------------------------------------------------