Xcode 4.2 on Lion OpenCL continually pausing with EXC_BAD_ACCESS - xcode

So I am running some simple Hello World OpenCL code in Xcode 4.1 on Lion and it continually breaks at clEnqueueTask. The same thing happens when I run the source from the MacResearch.org OpenCL tutorials, which breaks at clEnqueueNDRangeKernel. lldb gives code 1, address 0x30.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <OpenCL/opencl.h>
#define MEM_SIZE (128)
#define MAX_SOURCE_SIZE (0x100000)
int main ()
{
char *program_source = "\n"\
"__kernel void hello(__global char* string) \n"\
"{ \n"\
" string[0] = 'H'; \n"\
" string[1] = 'e'; \n"\
" string[2] = 'l'; \n"\
" string[3] = 'l'; \n"\
" string[4] = 'o'; \n"\
" string[5] = ','; \n"\
" string[6] = ' '; \n"\
" string[7] = 'w'; \n"\
" string[8] = 'o'; \n"\
" string[9] = 'r'; \n"\
" string[10] = 'l'; \n"\
" string[11] = 'd'; \n"\
" string[12] = '!'; \n"\
" string[13] = '\0'; \n"\
"} \n"\
"\n";
size_t source_size = sizeof(program_source);
cl_device_id device_id = NULL;
cl_context context = NULL;
cl_command_queue command_queue = NULL;
cl_mem memobj = NULL;
cl_program program = NULL;
cl_kernel kernel = NULL;
cl_platform_id platform_id = NULL;
cl_uint ret_num_devices;
cl_uint ret_num_platforms;
cl_int ret;
char string[MEM_SIZE];
// get platform and device information
ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &ret_num_devices);
cl_int err = 0;
size_t returned_size = 0;
size_t buffer_size;
// Get some information about the returned device
cl_char vendor_name[1024] = {0};
cl_char device_name[1024] = {0};
err = clGetDeviceInfo(device_id, CL_DEVICE_VENDOR, sizeof(vendor_name), vendor_name, &returned_size);
err |= clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_name),device_name, &returned_size);
// assert(err == CL_SUCCESS);
printf("Connecting to %s %s...\n", vendor_name, device_name);
// create OpenCL context
context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret);
// create command queue
command_queue = clCreateCommandQueue(context, device_id, 0, &ret);
// create memory buffer
memobj = clCreateBuffer(context,CL_MEM_READ_WRITE, MEM_SIZE*sizeof(char), NULL, &ret);
// create kernel program from source code
program = clCreateProgramWithSource(context, 1, (const char **)&program_source, (const size_t*)&source_size, &ret);
// build kernel program
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
// create OpenCL Kernel
kernel = clCreateKernel(program, "hello", &ret);
// set OpenCL kernel parameters
ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&memobj);
// Execute OpenCL kernel
ret = clEnqueueTask(command_queue, kernel, 0, NULL, NULL);
// copy results from the memory buffer
ret = clEnqueueReadBuffer(command_queue, memobj, CL_TRUE, 0, MEM_SIZE*sizeof(char), string, 0, NULL, NULL);
// display results
puts(string);
// finish up
ret = clFlush(command_queue);
ret = clFinish(command_queue);
ret = clReleaseKernel(kernel);
ret = clReleaseProgram(program);
ret = clReleaseMemObject(memobj);
ret = clReleaseCommandQueue(command_queue);
ret = clReleaseContext(context);
return 0;
}
Tried using Guard Malloc, got:
GuardMalloc[OCL_HW-1453]: recording malloc stacks to disk using standard recorder
GuardMalloc[OCL_HW-1453]: Allocations will be placed on 16 byte boundaries.
GuardMalloc[OCL_HW-1453]: - Some buffer overruns may not be noticed.
GuardMalloc[OCL_HW-1453]: - Applications using vector instructions (e.g., SSE) should work.
GuardMalloc[OCL_HW-1453]: version 24.1
OCL_HW(1453) malloc: process 1423 no longer exists, stack logs deleted from /tmp/stack-logs.1423.OCL_HW.yL5f5u.index
OCL_HW(1453) malloc: stack logs being written into /tmp/stack-logs.1453.OCL_HW.pCjTNR.index
Connecting to NVIDIA GeForce GT 330M...
I had no problems with these codes under Snow Leopard and Xcode 3. I made sure not to compile any .cl files by removing them from the target, and 'OpenCl.framework' is linked and everything.
I actually even wiped my computer and clean installed lion and xcode and still it's a problem. I'm pretty sure at this point it's something stupid.
-Thanks a bunch

