Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 26.07.2012, 10:54   #1
bedouin
Пользователь
 
Регистрация: 05.01.2012
Сообщений: 27
По умолчанию Сохранение данных COM-порта в несколько файлов

Добрый день всем!
Возник вот какой вопрос:
У меня есть входной поток с СОМ-порта. Данные записываются в файл.
Но так как считывание происходит непрерывно, в течение длительного времени (до нескольких дней), то приемный файл сильно "разбухает".
Все, что встречал в нете, связано с сохранением в один и тот же файл.
А кому-нибудь приходилось сохранять данные в различные файлы?

P.S.: Мне подобную циклическую запись удалось реализовать только для синхронного режима чтения СОМ-порта (по достижении заданного объема текущий файл закрывался и запись начинала вестись в новый файл).
Но это тупиковый путь, т.к. "поедается" много системных ресурсов и программа работает нестабильно.
Может кто-то делал подобное для асинхронного режима?
bedouin вне форума Ответить с цитированием
Старый 26.07.2012, 12:42   #2
raxp
Старожил
 
Регистрация: 29.09.2009
Сообщений: 9,713
По умолчанию

...решается очень просто формированием имени файла из даты-года текущего, к примеру 10-08-2012.txt, 11-08-2012.txt, ... . К тому же, так удобнее просматривать потом логи.
Разработки и научно-технические публикации :: Видеоблог :: Твиттер
Radar systems engineer & Software developer of industrial automation
raxp вне форума Ответить с цитированием
Старый 26.07.2012, 13:30   #3
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

В чем проблема с асинхронным чтением? Все равно данные приходят сначала к вам, потом идут в файл, не зависимо синхронно или нет. Что мешает проверить не нужно ли менять файл?

А с чего вы взяли, что при синхронном режиме поедаются много ресурсов? Ничего подобного.
waleri вне форума Ответить с цитированием
Старый 30.07.2012, 23:18   #4
bedouin
Пользователь
 
Регистрация: 05.01.2012
Сообщений: 27
По умолчанию

