I am studing serial communication with win32 using C now. reading from serial port is given as below.
DWORD dwEventMask;
DWORD dwSize;
if(!SetCommMask(hSerial, EV_RXCHAR)){
//Error handling
printf("Error Setting Comm Mask \n");
}
if(WaitCommEvent(hSerial, &dwEventMask, NULL))
{
unsigned char szBuf[1024];
DWORD dwIncommingReadSize;
do
{
if(ReadFile(hSerial, &szBuf, 1, &dwIncommingReadSize, NULL) != 0) {
//Handle Error Condition
}
if(dwIncommingReadSize > 0)
{
dwSize += dwIncommingReadSize;
sb.sputn(&szBuf, dwIncommingReadSize);
printf("Reading from port \n");
}
else{
//Handle Error Condition
}
printf("Reading data from port \n");
} while(dwIncommingReadSize > 0);
}
else
{
//Handle Error Condition
}
They have used DWORD dwIncommingReadSize for while condition (while(dwIncommingReadSize > 0);.
Please explain how this condition is satifisfied. No modification can be seen for that.
Again please explain following part.
if(dwIncommingReadSize > 0)
{
dwSize += dwIncommingReadSize;
sb.sputn(&szBuf, dwIncommingReadSize);
printf("Reading from port \n");
}
This line:
if(ReadFile(hSerial, &szBuf, 1, &dwIncommingReadSize, NULL)
passes the address of dwIncommingReadSize (however badly spelt it may be) to the function so it can change it to whatever it wants.
It's similar to:
void fn (int *x) { *x = 42; }
:
int xyzzy = 1;
fn (&xyzzy);
// Here, xyzzy is now 42.
In terms of your second question, it's a little hard to tell without seeing more of the code, but it looks like it's simply increasing a "total size" variable for each block of data read in (plus whatever sb.sputn is supposed to do).
This is typical where a single read may not get all the data you want - you simply store what you got and then go back for more.
Related
Implementing a data link protocol. I managed to send the whole file through the virtual serial port - which should be the hard part. The weird thing is I'm getting a segfault on fclose() when trying to save it. The file is being created, which means the open is successful, but nothing it being stored in it. Even changed the implementation to buffer all the file into memory before saving it.
int app_rx(const char* outputFile){
file_data_t fileData;
if(!receive_ctrl_pckt(&fileData)){
printf("Could not receive control packet\n");
return FAILURE;
}
printf("Receiving file [%s]\nFile size: %d\n", fileData.fileName, fileData.fileSize);
unsigned char fileBuffer[fileData.fileSize];
int fileIndex = 0;
int totalBytes = 0;
int stop = 0;
size_t sqNo = 0;
int bytes;
FILE* out = fopen(outputFile, "w");
do{
activeBuffer = (activeBuffer + 1) % 2;
printf("Receiving packet %lu\n", sqNo);
bytes = llread(BUFFERS[TMP_BUFFER]);
if(bytes == DUP_ERR){
printf("Duplicate data. Discarding packet\n");
}
else if (bytes == WH_ERR){
printf("Invalid header. Discarding packet\n");
}
else if (bytes == WD_ERR){
printf("Corrupted data. Awaiting retransmission\n");
}
else{
printf("Packet %lu successfully received\n", sqNo);
int retrieveRes = retrieve_payload(sqNo);
switch(retrieveRes){
case CTRL_END: {
stop = 1;
break;
}
case FAILURE: {
printf("Unknown error\nExiting...");
exit(1);
}
case SQ_ERR:{
printf("Unsynchronized packets\nExiting");
exit(1);
}
default:{
for(int i = 0; i < retrieveRes; i++){
fileBuffer[fileIndex] = BUFFERS[activeBuffer][i];
fileIndex++;
}
sqNo = (sqNo + 1) % 255;
totalBytes += bytes;
break;
}
}
}
}while(!stop);
printf("file index: %d\n", fileIndex);
fwrite(fileBuffer, sizeof(unsigned char), fileIndex, out);
printf("here\n");
fclose(out);
if(totalBytes == fileData.fileSize){
return SUCCESS;
}
else{
return FAILURE;
}
}
Stdout:
Packet 9 successfully received
Receiving packet 10
Asserting data integrity
Packet 10 successfully received
Receiving packet 11
Asserting data integrity
Packet 11 successfully received
file index: 10968
here
make: *** [Makefile:35: run_rx] Segmentation fault (core dumped)
Giant method, I know. Just trying to get it under before refactoring properly. Can't for the sake of nothing figure out what's going on. I know this works because I've copied the exact same file using this method with a simple copyfile.c test driver which mimics the cp command.
Any ideas? I find it particularly odd that it creates the output file, but doesn't write anything on it.
EDIT: managed to get it going by opening the file right before writting to it. Still don't quite understand what happened
There is a potential buffer overflow risk for array fileBuffer, except that retrieveRes is guaranteed smaller or equal than fileData.fileSize, if there is a buffer overflow, pointer out may be overwritten and caused a segment fault when call fclose. The buffer overflow can be verified by print the value of out before do/while loop and call to fclose.
I want to connect/bridge two serial ports in C.
I have 2 threads reading the ports, and writing to the other port.
Here is one example:
void *rfid_to_uart_thread(void *) {
char rfid_read_buffer[100];
int writeCounter;
do {
writeCounter = read(rfidCom, rfid_read_buffer, sizeof(rfid_read_buffer)-1);
if (writeCounter > 0) {
write(uartCom, rfid_read_buffer, writeCounter);
} else
usleep(25);
} while (!bKillBridgeThreads);
return NULL;}
The problem is, it seems that the writes are too slow. I often receive only half of the String on the other side. It seems like the write is asynchronously and thus the buffer is overwritten again in the next loop and overwrites the last 'write', so that the data is crippled?!
Is that right?
The ports are opened NON_BLOCKING and RW, Baudrate is and has to be 9600.
Looking at the man:
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
In other wordsread does not grants to return all bytes send by other task, can give you a single byte up to sizeof(rfid_read_buffer)-1
What you can do is:
loop reading from rfidCom until the number of chars matches the number of chars sent.
You can use a specific terminator of messages and check for it to validate received message
encapsulate chars into a protocol message with an header that embed the message length, so the receiver can count the received chars and stop reading when last char is received.
For example:
void *rfid_to_uart_thread(void *)
{
char rfid_read_buffer[100] = {0};
int writeCounter;
char RXchar;
ssize_t retVal;
bool send = false;
do
{
memset(rfid_read_buffer, 0x00, sizeof(rfid_read_buffer));
send = true;
do
{
retVal = read(rfidCom, &RXchar, 1);
if (retVal > 0)
{
rfid_read_buffer[writeCounter] = RXchar;
writeCounter++;
}
else if (retVal < 0)
{
send = false;
RXchar = '\r'
break;
}
else
{
usleep(25);
}
}
while(RXchar != '\r');
if (send)
{
write(uartCom, rfid_read_buffer, writeCounter);
}
}
while (!bKillBridgeThreads);
return NULL;
}
OK, I've found a solution to my problem I think.
void *rfid_to_uart_thread(void *) {
char rfid_read_buffer[10];
ssize_t writeCounter = -1;
do {
writeCounter = read(rfidCom, &rfid_read_buffer, sizeof(rfid_read_buffer)-1);
if (writeCounter>0){
rfid_read_buffer[writeCounter] = 0;
LOGE("RFID -> UART: %s", rfid_read_buffer);
write(uartCom, rfid_read_buffer, writeCounter);
}else{
usleep(25);
}
tcdrain(uartCom);
} while (!bKillBridgeThreads);
return NULL;}
I've created my own define for a tcdrain, because the Android NDK I am using is not offering it in termios.h
Now, all the values seem to get transmitted to the UART port.
tcdrain is now defined as:
#define tcdrain(fd) ioctl(fd, TCSBRK, 1)
I'm trying to get the hang of message queues. For some reason, when displaying the message I typed back into the console, the string sometimes gets truncated, or altered. Does anyone know why this might be occuring?
void *readFromQueue() {
int ret;
mbr = malloc(sizeof(struct msgbuf)); // Allocate space to mbr.
while (TRUE) { // Forever...
ret = (int) msgrcv(msgId, mbr, sizeof(struct msgbuf), myId, MSG_NOERROR | IPC_NOWAIT); // Receive a message
if (ret == -1) { // Check for error.
//perror("Failed to receive message.");
} else {
printf("\t%160s", mbr->mtext);
}
}
}
I discovered that my bug was in my passing of the size of the struct msgbuf instead of the size of msgbuf.mtext.
ret = msgrcv(msgId, mbr, sizeof(mbr->mtext), myId, MSG_NOERROR | IPC_NOWAIT);
I have a C program that trying to read data from COM Port in windows.
I am able to write the data on com port but not able to read it.
This is my read function? if anyone could take a look and point me to correct direction.
I am starting a seperate thread in main method
------ Code of main method function ------
if(!SetCommMask(hSerial,eventFlags)){
printf("Error in setting the event maskwith error: %d \n",GetLastError());}
_beginthread(*readDataFromPort,0,NULL);
----- Code of read data function ------
void readDataFromPort(void*)
{
DWORD dwReadResult;
bool waitOnRead = FALSE;
bool abContinue = TRUE;
memset(&ovRead,0,sizeof(ovRead));
ovRead.hEvent = CreateEvent(0,TRUE,0,0);
if(ovRead.hEvent == NULL){
fprintf(stderr,"Error creating overlapped event for reading");
}
//Reading data from port
while (true){
//Changed the overlap to NULL
if(WaitCommEvent(hSerial,&eventFlags,NULL)){
if(GetCommMask(hSerial,&dwMask)){
ResetEvent(ovRead.hEvent);
if(dwMask == EV_RXCHAR){
printf("character arrived");
}
}
memset(tmp,0,sizeof(tmp));
if(!ReadFile(hSerial, tmp, sizeof(tmp), NULL, &ovRead)){
if(GetLastError()!=ERROR_IO_PENDING){
printf("error io pending: Error is %d\n",GetLastError());
break;
}else{
waitOnRead=TRUE;
}
}
if(waitOnRead){
dwReadResult = WaitForSingleObject(ovRead.hEvent,10000);
switch(dwReadResult){
case WAIT_OBJECT_0:
if(!GetOverlappedResult(hSerial,&ovRead,&dwBytesRead,TRUE)){
printf("Damn error again :-(");
}else{
if(dwBytesRead>0){
++Rx;
printf("Tx - %d: Rx - %d\n",Tx,Rx);
printf("%s",tmp);
}
}
}
}
waitOnRead=FALSE;
}
if(strlen(tmp)>0 && inLoop){
writeDataToPort(*tmp);
}
}
CloseHandle(ovRead.hEvent);
_endthread();
}
> Blockquote
_beginthread(*readDataFromPort,0,NULL);
This snippet starts the thread regardless of SetComMask outcome, but if you are reading OK must have worked.
Check out MSDN threaded port read/write which works (VC5 compile worked straight off out of the box) above code looks really similar though, is it same?.
i have a microcontroller connected to my usb port which i am reading using the code below
`
#include <windows.h>
#include <stdio.h>
#include <conio.h>
int main (void)
{
int n = 25;
char szBuff[25 + 1] = {0};
HANDLE hSerial;
DCB dcbSerialParams = {0};
COMMTIMEOUTS timeouts={0};
DWORD dwBytesRead =25;
dcbSerialParams.DCBlength=sizeof(DCB);
hSerial = CreateFile("COM4",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(hSerial==INVALID_HANDLE_VALUE)
{
if(GetLastError()==ERROR_FILE_NOT_FOUND)
{
puts ("cannot open port!");
return;
}
puts ("invalid handle value!");
return;
}
if (!GetCommState(hSerial, &dcbSerialParams))
{
puts ("error getting state");
return;
}
dcbSerialParams.BaudRate=CBR_57600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams))
{
puts ("error setting port state");
return;
}
timeouts.ReadIntervalTimeout = 30;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.ReadTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hSerial, &timeouts))
{
puts ("timeouts setting fail!");
}
while (1){
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
puts ("serial read error fail!");
return;
}
else
{
printf ("%s\n" , szBuff);
}
}
getch();
return 0;
}
`
i am sending data by this format: $A.B.C$ followed by a newline. so its 7 (or 8, including newline) bytes right? i set the 3rd argument for readfile to 20, greater than 7 bytes so that i can succesfully read all of the data string. however reading sometimes misses a few characters. instead of reading $A.B.C$ i read in one line $A.B.C and in the line after that $ (a hidden'\n'). how can i fix this?
This is normal. When the receive buffer contains at least one byte, you'll get back whatever is in the buffer. Which is usually but a fraction of what you expect, serial ports are quite slow. You'll have to keep reading until you get the full response.
Just to add to the answer, be sure to use some type of timeout, or you will block waiting a character that maybe never comes.
Maybe one option could be reading byte per byte then just wait the last '$' or '\n' to know that you received the complete string and then process it.