You're right -- it's something silly. You are passing an incorrect value to the fourth parameter of clCreateProgramWithSource. You should be passing the length of your source string, but you are passing the size of the pointer. You can fix it like this:
size_t source_size = strlen(program_source);
Note that I found this by checking the return value from clBuildProgram. It was -11, CL_BUILD_PROGRAM_FAILURE, which means your kernel compilation failed. Since your kernel looked fine, I did this on the command line:
CL_LOG_ERRORS=stdout ./test
Which caused the Apple OpenCL implementation to dump the compiler build log to standard output. I saw this:
[CL_BUILD_ERROR] : OpenCL Build Error : Compiler build log:
<program source>:2:1: error: unknown type name '__kerne'
__kerne
<program source>:2:8: error: expected identifier or '('
__kerne
Which made me immediately think something was up with your source code length parameter.
Also note that you need to change this in your kernel:
string[13] = '\0';
to
string[13] = 0;
After making these changes, I see this on my Macbook Pro:
Connecting to AMD ATI Radeon HD 6490M...
Hello, world!

Related

PRINTER_INFO_6 not available using WIn32 api

I have been trying to get printer status from a DNP rx1 printer, but the status of the printer does not change when I open the tray of the printer. Here is an example using py32win library to access the status and it always return status = 0 event when the tray is open.
device_name = win32print.GetDefaultPrinter()
handle = win32print.OpenPrinter(device_name)
# Get the default properties for the printer
properties = win32print.GetPrinter(handle, 2)
When I try win32print.GetPrinter(handle, 6) # 6 = print_info_6 I get the some NotImplementedException. So my guess is that the firmware of the printer have not implemented print_info_6. So I can't get the status from the printer
I have also tried using powershell with:
Get-Printer | Select Name, PrinterStatus
Also no change in status when I open the tray or if there is a paper jam.
Is there anything that I'm overlooking? Is there anything else I can try to get the status of the printer?
PRINTER_INFO_6 works for me in C++ on Windows 10 1903 with OneNote printer.
And when I pause the printer I get status 0x00000001 (PRINTER_STATUS_PAUSED).
The C++ code I used for testing.
#pragma comment(lib, "Winspool")
int main()
{
DWORD bufSize;
WCHAR* buf = NULL;
HANDLE hPrinter = NULL;
PRINTER_INFO_6 info = {};
DWORD needed;
BOOL result = FALSE;
DWORD err;
// Get required buffer size
result = GetDefaultPrinter(NULL, &bufSize);
if(!result)
{
err = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != err)
{
std::cout << "GetDefaultPrinter failed with error: \n" << GetLastError();
return 0;
}
}
buf = (WCHAR*)calloc(bufSize, sizeof(WCHAR));
result = GetDefaultPrinter(buf, &bufSize);
if (!result)
{
std::cout << "GetDefaultPrinter failed with error: \n" << GetLastError();
return 0;
}
std::wcout << "Printer name: " << buf << "\n";
result = OpenPrinter(buf, &hPrinter, NULL);
if (!result)
{
std::cout << "OpenPrinter failed with error: \n" << GetLastError();
return 0;
}
result = GetPrinter(hPrinter, 6, (LPBYTE)&info, sizeof(PRINTER_INFO_6), &needed);
if (!result)
{
err = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != err)
{
std::cout << "GetPrinter failed with error: \n" << GetLastError();
return 0;
}
}
BYTE* statBuf = (BYTE*)calloc(needed, sizeof(BYTE));
result = GetPrinter(hPrinter, 6, statBuf, needed, &needed);
if (!result)
{
std::cout << "GetPrinter failed with error: \n" << GetLastError();
return 0;
}
std::cout << "Printer status (low 32bit): " << *((DWORD*)statBuf) << "\n";
statBuf += sizeof(DWORD);
std::cout << "Printer status (high 32bit): " << *((DWORD*)statBuf) << "\n";
getchar();
}
Some issues I found in testing:
Pinter status defined as a DWORD (4 bytes) in PRINTER_INFO_6 structure but GetPrinter requries 8 bytes for it (needed == 8). So you will get ERROR_INSUFFICIENT_BUFFER error when you pass a PRINTER_INFO_6 structure as pPrinter parameter.
There is only PRINTER_INFO_6 defined but no _PRINTER_INFO_6W (Unicode) and _PRINTER_INFO_6A (ANSI) mentioned in the document.