to waleri
Проблема в том, что наиболее часто асинхронный режим чтения рекомендуют организовывать при помощи потоков, как, например, здесь:
http://www.piclist.ru/S-COM-THREAD-R...HREAD-RUS.html
Я открываю порт
Код:
void CReadDataDlg::COMOpen(void)
{
 char sPortName[10];    	 //имя порта (например, "COM1", "COM2" и т.д.)
 DCB dcb;                //структура для общей инициализации порта DCB
 COMMTIMEOUTS timeouts;  //структура для установки таймаутов
 
  cbPorts.GetWindowText(sPortName, 10); cbPorts.GetWindowText(sPortName, 10);	//получить имя выбранного порта

 //открыть порт, для асинхронных операций обязательно нужно указать флаг FILE_FLAG_OVERLAPPED
 COMport = CreateFile(sPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);


	if (COMport == INVALID_HANDLE_VALUE) 
	{	
		lLogList.AddString("Ошибка при открытии СОМ-порта");
	}
	else  
	{
		lLogList.AddString("СОМ-порт успешно открыт");

		DCB dcb;
		GetCommState(COMport, &dcb);
		dcb.BaudRate = CBR_19200;
		dcb.ByteSize = 8;
		dcb.Parity = NOPARITY;
		dcb.StopBits = ONESTOPBIT; 
		if (SetCommState(COMport, &dcb))
		{
		lLogList.AddString("Настройка СОМ-порта выполнена успешно");
		
		}
		else
			lLogList.AddString("Ошибка в настройке СОМ-порта");
	}
Создаю поток
Код:
DWORD WINAPI ReadThread(LPVOID)
{
 COMSTAT comstat;		//структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
 DWORD btr, mask, temp, signal;	//переменная temp используется в качестве заглушки

 overlapped.hEvent = CreateEvent(NULL, true, true, NULL);	//создать сигнальный объект-событие для асинхронных операций
 SetCommMask(COMport, EV_RXCHAR);                   	        //установить маску на срабатывание по событию приёма байта в порт
 while(1)						//пока поток не будет прерван, выполняем цикл
  {
   WaitCommEvent(COMport, &mask, &overlapped);               	//ожидать события приёма байта (это и есть перекрываемая операция)
   signal = WaitForSingleObject(overlapped.hEvent, INFINITE);	//приостановить поток до прихода байта
   if(signal == WAIT_OBJECT_0)				        //если событие прихода байта произошло
    {
     if(GetOverlappedResult(COMport, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
      if((mask & EV_RXCHAR)!=0)					//если произошло именно событие прихода байта
       {
        ClearCommError(COMport, &temp, &comstat);		//нужно заполнить структуру COMSTAT
        btr = comstat.cbInQue;                          	//и получить из неё количество принятых байтов
        if(btr)                         			//если действительно есть байты для чтения
        {
         ReadFile(COMport, bufrd, btr, &temp, &overlapped);     //прочитать байты из порта в буфер программы
         counter+=btr;                                          //увеличиваем счётчик байтов
         ReadPrinting();                      		//вызываем функцию для вывода данных на экран и в файл
        }
       }
    }
  }
}
Создаю имя файла в зависимости от времени

Код:
CString CReadDataDlg::GetFileName(void)
{
SYSTEMTIME lt;
GetLocalTime(&lt);

CString stroke;
stroke = "";
char temp[5];
// Преобразуем целое в строку в десятичном формате
itoa(lt.wYear, temp, 10);
stroke += temp;
stroke += "-";
itoa(lt.wMonth, temp, 10);
stroke += temp;
stroke += "-";
itoa(lt.wDay, temp, 10);
stroke += temp;
stroke += "-";
itoa(lt.wHour, temp, 10);
stroke += temp;
stroke += "-";
itoa(lt.wMinute, temp, 10);
stroke += temp;
stroke += "-";
itoa(lt.wSecond, temp, 10);
stroke += temp;
stroke += ",";
itoa(lt.wMilliseconds, temp, 10);
stroke += temp;
stroke += ".dat";

return stroke;
}
Организую асинхронное чтение в файл
Код:
void ReadPrinting()
{
  myFile.Write(bufrd, strlen(bufrd));  //записать в файл данные из приёмного буфера
  memset(bufrd, 0, BUFSIZE);	        //очистить буфер (чтобы данные не накладывались друг на друга)
}
И оно все работает.
Но только для одного файла!
А организовать цикл не получается
bedouin вне форума Ответить с цитированием
Старый 30.07.2012, 23:20   #5
bedouin
Пользователь
 
Регистрация: 05.01.2012
Сообщений: 27
По умолчанию

Для синхронного режима с этим проблем нет:
Код:
	for (k=0; k<5; k++)
{
	
	//ПРОЦЕДУРА ФОРМИРОВАНИЯ ИМЕНИ ФАЙЛА
curTime = CTime::GetCurrentTime(); 
m_fileName = GetFileName();

UpdateData(TRUE);
char data[23];
strcpy(data,m_fileName);
szFileName = data;

    // Создаём файл и открываем его
   myFile.Open( szFileName, CFile::modeCreate | CFile::modeWrite );

    for (i=0; i<101; i++) 
{
ReadFile(hCom,&szBuffer, 4096,&LenBuf, NULL);
//	ReadFile("data.dat",&szBuffer, 4096,&LenBuf, NULL);

myFile.Write(szBuffer, sizeof(szBuffer));
}
myFile.Close();
}
Но данный код нерационален.
"Кушает" много ресурсов и часто зависает
bedouin вне форума Ответить с цитированием
Старый 31.07.2012, 10:47   #6
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Не вижу, где синхронный код кушает ресурсы. Зависает - это да. Точнее не зависает а просто ждет 4К данных. Посмотрите на SetCommTimeouts(). И потом, почему в асинхронном варианте вы ожидаете информации о событии а в синхронном варианте нет? Что мешает узнать точное число байт в очереди и считать только их - тогда ничего зависать не будет.

Почему вы решили что асинхронный вариант можно только для одного файла? Что вам мешает а) запустить несколько потоков или б) воспользоваться услугами WaitForMultipleObjects()?
waleri вне форума Ответить с цитированием
Старый 12.08.2012, 00:18   #7
bedouin
Пользователь
 
Регистрация: 05.01.2012
Сообщений: 27
По умолчанию

В асинхронном режиме не могу организовать запись в несколько файлов, потому что за входящий поток отвечает функция
Код:
DWORD WINAPI ReadThread(LPVOID)
А за запись - функция
Код:
void ReadPrinting()
В синхронном режиме все просто и понятно: загнал цикл для одной и той же функции и пишешь.
А как работать с двумя - ума не приложу.
Где ограничить объем файла и как проводить отсечку потока, если условие цикла :
Код:
 while(1)						//пока поток не будет прерван, выполняем цикл
  {
 ...
}
не позволяет ограничить объем файла?
bedouin вне форума Ответить с цитированием
Старый 12.08.2012, 00:26   #8
bedouin
Пользователь
 
Регистрация: 05.01.2012
Сообщений: 27
По умолчанию

Распараллелить входной поток (он один единственный) на несколько я не могу, потому что в нем каждый байт что-то значит. При чем важно не только за каким и перед каким байтом он идет, но и какой он по счету.
А на счет очереди вопрос - поток непрерывный (с постоянной скоростью). Получается, число байт в очереди будет постоянно обновляться (накапливаться).
Разве я смогу узнавать, сколько их там в какой момент времени?
bedouin вне форума Ответить с цитированием
Старый 12.08.2012, 05:18   #9
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

А зачем вам цикл в ReadPrinting() вообще?
Все гораздо проще (на псевдокоде):

Код:
void ReadPrinting()
{
  if (GetFileSize() > FILE_SIZE_LIMIT)
  {
    CloseFile();
    CreateFile(new_file_name,...);
  }

  WriteFile(...);
}
Кстати, ReadPrinting не самое лучшее имя - не глядя на код ни за что не догадатся что эта функция делает. Далее, strlen() не лучший способ - у вас нет гарантии, что буфер, который вы прочитали закончится нулем. Даже если девайс и посылает 0, нет гарантии что данные будут прочитаны в один прием. Лучше передавайте размер буфера как аргумент, ну коли так, лучше и сам буфер передавать.
waleri вне форума Ответить с цитированием
Старый 12.08.2012, 21:23   #10
bedouin
Пользователь
 
Регистрация: 05.01.2012
Сообщений: 27
По умолчанию

Спасибо, попробую
bedouin вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
расшифровка данных, принятых с COM-порта IIUH Общие вопросы Delphi 25 12.04.2021 14:05
отправка/принятие данных с порта. romank26 Win Api 1 26.03.2012 12:51
Считка данных по-битно из COM порта Terran Общие вопросы Delphi 3 23.11.2011 04:19
Чтение данных с COM порта 232 Dimitr_88 Общие вопросы C/C++ 10 03.09.2010 10:39
Приём данных с com порта kyc0k Помощь студентам 3 28.03.2008 15:04