Можно ли как-нибудь убрать Sleep в чтении/записи COM порта
Скажите, можно ли в указанном коде ниже, убрать Sleep в WorkWithComPort, или хотя свести к минимуму
временные задержки? Так-все работает, но если поставить Sleep(1) или вообще убрать, код не успевает, читать/писать, хотя вроде бы overlapped
настроена. Спасибо за комментарии.
*********************************************
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <time.h>
#define SLEEP 20 //ms
#define MEMORYPAGE_MAX 4032
#define COM_NUMBER 7
#define rNumOfRealTimeTransaction 429
#define rNumOfMemoryPageTransaction 430
#define rStatusMemory 431
#define rTime 427
#define rData 426
#define rSerialNumber 420
#define R_01 13
#define R_02 516
HANDLE thread_handle = INVALID_HANDLE_VALUE;
BOOL time_to_quit = FALSE;
OVERLAPPED overlapped; //будем использовать для операций чтения (см. поток ReadThread)
HANDLE reader; //дескриптор потока чтения из порта
#define BUFSIZE 8192 //ёмкость буфера
unsigned long counter; //счётчик принятых байтов, обнуляется при каждом открытии порта
unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE]; //приёмный и передающий буферы
int MaxPage = 0;
char NewMessage = false;
bool IsBusy = false;
bool IsRead = false;
#define ACC 0.015625
#define ANGLECC 0.0152587890625
unsigned long page = 1; //начальная страница памяти
//объявим структуру для асинхронной работы порта
OVERLAPPED over;
//для выделения сигнала
DWORD dwSignal;
//объявим структуру для конфигурации СОМ порта
DCB dcb;
//дескриптор порта
HANDLE hPortDat = NULL;
//переменная для чтения
char Data;
bool COMOPEN = false;
bool Terminated = false;
bool IsMemoryRead = false;
CRITICAL_SECTION m_crisec; // Критическая секция
int ReadFlag = 0; //начальное значение
int Incomplete = 1; //полностью прочитанное состояние
int CounterByte = 0; //счетчик байт
bool IsFirstRead = false; //первый раз чтение
bool ReadBusy = false;
struct MESSAGE
{
unsigned char EventNumber[4];
float AccelerationX;
float AccelerationY;
float AccelerationZ;
float ASpeedX;
float ASpeedY;
float ASpeedZ;
};
struct DATA
{
unsigned char Marker;
unsigned char OperationType;
unsigned short NetworkAddress;
unsigned short Register;
unsigned short Data[4];
unsigned short crc;
};
DATA out={0};
//расчет crc3
DWORD crc_cycle3(unsigned char*BuffSend,int len)
{
if (!BuffSend) return 0;
int i=0,j=0;
DWORD CRC32;
CRC32 = 0xFFFFFFFF;
for (j= 0; j < (len / 4); j++)
{
CRC32 = CRC32 ^ (BuffSend[j*4+0]*1+BuffSend[j*4+1]*0x100+BuffSend[j*4+2]*0x10000+BuffSend[j*4+3]*0x10000*0x100);
for (i= 0; i <32;i++)
{
if (!((CRC32 & 0x80000000)==0))
CRC32 = (CRC32 * 2) ^ 0x04C11DB7;
else
CRC32 = (CRC32 * 2);
}
}
if ((len-(len / 4) *4)>0)
{
if ((len-(len / 4) *4)==1) CRC32 = CRC32 ^ BuffSend[j*4+0];
if ((len-(len / 4) *4)==2) CRC32 = CRC32 ^ (BuffSend[j*4+0]*1+BuffSend[j*4+1]*0x100);
if ((len-(len / 4) *4)==3) CRC32 = CRC32 ^ (BuffSend[j*4+0]*1+BuffSend[j*4+1]*256+BuffSend[j*4+2]*0x10000);
for (i= 0; i < 32; i++)
if (!((CRC32 & 0x80000000)==0))
CRC32 = (CRC32 * 2) ^ 0x04C11DB7;
else
CRC32 = (CRC32 * 2);
}
return CRC32;
}
BOOL WriteABuffer(unsigned char * lpBuf, DWORD dwToWrite)
{
// OVERLAPPED over = {0};
if (IsRead) return false;
DWORD dwRes=0;
BOOL fRes = FALSE;
DWORD dwWritten=0;
if (!hPortDat) return FALSE;
// Create this write operation's OVERLAPPED structure hEvent.
over.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (over.hEvent == NULL)
// Error creating overlapped event handle.
return FALSE;
// Issue write
if (!WriteFile(hPortDat, lpBuf, dwToWrite, &dwWritten, &over))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// WriteFile failed, but it isn't delayed. Report error.
fRes = FALSE;
}
else
// Write is pending.
dwRes = WaitForSingleObject(over.hEvent, INFINITE);
switch(dwRes)
{
// Overlapped event has been signaled.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hPortDat, &over, &dwWritten, FALSE))
fRes = FALSE;
else
{
if (dwWritten != dwToWrite)
{
// The write operation timed out. I now need to
// decide if I want to abort or retry. If I retry,
// I need to send only the bytes that weren't sent.
// If I want to abort, I would just set fRes to
// FALSE and return.
fRes = FALSE;
}
else
{
// Write operation completed successfully.
fRes = TRUE;
}
}
break;
default:
// An error has occurred in WaitForSingleObject. This usually
// indicates a problem with the overlapped event handle.
fRes = FALSE;
break;
}
}
else
{
// WriteFile completed immediately.
if (dwWritten != dwToWrite)
{
// The write operation timed out. I now need to
// decide if I want to abort or retry. If I retry,
// I need to send only the bytes that weren't sent.
// If I want to abort, then I would just set fRes to
// FALSE and return.
fRes = FALSE;
}
else
{
fRes = TRUE;
}
}
CloseHandle(over.hEvent);
return fRes;
}
//читаем регистр
bool ReadRegister(unsigned short reg)
{
unsigned char Buff[13]={0};
char a=0;
DWORD crc=0;
Buff[0]=0x46;
Buff[1]=0x00;//$00 - read
Buff[2]=0x00;//address H
Buff[3]=0x00;//address L
Buff[5]=reg-(reg / 256)*256;//register H
Buff[4]=reg / 256;//register L
Buff[6]=0x0;//data L(1)
Buff[7]=0x0;//data (2)
Buff[8]=0x0;//data (3)
Buff[9]=0x0;//data H(4)
Buff[10]=0x00;//CRC H
Buff[11]=0x00;//CRC L
Buff[12]=0x0D;
unsigned char BuffSend[13];
for (a = 0; a < 13; a++)
BuffSend[a]=Buff[a];
crc = crc_cycle3(BuffSend,10);
Buff[11]=BYTE(crc);
Buff[10]=unsigned char(crc / 256);
BuffSend[11]=unsigned char(crc);
BuffSend[10]=unsigned char(crc / 256);
if (WriteABuffer(Buff,sizeof(Buff)))
{
return true;
}
return false;
}
//запись регистра
bool WriteRegister(unsigned short reg,unsigned char data1, unsigned char data2,
unsigned char data3,unsigned char data4)
{
unsigned char Buff[13]={0};
char a=0;
DWORD crc=0;
Buff[0]=0x46;
Buff[1]=0x04;//$04 - write
Buff[2]=0x00;//address H
Buff[3]=0x00;//address L
Buff[5]=reg-(reg / 256)*256;//register H
Buff[4]=reg / 256;//register L
Buff[6]=data1;//data L(1)
Buff[7]=data2;//data (2)
Buff[8]=data3;//data (3)
Buff[9]=data4;//data H(4)
Buff[10]=0x00;//CRC H
Buff[11]=0x00;//CRC L
Buff[12]=0x0D;
unsigned char BuffSend[13];
for (a = 0; a < 13; a++)
BuffSend[a]=Buff[a];
crc = crc_cycle3(BuffSend,10);
Buff[11]=BYTE(crc);
Buff[10]=unsigned char(crc / 256);
BuffSend[11]=unsigned char(crc);
BuffSend[10]=unsigned char(crc / 256);
if (WriteABuffer(Buff,sizeof(Buff)))
{
return true;
}
return false;
}
//пишим функцию инициализации порта
bool InitPort (unsigned char PORT)
{
//открываем порт СОМ 1
char v[10] = "\0";
sprintf(v,"COM%d",PORT);
hPortDat = CreateFile (v, GENERIC_READ|GENERIC_WRITE,
0,NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (hPortDat == INVALID_HANDLE_VALUE)//если порт не удалось открыть
{
CloseHandle (hPortDat);
return false;//выходим из функции с ошибкой
}
//настраиваем параметры порта
dcb.BaudRate = CBR_115200;//скорость передачи
dcb.ByteSize = 8;//размер передачи
dcb.StopBits = ONESTOPBIT;//один стоповый бит
dcb.Parity = NOPARITY;
//проверяем на правильность настройки
if ( !SetCommState ( hPortDat, &dcb)) //тоже не работает....
{
CloseHandle (hPortDat);
return false;//выходим из функции с ошибкой
}
COMMTIMEOUTS timeouts; //структура для установки таймаутов
//установить таймауты
timeouts.ReadIntervalTimeout = MAXDWORD; //таймаут между двумя символами
timeouts.ReadTotalTimeoutMultiplier = 0; //общий таймаут операции чтения
timeouts.ReadTotalTimeoutConstant = 0; //константа для общего таймаута операции чтения
timeouts.WriteTotalTimeoutMultiplier = 0; //общий таймаут операции записи
timeouts.WriteTotalTimeoutConstant = 0; //константа для общего таймаута операции записи
//записать структуру таймаутов в порт
//если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
if(!SetCommTimeouts(hPortDat, &timeouts))
{
CloseHandle (hPortDat);
return false;
}
//установить размеры очередей приёма и передачи
SetupComm(hPortDat,2000,2000);
PurgeComm(hPortDat, PURGE_RXCLEAR);
//очистить принимающий буфер порта
COMOPEN = true;
//если все выполнилось то возвращаем положительный результат
return true;
}
//работаем с COM портом
void WorkWithComPort()
{
while (!time_to_quit)
{
//читаем регистр
ReadFlag = 1;
if (ReadRegister(rStatusMemory))
{
printf(" %d %d ",out.Register,out.Data[0]);
Sleep(10);
}
if (ReadRegister(1))
{
printf(" %d %d ",out.Register,out.Data[0]);
Sleep(10);
}
}
}
DWORD WINAPI thread_func(LPVOID lpvd)
{
fprintf(stdout, "thread write running...\n");
WorkWithComPort();
return 0;
}
void cleanup()
{
//закрываем потоки
fprintf(stdout, "cleaning up...\n");
if (thread_handle)
{
CloseHandle(thread_handle);
thread_handle = NULL;
}
if (reader)
{
CloseHandle(reader);
reader = NULL;
}
// Удаляем критическую секцию
DeleteCriticalSection(&m_crisec);
if (hPortDat)
{
CloseHandle(hPortDat);
hPortDat = NULL;
}
}
//анализируем страницу памяти
void AnalyseMemoryPage(unsigned char* Buf,DWORD size)
{
if (size != R_02) return;
//первые 3 байта - маркеры
if (Buf[0] == 0xF0 && Buf[1] == 0xAA && Buf[2] == 0xFF)
{
printf("\nACK PACKET\n");
for (DWORD x = 0; x < size; x++)
printf("%.2X",Buf[x]);
MESSAGE page[32];
memset(page,0,sizeof(page));
for (char r = 0; r < 32; r++)
{
page[r].EventNumber[0] = Buf[3+(r*10)];
page[r].EventNumber[1] = Buf[4+(r*10)];
page[r].EventNumber[2] = Buf[5+(r*10)];
page[r].EventNumber[3] = Buf[6+(r*10)];
page[r].AccelerationX = (float)(Buf[7+(r*10)]*ACC);
page[r].AccelerationY = (float)(Buf[8+(r*10)]*ACC);
page[r].AccelerationZ = (float)(Buf[9+(r*10)]*ACC);
page[r].ASpeedX = (float)(Buf[10+(r*10)]*ANGLECC);
page[r].ASpeedY =(float)(Buf[11+(r*10)]*ANGLECC);
page[r].ASpeedZ = (float)(Buf[12+(r*10)]*ANGLECC);
}
}
}
//проверка прочитанного регистра
bool CheckReadRegister(unsigned char* Buf,DWORD size,DATA* data)
{
if (size != R_01 || !Buf) return false;
//проверка маркера
if (Buf[0] == 0x00) return false;
if (Buf[0] == 0x46 || Buf[0] == 0x31 || Buf[0] == 0x3E)
{
DWORD crc = crc_cycle3(Buf,10);
//пустой массив
if (crc == 0) return false;
unsigned short a1 = byte(crc);
unsigned short a2 = byte(crc / 0x100);
//crc проверен
if (a1 == Buf[10] && a2 == Buf[11])
{
//заполним память
if (data)
{
data->Marker = Buf[0];
data->OperationType = Buf[1];
data->NetworkAddress = MAKEWORD(Buf[3],Buf[2]);
data->Register = MAKEWORD(Buf[5],Buf[4]);
for (char e = 0; e < 4; e++)
data->Data[e] = Buf[6+e];
data->crc = MAKEWORD(Buf[11],Buf[10]);
//printf("\nPAGE = %d %X %X %X %X %d\n",page,Buf[6],Buf[7],Buf[8],Buf[9],(Buf[6] + Buf[7]*256));
}
return true;
}
else
return false;
}
return false;
}
//проверка прочитанной страницы памяти
bool CheckReadMemoryPage(unsigned char* Buf,DWORD size,DATA* data)
{
if (size != R_02 || !Buf) return false;
//проверка маркера
if (Buf[100] == 0x00 && Buf[101] == 0x00 && Buf[102] == 0x00)
return false;
if (Buf[0] == 0xF0 || Buf[1] == 0xAA || Buf[3] == 0xFF)
{
DWORD crc = crc_cycle3(Buf,R_02-1);
if (crc == 0) return false;
unsigned short a1 = LOBYTE(crc);
//crc проверен
if (a1 == Buf[R_02-1])
return true;
else
return false;
}
return false;
}
//парсируем буфер
void ParseBuf(unsigned char* Buf,DWORD size)
{
int kind = 0;
ReadBusy = true;
if (!Buf)
{
Incomplete = -1;
CounterByte = 0;
IsRead = false;
return;
}
if (size ==0)
{
CounterByte = 0;
Incomplete = 1;
IsRead = false;
return;
}
if (ReadFlag == 1)
kind = R_01;
if (ReadFlag == 2)
kind = R_02;
//проверка чтения
{
//данные прочитались полностью
if (size == kind)
{
Incomplete = 1;
CounterByte = 0;
//это - регистр
if (ReadFlag == 1)
if (CheckReadRegister(Buf,size,&out))
{
/*printf("\n");
for (DWORD x = 0; x < size; x++)
printf("%.2X",Buf[x]);
printf("\n");
*/
}
//это - энергонезависимая память
if (ReadFlag == 2)
{
if (CheckReadMemoryPage(bufwr,kind,NULL))
AnalyseMemoryPage(Buf,size);
}
memset(bufwr,0,sizeof(bufwr));
IsFirstRead = false;
}
//данные прочитались не полностью
else
if (size > kind)
{
Incomplete = 1;
CounterByte=0;
IsFirstRead = false;
}
else
if (size < kind)
{
Incomplete = 0;
//начинаем процесс дочитывания
if (!IsFirstRead)
{
memcpy(bufwr,Buf,size);
IsFirstRead = true;
}
//уже начат процесс дочитывания
else
{
//возьмем адрес массива
unsigned char *p = &bufwr[0];
//перескочем на CounterByte позиций
p+=CounterByte;
//скопируем хвост
memcpy(p,Buf,size);
}
CounterByte+=size;
//дочитывание завершено
if (CounterByte == kind)
{
Incomplete = 1;
CounterByte = 0;
//это - регистр
if (ReadFlag == 1)
if (CheckReadRegister(bufwr,kind,&out))
{
/*printf("\n");
for (DWORD x = 0; x < kind; x++)
printf("%.2X",bufwr[x]);
printf("\n");*/
}
//это - энергонезависимая память
if (ReadFlag == 2)
{
if (CheckReadMemoryPage(bufwr,kind,NULL))
AnalyseMemoryPage(bufwr,kind);
}
memset(bufwr,0,sizeof(bufwr));
IsFirstRead = false;
}
}
}
IsRead = false;
}
//главная функция потока, реализует приём байтов из COM-порта
DWORD WINAPI ReadThread(LPVOID)
{
fprintf(stdout, "thread write running...\n");
COMSTAT comstat; //структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
DWORD btr, temp, mask, signal; //переменная temp используется в качестве заглушки
overlapped.hEvent = CreateEvent(NULL, true, true, NULL); //создать сигнальный объект-событие для асинхронных операций
SetCommMask(hPortDat, EV_RXCHAR); //установить маску на срабатывание по событию приёма байта в порт
while(!Terminated) //пока поток не будет прерван, выполняем цикл
{
WaitCommEvent(hPortDat, &mask, &overlapped); //ожидать события приёма байта (это и есть перекрываемая операция)
signal = WaitForSingleObject(overlapped.hEvent, INFINITE); //приостановить поток до прихода байта
if(signal == WAIT_OBJECT_0) //если событие прихода байта произошло
{
if(GetOverlappedResult(hPortDat, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
if((mask & EV_RXCHAR)!=0) //если произошло именно событие прихода байта
{
ClearCommError(hPortDat, &temp, &comstat); //нужно заполнить структуру COMSTAT
btr = comstat.cbInQue; //и получить из неё количество принятых байтов
{
ReadFile(hPortDat, bufrd, btr, &temp, &overlapped);
ParseBuf(bufrd,temp);
CancelIo(hPortDat);
//вызываем функцию для вывода данных на экран и в файл
}
}
}
}
CloseHandle(overlapped.hEvent); //перед выходом из потока закрыть объект-событие
return TRUE;
}
int main()
{
DWORD thread_id = 0;
bool k = InitPort(COM_NUMBER);
if (k)
{
thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, NULL, 0, &thread_id);
if (thread_handle != NULL)
{
fprintf(stdout, "thread write created...\n");
//WaitForSingleObject(thread_handle, INFINITE);
}
// Инициализируем критическую секцию
InitializeCriticalSection(&m_crisec);
//создаём поток чтения, который сразу начнёт выполняться (предпоследний параметр = 0)
reader = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL);
if (reader != NULL)
{
fprintf(stdout, "thread read created...\n");
WaitForSingleObject(thread_handle, INFINITE);
}
}
cleanup();
return 0;
}
Можно.