Using pipes in a WinDBG extension

I am writing a WinDBG extension to debug a device driver, and need to call an external binary to debug the device's firmware. I would like to show the output of this binary in the WinDBG console.
My initial idea was to simply pipe the output of the binary to a buffer and print that buffer with ControlledOutput. However, I get a 'broken pipe' error when I try to read from the pipe in my extension.
Here is how I create the external process in my extension:
SECURITY_ATTRIBUTES sAttr;
HANDLE childOutRead = NULL;
HANDLE childOutWrite = NULL;
PROCESS_INFORMATION childProcInfo;
STARTUPINFO childStartInfo;
char buf[4096];
sAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
sAttr.bInheritHandle = TRUE;
sAttr.lpSecurityDescriptor = NULL;
CreatePipe(&childOutRead, &childOutWrite, &sAttr, 0);
// don't inherit read end
SetHandleInformation(childOutRead, HANDLE_FLAG_INHERIT, 0);
ZeroMemory(&childProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&childStartInfo, sizeof(STARTUPINFO));
childStartInfo.cb = sizeof(STARTUPINFO);
childStartInfo.hStdError = childOutWrite;
childStartInfo.hStdOut = childOutWrite;
childStartInfo.hStdIn = GetStdHandle(STD_INPUT_HANDLE);
childStartInfo.dwFlags |= STARTF_USESTDHANDLES;
CreateProcessA(NULL, "myBinary.exe someArgs",
NULL, NULL, TRUE, 0, NULL, NULL,
&childStartInfo, &childProcInfo);
// close the handle not used in parent
CloseHandle(childOutWrite);
// read output
while (1) {
DWORD read;
BOOL r;
DWORD error;
r = ReadFile(childOutRead, buf, sizeof(buf), &read, NULL);
if (!r) {
error = GetLastError();
windbgPrintf("got error 0x%x\n", error);
break;
}
if (read == 0) break;
windbgPrint(buf, read);
}
ReadFile fails with error 0x6D, BROKEN_PIPE. This makes me suspect that the pipe is somehow not being inherited.
I have nearly identical code working in a test outside of WinDBG, so it must be doing something differently. How do I get pipes working in this way inside WinDBG?

OpenCL 2.1 C++ HelloWorld: invalid context?

