|
Hi everybody,
I have some problems reading the COM ports. In particular I have used WaitForMultipleObjects and ReadFile, that permit me
listen the COM port selected.
I use this code for reading the COM port while I was trasfering a file with Bluetooth from the phone to the computer.
I can open the right COM port (they are 4, one for the input, one for the output and two for some remote control, i think)
but in any of them I can see nothing in the buffer, because everytime the ::WaitForMultipleObjects switch
in the default case, exiting from the cycle.
My question is:
Is this the correct way to read the bluetooth packets arriving in the COM ports?
If, yes, why during the data transfert is like if no package where transfering in the port?
I have used also CSerial class present in this site with the same result.
Thank,
Anne
//[...]
HANDLE hevtOverlapped = ::CreateEvent(0,TRUE,FALSE,0);;
if (hevtOverlapped == 0)
{
cout << "Unable to create manual-reset event for overlapped I/O.\n";
return -1;
}
// Setup the overlapped structure
OVERLAPPED ov = {0};
ov.hEvent = hevtOverlapped;
// Open the "STOP" handle
string name1 = "Overlapped_Stop_Event";
HANDLE hevtStop = ::CreateEvent(0,TRUE,FALSE, name1.c_str());
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent(&ov);
if (lLastError != ERROR_SUCCESS)
{
cout << "Unable to wait for a COM-port event.\n";
return -1;
}
// Setup array of handles in which we are interested
HANDLE ahWait[2];
ahWait[0] = hevtOverlapped;
ahWait[1] = hevtStop;
// Wait until something happens
switch (::WaitForMultipleObjects(sizeof(ahWait)/sizeof(*ahWait),ahWait,FALSE,500))
{
case WAIT_OBJECT_0:
{
// Read data from the COM-port (ReadFile)
[...]
}
break;
case WAIT_OBJECT_0+1:
{
// Set the continue bit to false, so we'll exit
fContinue = false;
}
break;
default:
{
// Something went wrong
// exit
[...]
}
break;
}
}
while (fContinue);
//[...]
|
|
|
|
|
You should check better the WaitForMultipleObjects return value and, if it is WAIT_FAILED then call GetLastError , as stated in the documentation[^].
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Firstly, please put all your code in <pre></pre> tags, or select it and click the code block button above the message content text box. This will make it easier for everyone to read.
0.5s isn't a very long time to wait for something like bluetooth, try waiting for longer.
Make sure the hevtStop isn't set
Add cases to the WaitForMultipleObjects switch for WAIT_FAILED and WAIT_TIMEOUT , in WAIT_FAILED add a call to GetLastError() , if it is hit, find the error code in the System Error Codes[^] page on MSDN
If you are using ReadFile, I wouldn't bother with overlapped operations at this stage. Either get it working then put them in, or put this code into a different thread
|
|
|
|
|
Hi!
Thank you for the replay.
- I set 4000 instead 500 with the same result (I also set INFINITE, and the program is blocked in waiting)
- I haven't done any other operation with hevtStop, it shouldn't be set
- I add WAIT_TIMEOUT and WAIT_FAILED, and it enter in WAIT_TIMEOUT, after 4 seconds.
I use ReadFile, but I use it inside WAIT_OBJECT_0, where it doesn't enter.
Sorry for the tags, in future i'll use
|
|
|
|
|
Well that really only leaves serial.WaitEvent(&ov) . How and where is the event set?
Have you tried opening the COM port in something like HyperTerminal or PuTTY?
|
|
|
|
|
I use the class CSerial (founded in this site) and serial is an object of the class.
serial.WaitEvent(&ov) is this:
<pre>
LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
{
// Check if time-outs are supported
CheckRequirements(lpOverlapped,dwTimeout);
// Reset error state
m_lLastError = ERROR_SUCCESS;
// Check if the device is open
if (m_hFile == 0)
{
// Set the internal error code
m_lLastError = ERROR_INVALID_HANDLE;
// Issue an error and quit
_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n");
return m_lLastError;
}
</pre>
I haven't used HyperTerminal and Putty, but I think is a good idea for seeing the effective data tranfer (if I undestand correctly the usage)
Anne
|
|
|
|
|
Your code looks pretty much the same as the sample code, so all I can suggest for now is that you open the COM port in PuTTY or HyperTerminal and make sure that you have the right settings for the connection
|
|
|
|
|
Hi,
I try to use PuTTY and I never can see the data flowing (PuTTY says "Unable to Open the port").
I try to use Portmon (Sysinternal) but also in this case the "Device is in use" and I can't open it)
At this point i would like to try the code on some other device, if you have any ideas how can I try it (not only bluetooth, also a device using COM port, or also a simulator of data transfer in COM port)
Any idea is wellcome,
Anne
|
|
|
|
|
This is a good indication that your error handling isn't very good.
Make sure you are checking the return value of all functions that you call in CSerial.
I dont know of any virtual COM ports, but a good place to start would be google[^].
|
|
|
|
|
Hi All,
Both _stat() and _fstat() are used to obtain the opened file information._stat() does not require FileDescriptor whereas _fstat() needs FileDescriptor to obtain the file Info.
Is any other differences between these?In what scenario these can be used?
Can any one clarify my doubt?
Thanx.
|
|
|
|
|
Reffer to MSDN for function documentation.
_stat[^]
_fstat[^]
_fstat gets information based on a file descriptor (acquired with _open or fopen)
_stat gets information based on a file path
|
|
|
|
|
Can you tell me if I use in corect way these classes , CTypedPtrArray & CStringArray ?
These are member variable to CMyDoc class :
typedef CTypedPtrArray<CObArray,CStringArray*> CTableArray;
class CMyDoc : public CDocument
{
public:
CStringArray m_saTable;
CTableArray m_saTables;
...
}
and here is code snipped for use of them :
m_saTable.Add("String Test");
m_saTables.Add(&m_saTable);
CStringArray* saTest = m_saTables.GetAt(0);
CString sTest = saTest->GetAt(0);
TRACE("\n %s \n",sTest);
but , where I need to delete elements ?
I try to delete items in OnCloseDocument(...)
void CMyDoc::OnCloseDocument()
{
m_saTable.RemoveAll();
m_saTables.RemoveAll();
TRACE("\n %d - %d \n",m_saTable.GetSize(),m_saTables.GetSize());
CDocument::OnCloseDocument();
}
But with or without remove code , I didn't have memory leaks in debug window ... is really necesary to delete the items ?
Any help , I will appreciated ! Thanks !
|
|
|
|
|
Just one point to offer. Having two member variables named so similarly is likely going to lead to confusion at some later point. Try to come up with names that are more meaningful to the actual use of the data. For example if the strings in the string array class are all people names, cities of the world or street names, try to use that instead of m_saTable. Similarly with the member m_saTables. Just a suggestion.
Chris Meech
I am Canadian. [heard in a local bar]
In theory there is no difference between theory and practice. In practice there is. [Yogi Berra]
posting about Crystal Reports here is like discussing gay marriage on a catholic church’s website.[Nishant Sivakumar]
|
|
|
|
|
Thanks for the suggestion , I will fix that .
|
|
|
|
|
Firstly, make sure you are dumping the memory leaks correctly. There are a number of ways to do this, but the best is by adding
#if defined(DEBUG) || defined(_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
as early in your code as possible, in your case it will be the constructor of your App object BOOL CxxxApp::CxxxApp()
This is the only way will dump the memory leaks after all static objects have been destroyed. All other ways that I know of will give misleading results if you have static objects
If no destructor is provided for your class 1 is generated which calls the destructors of all member classes, otherwise the destructors of all member classes is called after your destructor code.
In destructors you only need to delete memory allocated by new , malloc or the likes.
Either way, your code is calling the destructors to m_saTable and m_saTables and these destructors will free any memory associated with it.
Having said that, your CTableArray is storing pointers, which means that the destructor for the table will only free the pointers, and not the actual data.
You will need to enumerate each item and free its memory manually. CMyDoc::OnCloseDocument() would be a good place to do this.
INT_PTR nElements = m_saTables.GetCount();
for (int nIndex = 0; nIndex < nElements; ++nIndex) {
delete m_saTables.GetAt(nIndex);
}
|
|
|
|
|
At this code :
#if defined(DEBUG) || defined(_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
give me the follow error :
error C2501: '_CrtSetDbgFlag' : missing storage-class or type specifiers
Because I use VC6 ?
|
|
|
|
|
Possibly.
Try #include <crtdbg.h> and see if that fixes the problem, otherwise try _CrtDumpMemoryLeaks(); as the last statement in the App destructor CxxxApp::~CxxxApp()
I havn't used VC 6 in a many years, and it may not have these debugging functions. MSDN only has version 7.1 (2003) onwards.
If I might make a suggestion, it might be an idea to upgrade.
VC++ 7.1 (2003) is the latest version to support Windows 95, VC++ 8.0 (2005) is the latest version to support Windows 98/ME, VC++ 9.0 (2008) and 10.0 (2010) support Windows 2000 onwards.
Unless you are wanting to support these older platforms I would suggest upgrading to at least VS 2008 Express. It is a free download from the Microsoft website with a Windows Live ID.
|
|
|
|
|
I don't know if is corect , but I think that I solve it :
typedef CTypedPtrArray<CObArray,CStringArray*> CDumpArray;
class CMyDoc : public CDocument
{
protected:
CMyDoc();
DECLARE_DYNCREATE(CMyDoc)
public:
CDumpArray m_arrDump;
...
};
CString sText = "one";
CStringArray* pTable = NULL;
pTable = new CStringArray();
pTable->Add(sText);
sText = "two";
pTable->Add(sText);
m_arrDump.Add(pTable);
pTable = new CStringArray();
sText = "three";
pTable->Add(sText);
sText = "four";
pTable->Add(sText);
m_arrDump.Add(pTable);
void CMyDoc::OnCloseDocument()
{
TRACE("\n m_arrDump %d \n",m_arrDump.GetSize());
CString sTemp;
for(int n = 0;n < m_arrDump.GetSize();++n)
{
TRACE("\n StringArray no %d \n",n);
CStringArray* pTable = m_arrDump.GetAt(n);
for(int t = 0;t < pTable->GetSize();++t)
{
sTemp = pTable->GetAt(t);
TRACE("\n %s \n",sTemp);
}
}
int nCount = m_arrDump.GetSize();
for(int i = 0;i < nCount;++i)delete m_arrDump.GetAt(i);
m_arrDump.RemoveAll();
TRACE("\n m_arrDump %d \n",m_arrDump.GetSize());
CDocument::OnCloseDocument();
}
|
|
|
|
|
I cant see anything wrong with this, however a better solution for CMyDoc::OnCloseDocument() would be
void CMyDoc::OnCloseDocument()
{
TRACE("\n m_arrDump %d \n",m_arrDump.GetSize());
CString sTemp;
int nCount = m_arrDump.GetSize();
for(int n = 0;n < nCount; ++n)
{
TRACE("\n StringArray no %d \n",n);
CStringArray* pTable = m_arrDump.GetAt(n);
for(int t = 0;t < pTable->GetSize();++t)
{
sTemp = pTable->GetAt(t);
TRACE("\n %s \n",sTemp);
}
delete pTable;
}
m_arrDump.RemoveAll();
CDocument::OnCloseDocument();
}
|
|
|
|
|
Thanks , works fine ! Thank you all !!!
|
|
|
|
|
In my SDI app, I want to display a dialog after the main window is showing (this is to verify the starting path of some file processing). I've set breakpoints in locations like CFrameWnd::OnCreate() , CFrameWnd::PreCreateWindow() , CListView::OnInitialUpdate() , but none of them are hit before the action starts in CDocument::OnNewDocument() .
I've seen a few examples of this with the dialog being displayed before the main window is showing, but that's not the look I am after.
Thanks for any help you might have.
- DC
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|
|
Have you tried CView::OnActivateFrame ?
Seems to be working on my sample test; you might have to use a bool to guard the code because OnActivateFrame is called often.
Watched code never compiles.
|
|
|
|
|
Maximilien wrote: Have you tried CView::OnActivateFrame ?
CDocument::OnNewDocument() is still hit first.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|
|
The window shows where you have the m_pMainWnd->ShowWindow(SW_SHOW); call in CxxxSDIApp::InitInstance() or during if (!ProcessShellCommand(cmdInfo)) if the program was started with SW_SHOW option (which it is when run from the debugger and the Windows Explorer.
Depending on what you want the dialog to do, you may be able to just make a modeless dialog right there, otherwise you will need to m_pMainWnd->SendMessage() or m_pMainWnd->PostMessage() to tell the main window to open the modal dialog.
SendMessage() will do it right then, whereas PostMessage() will do it some time in the near future.
EDIT: HTML formatting error
|
|
|
|
|
Displaying the dialog at the tail end of CWinApp::InitInstance() did the trick. Thanks.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|