PDA

View Full Version : WriteFile in QT... Too many bytes to write?



AlphaWolfXV
14th September 2009, 16:48
Hello all,
Currently I am working on creating an HID device User Application using QT4. I am using QTCreator 1.2 on Windows Vista (32bit) Business. Here is the rundown...

Firstly, I open a file and create a buffer filled with x bytes of data from the file, then I call writefile on the buffer with the number of bytes passed as a DWORD (code below). Since the HID device has a packet size of 64 bytes, the internal USB engine parses out the data in 64 byte blocks to the device. (WORKS)
Next, once the writefile() completes, it returns to the caller and if the file was not completely read, it grabs the next set of x bytes and repeats. (WORKS SOMETIMES)

If I set the x bytes to something <=256, the transfers work exactly as described above. Once I exceed 256, the QT App crashes during the WriteFile() call. I have qDebug statements running to see when it gets to certain areas of theprogram, and I see it enter the WriteFile() but never returns before it crashes. The device however gets the complete transmission of x bytes even though the crash happens long before the device would get all the data. i.e. If I set the x bytes to 1024, the device sees all 1024 passed bytes, even though the app crashed on the WriteFile() call. My total file size right now is ~ 2048 bytes. (This could grow to < 8kB). So I set the x bytes = 4096, and fixed the descriptors in the device, also under my control, to take in 4k report size. I can break in the device code and see that it receives the entire file, but the QT App still crashes almost immediately after the writefile() has been called.

If anyone can offer some assistance it would be greatly appreciated... If I need to submit more/less code, just say the word!
Thanks to all,
AlphaWolfXV

Here is the calling code snippet:

void USBProgrammer::cmdProgNew()
{
unsigned int patSz = 4096;
unsigned char outputBuffer[patSz+1];
unsigned char* pOutBuf;
BYTE n;
gblHold = "";
// teBottom->clear();
totalECHCount = 0; //clear before we start
for(unsigned int i = 0; i < (patSz + 1); i++)
outputBuffer[i] = 0;
//we need to get what file we will be programming from the user. (if there is not one already
//selected)
if(!(lblProgramFile->text().contains(".ech")))
//we do not have avalid file selected, lets get one...
cmdBrowse();
if (!(blnAlreadyActive))
Activate(); //need this running first...
if (!(blnAlreadyActive))
{
//this kicks us out if the board still isn't connected after
//trying again to activate!
sbarStatus->showMessage(msgProgError, 2000);
return;
}

lblProgress->setText(progBarDownload);
pbarProgress->reset(); //put the progress bar back to 0

//now we need to stuff the output buffer.
QFile fIn(lblProgramFile->text()), fOut();
QDataStream dsIn(&fIn); //data stream input from file.
QMessageBox m;
unsigned int totCode, progBarVal;

unsigned char tmp[0], tmp2[0],block,outCount = 2, tmpi, i;
if(!fIn.open(QIODevice::ReadOnly))
{
m.setText("Error opening ECH File!");
m.exec();
fIn.close(); return;
}
totCode = fIn.size();

unsigned int z, q;
pOutBuf = outputBuffer;
*pOutBuf++ = 0;//first byte always 0;
*pOutBuf++ = 1; //Code Byte, first byte received at SiLabs
while (!fIn.atEnd())
{
if (pOutBuf == outputBuffer)
{
*pOutBuf++ = 0;
q = dsIn.readRawData((char*)pOutBuf,(patSz));
}
else
q = dsIn.readRawData((char*)pOutBuf,(patSz - 1 ));
qDebug()<< "BytesWritten:"<<q;
QString s;
for (unsigned int m1 = 0; m1 < (patSz+1); m1++)
s.append(QString::number(outputBuffer[m1],16) + ", ");
qDebug()<<s;
//send it out
n = hidDevice.setReport_Interrupt(outputBuffer, (patSz+1));
qDebug()<<"Return Code from Interrupt Send:" << n;
//ok, clear the buffer for the next round
for(unsigned int m1 = 0; m1 < (patSz+1); m1++)
outputBuffer[m1] = 0;
pOutBuf = outputBuffer;
}
}
And the actual WriteFile() Call:


BYTE HIDDevice::setReport_Interrupt(BYTE* buffer, DWORD bufferSize)
{
BYTE status = HID_DEVICE_SUCCESS;
if(bufferSize <= (DWORD)(m_OutputReportBufferLength))
{
if(isOpened())
{
DWORD bytesWritten = 0;
OVERLAPPED o = {0};
o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
bool a = flushBuffers();
qDebug()<< "Output Buffer Length="<<QString::number(m_OutputReportBufferLength, 10);
//try to write to the file...
if(!::WriteFile(m_Handle, buffer, bufferSize, &bytesWritten, &o))
{
qDebug()<< "Errored Out!";
//if write fails see if due to IO pending...
if(GetLastError() == ERROR_IO_PENDING) //winerror.h
{
// if there is still data to be written, wait on the event
// for m_SetReportTimeout
DWORD waitStatus = WaitForSingleObject(o.hEvent, m_SetReportTimeout);
// if the object is signaled, get the overlapped result...
// the write succeeded...
if(waitStatus == WAIT_OBJECT_0)
{
GetOverlappedResult(m_Handle, &o, &bytesWritten, FALSE);
}
else if (waitStatus == WAIT_TIMEOUT)
{
status = HID_DEVICE_TRANSFER_TIMEOUT;
CancelIo(m_Handle);
}
else
{
status = HID_DEVICE_TRANSFER_FAILED;
CancelIo(m_Handle);
}
}
else
status = HID_DEVICE_TRANSFER_FAILED;

}
qDebug()<<"Bytes Written:"<<bytesWritten;
CloseHandle(o.hEvent);
}
else
status = HID_DEVICE_NOT_OPENED;
}
else
status = HID_DEVICE_INVALID_BUFFER_SIZE;
return status;
}