Similar to this question, I'm trying to implement the HelloWorld example from this video by Wesley Shillingford, except this time with OpenCL 2.1. I can get it to run if I use the default context, but not if I create my own (as the video does).
When I use my own context, it produces a cl::Error (-34 = CL_INVALID_CONTEXT):
From here:
CL_INVALID_CONTEXT = the given context is invalid OpenCL context, or the context associated with certain parameters are not the same.
I'm not sure how I could tell that the context is invalid. I've tried comparing the defaultContext to myContext, and they match of everything except CL_CONTEXT_REFERENCE_COUNT. Which doesn't seem to matter (but maybe it does).
I could be mixing contexts. However, I assign the context I want to use to chosenContext and use that everywhere I need a context.
It seems that something is somehow using the default context instead of my supplied context, but I haven't been able to spot where. Any insights would be appreciated.
The code:
#define CL_HPP_ENABLE_EXCEPTIONS
#define CL_HPP_TARGET_OPENCL_VERSION 200
#include <CL/cl2.hpp>
#include <fstream>
#include <iostream>
int main()
{
// Get Platform and Device
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
auto platform = platforms.front();
std::vector<cl::Device> devices;
platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
auto device = devices.front();
//This context doesn't work. Causes CL_INVALID_CONTEXT (-34)
cl_context_properties properties[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform(), 0};
cl::Context myContext(device, properties);
//If I stick with the default context, things work.
cl::Context defaultContext = cl::Context::getDefault();
//The choice of context here determines whether it works or not:
// myContext -> Fails with CL_INVALID_CONTEXT (-34)
// defaultContext -> works
auto chosenContext = myContext;
std::ifstream helloWorldFile("hello_world.cl");
std::string src(std::istreambuf_iterator<char>(helloWorldFile), (std::istreambuf_iterator<char>()));
cl::Program program(chosenContext, src);
program.build("-cl-std=CL2.1");
//Debugging code: Check to make sure that the contexts are similar
auto myContextDevices = myContext.getInfo<CL_CONTEXT_DEVICES>();
auto defaultContextDevices = defaultContext.getInfo<CL_CONTEXT_DEVICES>();
auto devicesMatch = myContextDevices == defaultContextDevices; //true
auto myContextProperties = myContext.getInfo<CL_CONTEXT_PROPERTIES>();
auto defaultContextProperties = defaultContext.getInfo<CL_CONTEXT_PROPERTIES>();
auto propertiesMatch = myContextProperties == defaultContextProperties; //true
auto myContextNumDevices = myContext.getInfo<CL_CONTEXT_NUM_DEVICES>();
auto defaultContextNumDevices = defaultContext.getInfo<CL_CONTEXT_NUM_DEVICES>();
auto numDevicesMatch = myContextNumDevices == defaultContextNumDevices; //true
auto myContextRefCount = myContext.getInfo<CL_CONTEXT_REFERENCE_COUNT>(); // 1 if defaultContext, 3 if myContext
auto defaultContextRefCount = defaultContext.getInfo<CL_CONTEXT_REFERENCE_COUNT>(); // 4 if defaultContext, 2 if myContext
auto refCountsMatch = myContextRefCount == defaultContextRefCount; // false
auto contextsMatch = myContext == defaultContext; //false
//End of debugging code
//Continuing with computation
char buf[16];
cl::Buffer outputBuffer = cl::Buffer(CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, sizeof(buf));
cl::Kernel kernel(program, "HelloWorld");
kernel.setArg(0, outputBuffer);
cl::CommandQueue commandQueue(chosenContext, device);
auto result = commandQueue.enqueueNDRangeKernel(kernel, 0, 1, 1); //CL_SUCCESS
commandQueue.enqueueReadBuffer(outputBuffer, CL_TRUE, 0, sizeof(buf), buf); // Execution fails here, raises cl::Error (-34)
std::cout << buf;
return EXIT_SUCCESS;
}
Build Command:
g++ -g hello_world_21.cpp -IOpenCL-Headers/opencl21 -std=c++11 -lOpenCL
hello_world.cl:
__kernel void HelloWorld(__global char* output) {
output[0] = 'H';
output[1] = 'e';
output[2] = 'l';
output[3] = 'l';
output[4] = 'o';
output[5] = ' ';
output[6] = 'W';
output[7] = 'o';
output[8] = 'r';
output[9] = 'l';
output[10] = 'd';
output[11] = '!';
output[12] = '\n';
}
You are still using the default context for the global memory buffer instead of using your own context:
cl::Buffer outputBuffer = cl::Buffer(CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, sizeof(buf));
Just change this line to the following and it should work:
cl::Buffer outputBuffer = cl::Buffer(myContext, CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, sizeof(buf));

OS partition coming as RAW after volume cloning in Windows server 2008, 2012 &etc

