IIO device buffer always null - c

I am using an IMU sensor called LSM6DSL with the iio drivers. They work fine if I display the raw values with the command:
cat /sys/bus/iio/devices/iio:device0/in_accel_x_raw
Then I decided to use the libiio so I can read all these values from a C program :
struct iio_context *context = iio_create_local_context();
struct iio_device *device = iio_context_get_device(context, 1);
struct iio_channel *chan = iio_device_get_channel(device, 0);
iio_channel_enable(chan);
if (iio_channel_is_scan_element(chan) == true)
printf("OK\n");
struct iio_channel *chan2 = iio_device_get_channel(device, 1);
iio_channel_enable(chan2);
struct iio_buffer *buff = iio_device_create_buffer(device, 1, true);
if (buff == NULL)
{
printf("Error: %s\n", strerror(errno));
return (1);
}
And this is the result :
OK
Error: Device or resource busy
Am I missing something? Let me know if you need more informations.

I guess I found the answer, and I didn't pay attention to the effects of the ncurses library (sorry for not mentioning that I was using it).
I moved these functions before the initialization of ncurses and now the buffer is created successful.

Related

How to properly initialize a string that is a field of an autogenerated structure from RPC in ANSI-C

I'm programming a RPC client-server application using ANSI-C, in Ubuntu 17.04. I'm having big troubles at the time of properly initializing strings that are auto-generated from a predefined structures using RPC, and passing it from client-side to server.
Here's my definition of the structure (in RPC):
struct usuario{
int codigo;
string nombreUsuario<25>;
string nombreReal<25>;
string apellido1<25>;
string apellido2<25>;
string clave<25>;
int num_tarjeta;
string fechaAlta<10>;
string fechaBaja<10>;
};
Here the remote function definition (in RPC):
program NPROG {
version NVERS {
string registrarse(usuario)=2;
}=1;
}=0x20000001;
NOTE: I initialize all the fields, and all the strings before the remote call, the strings like the way I'm going to show below, but I'm writing just one here in order to not writing a long question.
Now I've got something like this in my client side:
void
nprog_1(char *host)
{
CLIENT *clnt;
char * *result_1;
usuario register_arg;
#ifndef DEBUG
clnt = clnt_create (host, NPROG, NVERS, "tcp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
register_arg.codigo = 0;
// In this way, Segment fault, the two functions, strcpy and strncpy
// strcpy(register_arg.nombreUsuario, "SomeName");
strncpy(register_arg.nombreUsuario, "SomeName", sizeof(register_arg.nombreUsuario));
// call failed en registro: RPC: Remote system error
// register_arg.nombreUsuario = "SomeName";
result_1 = registrarse_1(&register_arg, clnt);
if (result_1 == (char **) NULL) {
clnt_perror (clnt, "call failed en registro");
}
#ifndef DEBUG
clnt_destroy (clnt);
#endif /* DEBUG */
}
I don't put the remote/server code because I'm not even able to get there.
The problem is, that in the generated struct for strings no memory is preallocated, these are just dangling pointers! So you have to care about the memory for the string yourself, you could for example pass a constant:
register_arg.nombreUsuario = "SomeName";
or allocate the memory yourself:
register_arg.nombreUsuario = strdup("SomeName");
Then it should work as you expect.

Contents in message-queue is changed

I am using uuntu 18.04.1LTS and studying IPC using C. I'm testing Unix i/o using LPC this time, and there's a problem when more than one client connects to the server at the same time.
(when only one client connected, there is no problem.)
sprintf(s1,"./%sA",t);
sprintf(s2, "./%sB", t);
if (MakeDirectory(s1, 0755) == -1) {
return -1;
}
if (MakeDirectory(s2, 0755) == -1) {
return -1;
}
for (i = 0; i < 5; i++)
{
memset(dirName, 0, SIZE);
sprintf(dirName, "%s/%d",s1,i);
usleep(300000);
if (MakeDirectory(dirName, 0755) == -1) {
return -1;
}
}
This code is client's main function. There is no problem at the top, but after running the repeat statement once (when i = 1), MakeDirectory() returns -1 with an error.
(t refers to the pid of the forked process converted into a string.)
int MakeDirectory(char* path, int mode) {
memset(&pRequest, 0x00, LPC_REQUEST_SIZE);
memset(&pResponse, 0x00, LPC_RESPONSE_SIZE);
pRequest.pid = getpid();
pRequest.service = LPC_MAKE_DIRECTORY;
pRequest.numArg = 2;
pRequest.lpcArgs[0].argSize = strlen(path);
strcpy(pRequest.lpcArgs[0].argData, path);
pRequest.lpcArgs[1].argSize = mode;
msgsnd(rqmsqid, &pRequest, LPC_REQUEST_SIZE, 0);
msgrcv(rpmsqid, &pResponse, LPC_RESPONSE_SIZE, getpid(), 0);
int res = pResponse.responseSize;
return res;
}
This is client's MakeDirectory, and
int MakeDirectory(LpcRequest* pRequest) {
memset(&pResponse, 0x00, LPC_RESPONSE_SIZE);
char *path = pRequest->lpcArgs[0].argData;
int mode = pRequest->lpcArgs[1].argSize;
int res = mkdir(path, mode);
pResponse.errorno = 0;
pResponse.pid = pRequest->pid;
printf("%ld\n", pResponse.pid);
pResponse.responseSize = res;
msgsnd(rpmsqid, &pResponse, LPC_RESPONSE_SIZE, 0);
return res;
}
This is a function of the server that runs after checking the pRequest.service when the MakeDirectory function is enabled on the client.
Again, there's nothing wrong with having one client, and if there's more than one. I checked with printf(), but the server passes 0 and the client receives -1. I don't know why this happens.
There's too much missing from your code to know definitively what's happening. I'm placing my bet on either using unallocated memory, or not recognizing a syscall error.
I'm using LTS 16, and there's no definition on my system for LpcRequest or LPC_REQUEST_SIZE, etc. You don't show how they're defined, so we don't know for example if pRequest.lpcArgs[1] exists.
You're also not checking the return code for msgsnd and msgrcv, a sure recipe for endless hours of entertaining debugging.
I suggest you edit your question to include working code, and a shell script that produces the mysterious result. Then someone will be able, if willing, to debug it and explain where you went wrong.
My other suggestion in this area is pretty standard: W. Richard Stevens's books on TCP/IP, specifically Unix Network Programming. If you're studying this stuff, you'll absolutely be glad to have read it.

sending a struct array with sun rpc from server to client

how can i correctly send a struct from the server to the client in ansi-c sun-rpc?
in my test.x IDL file i defined a struct cluster with a string and an int
and a type clusters which is a variable-length array of cluster elements:
struct cluster {
string name<255>;
int debuglevel;
};
typedef cluster clusters<32>;
i then changed the stubs generated by rpcgen like
test_server.c
clusters *
test_1_svc(void *argp, struct svc_req *rqstp)
{
static clusters result;
cluster cl1, cl2;
cl1.name="cl1";
cl1.debuglevel="1";
cl2.name="cl2";
cl2.debuglevel="2";
cluster clist[2];
clist[0]=cl1;
clist[1]=cl2;
result.clusters_len = 2;
result.clusters_val = &clist;
/*
* insert server code here
*/
return(&result);
}
and test_client.c
test_prog_1( char* host )
{
CLIENT *clnt;
clusters *result_1;
char* test_1_arg;
clnt = clnt_create(host, test_PROG, test_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror(host);
exit(1);
}
result_1 = test_1((void*)&test_1_arg, clnt);
if (result_1 == NULL) {
clusters* rec_cls = malloc(2*sizeof(struct cluster));
if(xdr_clusters(&result_1, rec_cls)){
printf("got xdr_clusters");
}
clnt_perror(clnt, "call failed:");
}
clnt_destroy( clnt );
}
Both compile, but the server often segfaults after one or two request runs by the client and on the clientside the xdr_clusters function never returns true. It seems like some kind of memory mismanagement and I'm also not sure if I'm handling the serialization on the server-side correctly.
I just filled result.clusters_len and result.clusters_val with the appropiate values like they are defined in test.h (by rpcgen):
typedef struct {
u_int clusters_len;
cluster *clusters_val;
} clusters;
Do I have to make use of xdr_clusters on the server side for this to correctly serialize the result?
thank you
okay, i figured my mistakes, lets summarize them:
know how to initialize an int correctly (without the quotes of course...)
forget about that clist nonsense, just malloc the internal pointer of the result struct directly
read the damn compiler warnings: when it tells you, that there are functions declared implicitly and you didn't want implicit declarations, then there is possibly something missing, in my case i needed to include stdlib.h and stdio.h to get malloc, printf and exit functions for server and client stubs.
on the clientside: why should we do anything except throwing an error if the result is NULL? see the new client code below to check correct result printing
test_server.c
test_1_svc(void *argp, struct svc_req *rqstp){
static clusters result;
cluster cl1, cl2;
cl1.name="cl1";
cl1.debuglevel=1;
cl2.name="cl2";
cl2.debuglevel=2;
result.clusters_len = 2;
result.clusters_val = malloc(2*sizeof(struct cluster));
result.clusters_val[0]=cl1;
result.clusters_val[1]=cl2;
return(&result);
}
test_client.c
test_prog_1( char* host )
{
CLIENT *clnt;
clusters *result_1;
char* test_1_arg;
clnt = clnt_create(host, test_PROG, test_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror(host);
exit(1);
}
result_1 = test_1((void*)&test_1_arg, clnt);
if (result_1 == NULL) {
clnt_perror(clnt, "call failed:");
}else{
printf("I got %d cluster structs in an array\n",result_1->clusters_len);
int j;
for(j=0;j<result_1->clusters_len;j++){
printf("cluster #%d: %s#runlevel %d\n",j,result_1->clusters_val[j].name,result_1->clusters_val[j].debuglevel);
}
}
clnt_destroy( clnt );
}
as a result, we get some nice values on the clientside printed
and of course no segfaults anymore on the serverside:
lars$ ./test_client localhost
I got 2 cluster structs in an array
cluster #0: cl1#runlevel 1
cluster #1: cl2#runlevel 2

C structs strange behaviour

I have some long source code that involves a struct definition:
struct exec_env {
cl_program* cpPrograms;
cl_context cxGPUContext;
int cpProgramCount;
int cpKernelCount;
int nvidia_platform_index;
int num_cl_mem_buffs_used;
int total;
cl_platform_id cpPlatform;
cl_uint ciDeviceCount;
cl_int ciErrNum;
cl_command_queue commandQueue;
cl_kernel* cpKernels;
cl_device_id *cdDevices;
cl_mem* cmMem;
};
The strange thing, is that the output of my program is dependent on the order in which I declare the components of this struct. Why might this be?
EDIT:
Some more code:
int HandleClient(int sock) {
struct exec_env my_env;
int err, cl_err;
int rec_buff [sizeof(int)];
log("[LOG]: In HandleClient. \n");
my_env.total = 0;
//in anticipation of some cl_mem buffers, we pre-emtively init some. Later, we should have these
//grow/shrink dynamically.
my_env.num_cl_mem_buffs_used = 0;
if ((my_env.cmMem = (cl_mem*)malloc(MAX_CL_BUFFS * sizeof(cl_mem))) == NULL)
{
log("[ERROR]:Failed to allocate memory for cl_mem structures\n");
//let the client know
replyHeader(sock, MALLOC_FAIL, UNKNOWN, 0, 0);
return EXIT_FAILURE;
}
my_env.cpPlatform = NULL;
my_env.ciDeviceCount = 0;
my_env.cdDevices = NULL;
my_env.commandQueue = NULL;
my_env.cxGPUContext = NULL;
while(1){
log("[LOG]: Awaiting next packet header... \n");
//read the first 4 bytes of the header 1st, which signify the function id. We later switch on this value
//so we can read the rest of the header which is function dependent.
if((err = receiveAll(sock,(char*) &rec_buff, sizeof(int))) != EXIT_SUCCESS){
return err;
}
log("[LOG]: Got function id %d \n", rec_buff[0]);
log("[LOG]: Total Function count: %d \n", my_env.total);
my_env.total++;
//now we switch based on the function_id
switch (rec_buff[0]) {
case CREATE_BUFFER:;
{
//first define a client packet to hold the header
struct clCreateBuffer_client_packet my_client_packet_hdr;
int client_hdr_size_bytes = CLI_PKT_HDR_SIZE + CRE_BUFF_CLI_PKT_HDR_EXTRA_SIZE;
//buffer for the rest of the header (except the size_t)
int header_rec_buff [(client_hdr_size_bytes - sizeof(my_client_packet_hdr.buff_size))];
//size_t header_rec_buff_size_t [sizeof(my_client_packet_hdr.buff_size)];
size_t header_rec_buff_size_t [1];
//set the first field
my_client_packet_hdr.std_header.function_id = rec_buff[0];
//read the rest of the header
if((err = receiveAll(sock,(char*) &header_rec_buff, (client_hdr_size_bytes - sizeof(my_client_packet_hdr.std_header.function_id) - sizeof(my_client_packet_hdr.buff_size)))) != EXIT_SUCCESS){
//signal the client that something went wrong. Note we let the client know it was a socket read error at the server end.
err = replyHeader(sock, err, CREATE_BUFFER, 0, 0);
cleanUpAllOpenCL(&my_env);
return err;
}
//read the rest of the header (size_t)
if((err = receiveAll(sock, (char*)&header_rec_buff_size_t, sizeof(my_client_packet_hdr.buff_size))) != EXIT_SUCCESS){
//signal the client that something went wrong. Note we let the client know it was a socket read error at the server end.
err = replyHeader(sock, err, CREATE_BUFFER, 0, 0);
cleanUpAllOpenCL(&my_env);
return err;
}
log("[LOG]: Got the rest of the header, packet size is %d \n", header_rec_buff[0]);
log("[LOG]: Got the rest of the header, flags are %d \n", header_rec_buff[1]);
log("[LOG]: Buff size is %d \n", header_rec_buff_size_t[0]);
//set the remaining fields
my_client_packet_hdr.std_header.packet_size = header_rec_buff[0];
my_client_packet_hdr.flags = header_rec_buff[1];
my_client_packet_hdr.buff_size = header_rec_buff_size_t[0];
//get the payload (if one exists)
int payload_size = (my_client_packet_hdr.std_header.packet_size - client_hdr_size_bytes);
log("[LOG]: payload_size is %d \n", payload_size);
char* payload = NULL;
if(payload_size != 0){
if ((payload = malloc(my_client_packet_hdr.buff_size)) == NULL){
log("[ERROR]:Failed to allocate memory for payload!\n");
replyHeader(sock, MALLOC_FAIL, UNKNOWN, 0, 0);
cleanUpAllOpenCL(&my_env);
return EXIT_FAILURE;
}
if((err = receiveAllSizet(sock, payload, my_client_packet_hdr.buff_size)) != EXIT_SUCCESS){
//signal the client that something went wrong. Note we let the client know it was a socket read error at the server end.
err = replyHeader(sock, err, CREATE_BUFFER, 0, 0);
free(payload);
cleanUpAllOpenCL(&my_env);
return err;
}
}
//make the opencl call
log("[LOG]: ***num_cl_mem_buffs_used before***: %d \n", my_env.num_cl_mem_buffs_used);
cl_err = h_clCreateBuffer(&my_env, my_client_packet_hdr.flags, my_client_packet_hdr.buff_size, payload, &my_env.cmMem);
my_env.num_cl_mem_buffs_used = (my_env.num_cl_mem_buffs_used+1);
log("[LOG]: ***num_cl_mem_buffs_used after***: %d \n", my_env.num_cl_mem_buffs_used);
//send back the reply with the error code to the client
log("[LOG]: Sending back reply header \n");
if((err = replyHeader(sock, cl_err, CREATE_BUFFER, 0, (my_env.num_cl_mem_buffs_used -1))) != EXIT_SUCCESS){
//send the header failed, so we exit
log("[ERROR]: Failed to send reply header to client, %d \n", err);
log("[LOG]: OpenCL function result was %d \n", cl_err);
if(payload != NULL) free(payload);
cleanUpAllOpenCL(&my_env);
return err;
}
//now exit if failed
if(cl_err != CL_SUCCESS){
log("[ERROR]: Error executing OpenCL function clCreateBuffer %d \n", cl_err);
if(payload != NULL) free(payload);
cleanUpAllOpenCL(&my_env);
return EXIT_FAILURE;
}
}
break;
Now what's really interesting is the call to h_clCreateBuffer. This function is as follows
int h_clCreateBuffer(struct exec_env* my_env, int flags, size_t size, void* buff, cl_mem* all_mems){
/*
* TODO:
* Sort out the flags.
* How do we store cl_mem objects persistantly? In the my_env struct? Can we have a pointer int the my_env
* struct that points to a mallocd area of mem. Each malloc entry is a pointer to a cl_mem object. Then we
* can update the malloced area, growing it as we have more and more cl_mem objects.
*/
//check that we have enough pointers to cl_mem. TODO, dynamically expand if not
if(my_env->num_cl_mem_buffs_used == MAX_CL_BUFFS){
return CL_MEM_OUT_OF_RANGE;
}
int ciErrNum;
cl_mem_flags flag;
if(flags == CL_MEM_READ_WRITE_ONLY){
flag = CL_MEM_READ_WRITE;
}
if(flags == CL_MEM_READ_WRITE_OR_CL_MEM_COPY_HOST_PTR){
flag = CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR;
}
log("[LOG]: Got flags. Calling clCreateBuffer\n");
log("[LOG]: ***num_cl_mem_buffs_used before in function***: %d \n", my_env->num_cl_mem_buffs_used);
all_mems[my_env->num_cl_mem_buffs_used] = clCreateBuffer(my_env->cxGPUContext, flag , size, buff, &ciErrNum);
log("[LOG]: ***num_cl_mem_buffs_used after in function***: %d \n", my_env->num_cl_mem_buffs_used);
log("[LOG]: Finished clCreateBuffer with id: %d \n", my_env->num_cl_mem_buffs_used);
//log("[LOG]: Finished clCreateBuffer with id: %d \n", buff_counter);
return ciErrNum;
}
The first time round the while loop, my_env->num_cl_mem_buffs_used is increased by 1. However, the next time round the loop, after the call to clCreateBuffer, the value of my_env->num_cl_mem_buffs_used gets reset to 0. This does not happen when I change the order in which I declare the members of the struct! Thoughts? Note that I've omitted the other case statements, all of which so similar things, i.e. updating the structs members.
Well, if your program dumps the raw memory content of the object of your struct type, then the output will obviously depend on the ordering of the fields inside your struct. So, here's one obvious scenario that will create such a dependency. There are many others.
Why are you surprised that the output of your program depends on that order? In general, there's nothing strange in that dependency. If you base your verdict of on the knowledge of the rest of the code, then I understand. But people here have no such knowledge and we are not telepathic.
It's hard to tell. Maybe you can post some code. If I had to guess, I'd say you were casting some input file (made of bytes) into this struct. In that case, you must have the proper order declared (usually standardized by some protocol) for your struct in order to properly cast or else risk invalidating your data.
For example, if you have file that is made of two bytes and you are casting the file to a struct, you need to be sure that your struct has properly defined the order to ensure correct data.
struct example1
{
byte foo;
byte bar;
};
struct example2
{
byte bar;
byte foo;
};
//...
char buffer[];
//fill buffer with some bits
(example1)buffer;
(example2)buffer;
//those two casted structs will have different data because of the way they are defined.
In this case, "buffer" will always be filled in the same manner, as per some standard.
Of course the output depends on the order. Order of fields in a struct matters.
An additional explanation to the other answers posted here: the compiler may be adding padding between fields in the struct, especially if you are on a 64 bit platform.
If you are not using binary serialization, then your best bet is an invalid pointer issue. Like +1 error, or some invalid pointer arithmetics can cause this. But it is hard to know without code. And it is still hard to know, even with the code. You may try to use some kind of pointer validation/tracking system to be sure.
other guesses
by changing the order you are having different uninitialized values in the struct. A pointer being zero or not zero for example
you somehow manage to overrun an item (by casting ) and blast later items. Different items get blasted depending on order
This may happen if your code uses on "old style" initializer as from C89. For a simple example
struct toto {
unsigned a;
double b;
};
.
.
toto A = { 0, 1 };
If you interchange the fields in the definition this remains a valid initializer, but your fields are initialized completely different. Modern C, AKA C99, has designated initializers for that:
toto A = { .a = 0, .b = 1 };
Now, even when reordering your fields or inserting a new one, your initialization remains valid.
This is a common error which is perhaps at the origin of the initializerphobia that I observe in many C89 programs.
You have 14 fields in your struct, so there is 14! possible ways the compiler and/or standard C library can order them during the output.
If you think from the compiler designer's point of view, what should the order be? Random is certainly not useful. The only useful order is the order in which the struct fields were declared by you.

asynchronous serial port communication in windows in c

I am getting an error when I try to run a c file which does some basic writes to a serial port. I am trying to run it asynchronously because the writes sometimes take a long time to transfer. My original version had it running synchronously with WriteFile() commands which worked fine. I am new to using OVERLAPPED and would appreciate and input concerning it.
The error I am getting is:
Debug Assertion Failed!
<path to dbgheap.c>
Line: 1317
Expression: _CrtIsValidHeapPointer(pUserData)
when the second write function is called.
In main:
{
//initialized port (with overlapped), DBC, and timeouts
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
}
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) {
//write completed. check for errors? if so throw an exception maybe?
printf("write completed--and made it to callback function\n");
}
int write_port(HANDLE hComm,BYTE* lpBuf) {
OVERLAPPED osWrite = {0};
// Create this write operation's OVERLAPPED structure's hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// error creating overlapped event handle
return 0;
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, 1, &osWrite, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
// Write is pending.
WaitForSingleObjectEx(osWrite.hEvent, 50, TRUE); //50 ms timeout
return -1; //pending
}
}
else {
return 1; //finished
}
}
That was not the full code, sorry. I was using an array of BYTEs as well, not constants. But system("pause")'s were causing my debug assertion failed errors, and after carefully looking through my code, when the WriteFileEx() was successful, it was never setting an alert/timeout on the event in the overlapped structure, so the callback function would never get called. I fixed these problems though.
I just need help with the handling/accessing a single BYTE in a structure which is allocated when a ReadFileEx() function is called (for storing the BYTE that is read so it can be handled). I need to know how to access that BYTE storage using an offset and make the overlapped structure null. Would making the overlapped structure null be as simple as setting the handle in it to INVALID_HANDLE_VALUE?
I think you have a couple of issues:
You are passing an integer as a pointer (your compiler should warn against this or preferably refuse to compile the code):
result = write_port(outPortHandle, 128);
Compare this to the definition of write_port:
int write_port(HANDLE hComm,BYTE* lpBuf) {
The above statements doesn't match. Later on you then pass a pointer to the lpBuf pointer to the WriteFileEx function by taking the address of the BYTE* -> "&lpBuf". This will not result in what you think it will do.
Even if you fix this, you will still have potential lifetime issues whenever the write is successfully queued but won't complete within the 50 ms timeout.
When using overlapped I/O, you need to make sure that the read/write buffer and the overlapped structure remain valid until the I/O is completed, cancelled or the associated device is closed. In your code above you use a pointer to an OVERLAPPED struct that lives on the stack in your call to WriteFileEx. If WriteFileEx does not complete within 50 ms, the pending I/O will have a reference to a non-existing OVERLAPPED struct and you will (hopefully) have an access violation (or worse, silently corrupted stack data somewhere in your app).
The canonical way of handling these lifetime issues (if performance is not a big issue), is to use a custom struct that includes an OVERLAPPED struct and some storage for the data to be read/written. Allocate the struct when posting the write and deallocate the struct from the I/O completion routine. Pass the address of the included OVERLAPPED struct to WriteFileEx, and use e.g. offsetof to get the address to the custom struct from the OVERLAPPED address in the completion routine.
Also note that WriteFileEx does not actually use the hEvent member, IIRC.
EDIT: Added code sample, please note:
I haven't actually tried to compile the code, there might be typos or other problems with the code.
It's not the most efficient way of sending data (allocating/deallocating a memory block for each byte that is sent). It should be easy to improve, though.
#include <stddef.h>
#include <assert.h>
#include <windows.h>
// ...
typedef struct _MYOVERLAPPED
{
OVERLAPPED ol;
BYTE buffer;
} MYOVERLAPPED, *LPMYOVERLAPPED;
// ...
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
if (NULL == lpOverlapped)
{
assert(!"Should never happen");
return;
}
LPBYTE pOlAsBytes = (LPBYTE)lpOverlapped;
LPBYTE pMyOlAsBytes = pOlAsBytes - offsetof(MYOVERLAPPED, ol);
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)pOlAsBytes;
if ((ERROR_SUCCESS == dwErrorCode) &&
(sizeof(BYTE) == dwNumberOfBytesTransfered))
{
printf("written %uc\n", pMyOl->buffer);
}
else
{
// handle error
}
free(pMyOl);
}
int write_port(HANDLE hComm, BYTE byte) {
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)malloc(sizeof(MYOVERLAPPED));
ZeroMemory(pMyOl, sizeof(MYOVERLAPPED));
pMyOl->buffer = byte;
// Issue write.
if (!WriteFileEx(hComm, &pMyOl->buffer, sizeof(BYTE), pMyOl, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
free(pMyOl);
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
return -1; //pending
}
}
else {
free(pMyOl);
return 1; //finished
}
}
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
The lpBuf argument have to be pointers to buffers, not constants.
e.g.
char buffer;
buffer = 128;
result = write_port(outPortHandle, &buffer);
buffer = 131;
result = write_port(outPortHandle, &buffer);
What you really want to do is also pass a buffer length.
e.g.
char buffer[] = { 128, 131 };
result = write_port(outPortHandle, &buffer, sizeof(buffer));
int write_port(HANDLE hComm,BYTE* lpBuf, size_t length) {
...
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, length, &osWrite, &write_compl )) {
...

Resources