AlphaWolfXV
16th September 2009, 02:22
Ok, some changes here, now I can send the data out and for a 1024 byte transfer, The first 2 transfers pass fine, then the final transfer runs and either times out or causes qt to crash. Completely changed to syncronous call now.

The error code when the debug window appears is: -1073741819. All the data does complete writing, so it appears as though it is a crash on the last call only.


It acts as if the file is not closing properly or something... closing prematurely, some combination. Any ideas welcomed!
Thanks,
AlphaWolfXV

Here is the new Interrupt Report code:

BYTE HIDDevice::setReport_Interrupt(BYTE* buffer, DWORD bufferSize)
{
BYTE status = HID_DEVICE_SUCCESS;
if(bufferSize <= (DWORD)(m_OutputReportBufferLength))
{
if(isOpened())
{
LOCK_MUTEX();
qDebug()<<"MUTEX LOCKED!";
DWORD bytesWritten = 0;
OVERLAPPED o = {0};
o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(o.hEvent == NULL)
qDebug()<< "OVERLAPPED issue with structure.";
qDebug()<< "Output Buffer Length="<<QString::number(m_OutputReportBufferLength, 10);
//try to write to the file...
::WriteFile(m_Handle, buffer, bufferSize, &bytesWritten, NULL);
/*{
//qDebug()<< "Errored Out!"<< GetLastError();

//if write fails see if due to IO pending...
if(GetLastError() == ERROR_IO_PENDING) //winerror.h
{
//qDebug()<<"Begin Waiting... For IO Overlapped.";
//while(!(HasOverlappedIoCompleted(&o)));
//qDebug()<<"Done waiting for IO!";
// if there is still data to be written, wait on the event
// for m_SetReportTimeout
DWORD waitStatus = WaitForSingleObject(o.hEvent, m_SetReportTimeout);
// if the object is signaled, get the overlapped result...
// the write succeeded...
if(waitStatus == WAIT_OBJECT_0)
{
GetOverlappedResult(m_Handle, &o, &bytesWritten, FALSE);
}
else if (waitStatus == WAIT_TIMEOUT)
{
status = HID_DEVICE_TRANSFER_TIMEOUT;
CancelIo(m_Handle);
}
else
{
status = HID_DEVICE_TRANSFER_FAILED;
CancelIo(m_Handle);
}
}
else
status = HID_DEVICE_TRANSFER_FAILED;

}*/
qDebug()<<"Bytes Written:"<<bytesWritten;
CloseHandle(o.hEvent);
}
else
status = HID_DEVICE_NOT_OPENED;
}
else
status = HID_DEVICE_INVALID_BUFFER_SIZE;
UNLOCK_MUTEX();
qDebug()<<"MUTEX UNLOCKED!";
return status;
}


and the new calling code is:

void USBProgrammer::cmdProgNew()
{
DWORD patSz = 1024;
unsigned char outputBuffer[patSz+1];
unsigned char* pOutBuf;
BYTE n;
gblHold = "";
// teBottom->clear();
totalECHCount = 0; //clear before we start
for(unsigned int i = 0; i < (patSz + 1); i++)
outputBuffer[i] = 0;
//we need to get what file we will be programming from the user. (if there is not one already
//selected)
if(!(lblProgramFile->text().contains(".ech")))
//we do not have avalid file selected, lets get one...
cmdBrowse();
if (!(blnAlreadyActive))
Activate(); //need this running first...
if (!(blnAlreadyActive))
{
//this kicks us out if the board still isn't connected after
//trying again to activate!
sbarStatus->showMessage(msgProgError, 2000);
return;
}

lblProgress->setText(progBarDownload);
pbarProgress->reset(); //put the progress bar back to 0

//now we need to stuff the output buffer.
QFile fIn(lblProgramFile->text()), fOut();
QDataStream dsIn(&fIn); //data stream input from file.
QMessageBox m;
unsigned int totCode, progBarVal;

unsigned char tmp[0], tmp2[0],block,outCount = 2, tmpi, i;
if(!fIn.open(QIODevice::ReadOnly))
{
m.setText("Error opening ECH File!");
m.exec();
fIn.close(); return;
}
totCode = fIn.size();

unsigned int z, q;
pOutBuf = outputBuffer;
*pOutBuf++ = 0;//first byte always 0;
*pOutBuf++ = 1; //Code Byte, first byte received at SiLabs
while (!fIn.atEnd())
{
if (pOutBuf == outputBuffer)
{
*pOutBuf++ = 0;
q = dsIn.readRawData((char*)pOutBuf,(patSz));
}
else
{
q = dsIn.readRawData((char*)pOutBuf,(patSz - 1 ));
q++;
}
qDebug()<< "BytesWritten before send:"<<q+1;
QString s;
for (unsigned int m1 = 0; m1 < (patSz+1); m1++)
s.append(QString::number(outputBuffer[m1],16) + ", ");
qDebug()<<s;
//send it out
n = hidDevice.setReport_Interrupt(outputBuffer, (patSz+1));
qDebug()<<"Return Code from Interrupt Send:" << n;
//ok, clear the buffer for the next round
for(unsigned int m1 = 0; m1 < (patSz+1); m1++)
outputBuffer[m1] = 0;
pOutBuf = outputBuffer;
}
fIn.close();
}