I'm facing issue On my disk cloning. (ie.) OS partition is coming as RAW instead of NTFS file system after cloning completed.
I have used FSCTL_GET_VOLUME_BITMAP Device IO Control API for getting volume bitmap buffer. Using this volume bitmap i have cloned only used clusters from source disk and written in the same offset of destination disk. In the free cluster positions left as it is.
Only used clusters cloning will cause any issue?
Is it correct for both resident & non-resident content in the volume bitmap?. because i didn't considered non-resident attributes. Simply i cloned only used clusters using the following code.
I am facing this issue only with Windows server computers.
Please any one suggest the way to solve my issue. find the code snippet below.
Finding used clusters
BOOL IsClusterUsed (UINT64 Cluster)
{
return ((BitmapBuffer[Cluster / 32] & (1 << (Cluster % 32))) ? TRUE : FALSE);
}
Getting volume Bitmap:
STARTING_LCN_INPUT_BUFFER StartingLCN;
VOLUME_BITMAP_BUFFER *Bitmap = NULL;
ULONGLONG BitmapSize;
DWORD BytesReturned1;
BOOL Status;
ULONGLONG ClusterCount = 0;
DWORD BytesReturned = 0;
_tprintf(L"[%s %d]>>GetBitmap()volume Vol(%s)\n",
gpCFileName,
__LINE__,
i_VolumeName);
if(ISNULL(o_BitmapBuffer) || ISNULL(o_Size))
{
_tprintf(L"[%s %d]>>GetBitmap()Input null open volume Vol(%s)\n",
gpCFileName,
__LINE__,
i_VolumeName);
return -1;
}
HANDLE hFile=CreateFile(L"\\\\.\\C:",GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);
if(hFile == INVALID_HANDLE_VALUE) // this may happen if another program is already reading from disk
{
LastError = ::GetLastError();
INFOLOG(L"[%s %d]>>GetBitmap()-Unable to open volume Vol(%s) LError(0x%x)\n",
gpCFileName,
__LINE__,
i_VolumeName,
LastError);
CloseHandle(hFile);
return -1;
}
StartingLCN.StartingLcn.QuadPart = 0;
BitmapSize = sizeof (VOLUME_BITMAP_BUFFER) + 4;
Bitmap = (VOLUME_BITMAP_BUFFER *) malloc ((size_t)BitmapSize);
LastError = ::GetLastError();
if(ISNULL(Bitmap))
{
_tprintf(L"[%s %d]>>GetBitmap()-Couldn't properly read volume Bitmap Vol(%s) size(%d) LError(0x%x)\n",
gpCFileName,
__LINE__,
i_VolumeName,
(size_t)BitmapSize,
LastError);
return -1;
}
Status = DeviceIoControl( hFile, FSCTL_GET_VOLUME_BITMAP, &StartingLCN, sizeof (StartingLCN), Bitmap, (DWORD)BitmapSize, &BytesReturned1, NULL);
LastError = ::GetLastError();
if (Status == FALSE && LastError != ERROR_MORE_DATA)
{
SECURE_FREE(Bitmap);
_tprintf(L"[%s %d]>>GetBitmap()-Unable to get Bitmap Vol(%s) LError(0x%x)\n",
gpCFileName,
__LINE__,
i_VolumeName,
LastError);
return -1;
}
ClusterCount = Bitmap->BitmapSize.QuadPart - Bitmap->StartingLcn.QuadPart;//TOT noof clusters
//cout<<"\n Tot no of clusters :"<<ClusterCount<<"\n";
//cout<<"\n StartingLcn :"<<Bitmap->StartingLcn.QuadPart<<"\n";
//printf("Reallocate Memory \n");
BitmapSize = sizeof (VOLUME_BITMAP_BUFFER) + ((Bitmap->BitmapSize.QuadPart) / i_SectorPerCluster) + 1;
Bitmap = (VOLUME_BITMAP_BUFFER *) realloc (Bitmap, (size_t)BitmapSize);
//cout<<"\n Realloc BitmapSize :"<<BitmapSize<<"\n";
//cout<<"\n Realloc size_t BitmapSize :"<<(size_t)BitmapSize<<"\n";
//cout<<"\n GetClusterSize :"<<this->GetClusterSize()<<"\n";
Status = DeviceIoControl( hFile, FSCTL_GET_VOLUME_BITMAP, &StartingLCN, sizeof (StartingLCN), Bitmap, (DWORD)BitmapSize, &BytesReturned, NULL);
LastError = ::GetLastError();
if (Status == FALSE)
{
_tprintf(L"[%s %d]>>GetBitmap()-Couldn't properly read volume Bitmap Vol(%s) Bytes(%ld) LError(0x%x)\n",
gpCFileName,
__LINE__,
i_VolumeName,
BytesReturned,
LastError);
SECURE_FREE(Bitmap);
return -1;
}
ULONGLONG len = sizeof(UINT32) * (1 + (ClusterCount / 32));
*o_BitmapBuffer = (PUINT)new BYTE[(size_t)len];
memcpy (*o_BitmapBuffer, Bitmap->Buffer, ((size_t)(len)));
*o_Size = (DWORD)len;
SECURE_FREE(Bitmap);
CloseHandle(hFile);

Cause of serial port transmitting bad data and WriteFile return wrong number of bytes written?

Bugfix update:
As of Jun, 2013 FTDI did acknowledge to me that the bug was real. They have since released a new version of their driver (2.8.30.0, dated 2013-July-12) that fixes the problem. The driver made it through WHQL around the first of August, 2013 and is available via Windows Update at this time.
I've re-tested running the same test code and am not able to reproduce the problem with the new driver, so at the moment the fix seems to be 'upgrade the driver'.
The original question:
I've got an 8 port USB-serial device (from VsCOM) that is based on the FTDI FT2232D chip. When I transmit at certain settings from one of the ports, AND I use the hardware handshaking to stop and start the data flow from the other end, I get two symptoms:
1) The output data sometimes becomes garbage. There will be NUL characters, and pretty much any random thing you can think of.
2) The WriteFile call will sometimes return a number of bytes GREATER than the number I asked it to write. That's not a typo. I ask for 30 bytes to be transmitted and the number of bytes sent comes back 8192 (and yes, I do clear the number sent to 0 before I make the call).
Relevant facts:
Using FTDI drivers 2.8.24.0, which is the latest as of today.
Serial port settings are 19200, 7 data bits, odd parity, 1 stop bit.
I get this same behavior with another FTDI based serial device, this time a single port one.
I get the same behavior with another 8 port device of the same type.
I do NOT get this behavior when transmitting on the built-in serial ports (COM1).
I have a very simple 'Writer' program that just transmits continuously and a very simple 'Toggler' program that toggles RTS once per second. Together these seem to trigger the issue within 60 seconds.
I have put an issue into the manufacturer of the device, but they've not yet had much time to respond.
Compiler is mingw32, the one included with the Qt installer for Qt 4.8.1 (gcc 4.4.0)
I'd like to know first off, if there's anything that anyone can think of that I could possibly do to trigger this behavior. I can't conceive of anything, but there's always things I don't know.
Secondly, I've attached the Writer and Toggler test programs. If anyone can spot some issue that might trigger the program, I'd love to hear about it. I have a lot of trouble thinking that there is a driver bug (especially from something as mature as the FTDI chip), but the circumstances force me to think that there's at least SOME driver involvement. At the least, no matter what I do to it, it shouldn't be returning a number of bytes written greater than what I asked it to write.
Writer program:
#include <iostream>
#include <string>
using std::cerr;
using std::endl;
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
cerr << "COM Writer, ctrl-c to end" << endl;
if (argc != 2) {
cerr << "Please specify a COM port for parameter 2";
return 1;
}
char fixedbuf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
std::string portName = "\\\\.\\";
portName += argv[1];
cerr << "Transmitting on port " << portName << endl;
HANDLE ph = CreateFileA( portName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if (ph == INVALID_HANDLE_VALUE) {
cerr << "CreateFile " << portName << " failed, error " << GetLastError() << endl;
return 1;
}
COMMCONFIG ccfg;
DWORD ccfgSize = sizeof(COMMCONFIG);
ccfg.dwSize = ccfgSize;
GetCommConfig(ph, &ccfg, &ccfgSize);
GetCommState(ph, &(ccfg.dcb));
ccfg.dcb.fBinary=TRUE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
ccfg.dcb.fAbortOnError=FALSE;
ccfg.dcb.fNull=FALSE;
// Camino is 19200 7-O-1
ccfg.dcb.BaudRate = 19200;
ccfg.dcb.Parity = ODDPARITY;
ccfg.dcb.fParity = TRUE;
ccfg.dcb.ByteSize = 7;
ccfg.dcb.StopBits = ONESTOPBIT;
// HW flow control
ccfg.dcb.fOutxCtsFlow=TRUE;
ccfg.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
COMMTIMEOUTS ctimeout;
DWORD tout = 10;// 10 ms
ctimeout.ReadIntervalTimeout = tout;
ctimeout.ReadTotalTimeoutConstant = tout;
ctimeout.ReadTotalTimeoutMultiplier = 0;
ctimeout.WriteTotalTimeoutMultiplier = tout;
ctimeout.WriteTotalTimeoutConstant = 0;
SetCommConfig(ph, &ccfg, sizeof(COMMCONFIG));
SetCommTimeouts(ph, &ctimeout);
DWORD nwrite = 1;
for(;;) {
nwrite++;
if (nwrite > 30) nwrite = 1;
DWORD nwritten = 0;
if (!WriteFile(ph, fixedbuf, nwrite, &nwritten, NULL)) {
cerr << "f" << endl;
}
if ((nwritten != 0) && (nwritten != nwrite)) {
cerr << "nwrite: " << nwrite << " written: " << nwritten << endl;
}
}
return 0;
}
Toggler program:
#include <iostream>
#include <string>
using std::cerr;
using std::endl;
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
cerr << "COM Toggler, ctrl-c to end" << endl;
cerr << "Flips the RTS line every second." << endl;
if (argc != 2) {
cerr << "Please specify a COM port for parameter 2";
return 1;
}
std::string portName = "\\\\.\\";
portName += argv[1];
cerr << "Toggling RTS on port " << portName << endl;
HANDLE ph = CreateFileA( portName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if (ph == INVALID_HANDLE_VALUE) {
cerr << "CreateFile " << portName << " failed, error " << GetLastError() << endl;
return 1;
}
COMMCONFIG ccfg;
DWORD ccfgSize = sizeof(COMMCONFIG);
ccfg.dwSize = ccfgSize;
GetCommConfig(ph, &ccfg, &ccfgSize);
GetCommState(ph, &(ccfg.dcb));
ccfg.dcb.fBinary=TRUE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
ccfg.dcb.fAbortOnError=FALSE;
ccfg.dcb.fNull=FALSE;
// Camino is 19200 7-O-1
ccfg.dcb.BaudRate = 19200;
ccfg.dcb.Parity = ODDPARITY;
ccfg.dcb.fParity = TRUE;
ccfg.dcb.ByteSize = 7;
ccfg.dcb.StopBits = ONESTOPBIT;
// no flow control (so we can do manually)
ccfg.dcb.fOutxCtsFlow=FALSE;
ccfg.dcb.fRtsControl=RTS_CONTROL_DISABLE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
COMMTIMEOUTS ctimeout;
DWORD tout = 10;// 10 ms
ctimeout.ReadIntervalTimeout = tout;
ctimeout.ReadTotalTimeoutConstant = tout;
ctimeout.ReadTotalTimeoutMultiplier = 0;
ctimeout.WriteTotalTimeoutMultiplier = tout;
ctimeout.WriteTotalTimeoutConstant = 0;
SetCommConfig(ph, &ccfg, sizeof(COMMCONFIG));
SetCommTimeouts(ph, &ctimeout);
bool rts = true;// true for set
for(;;) {
if (rts)
EscapeCommFunction(ph, SETRTS);
else
EscapeCommFunction(ph, CLRRTS);
rts = !rts;
Sleep(1000);// 1 sec wait.
}
return 0;
}
I don't have a good answer yet from FTDI, but I've got the following suggestions for anyone dealing with this issue:
1) Consider switching to a non-FTDI usb-serial converter. This is what my company did, but certainly this isn't an option for everyone (we're putting the chip in our own product). We're using Silicon Labs chips now, but I think there are one or two other vendors as well.
2) Per Hans Passant in the comments - reconsider the use of RTS/CTS signalling. If the writes don't fail due to blocking, then you shouldn't trigger this bug.
3) Set all writes to infinite timeout. Again, no fail due to blocking, no triggering of the bug. This may not be appropriate for all applications, of course.
Note that if pursuing strategy #3, if Overlapped IO is used for writes, then CancelIo and it's newer cousin CancelIoEx could be used to kill off the writes if necessary. I have NOT tried doing so, but I suspect that such cancels might also result in triggering this bug. If they were only used when closing the port anyway, then it might be you could get away with it, even if they do trigger the bug.
If anyone else is still seeing this -- update your FTDI driver to 2.8.30.0 or later, as this is caused by a driver bug in earlier versions of the FTDI driver.

Resources