I am a noob in serial programming and I am trying to build a com port sniffer to sniff bytes between two ports by using pthreads. I am using com0com emulator for the com ports. The emulator creates COM ports in connected pairs. At first, I wanted to sniff using this scenario:
Application1<--->COM3<--->Sniffer<--->COM4<--->Application2
However, I am unable to read what goes on between the two ports even when I set the ports in the code to non-exclusive mode before the running the application, also, the applications are unable to access the ports (error is "Access Denied").
I tried to this scenario:
Application1<--->COM3<--->COM4<--->Sniffer<--->COM5<--->COM4<--->Application2
With this, code is able to read COM4 and COM5 while the applications take COM3 and COM4. In this scenario, I am able to see the bytes and write in one direction with one thread. But when I try to use two threads to ensure bi-directional communication, it fails at the first read.
Code for the second scenario:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <pthread.h>
void setupPort(HANDLE * handle, char * portName);
void * readFromPort(void * handles);
void writeToPort(HANDLE * handle, char data[]);
typedef struct
{
HANDLE from;
HANDLE to;
} bi_ports;
int main()
{
HANDLE first_port, second_port;
char * first_port_name = "COM4";
char * second_port_name = "COM5";
bi_ports *ports_first, *ports_second;
pthread_t firstToSecondThread, secondToFirstThread;
setupPort(&first_port, first_port_name);
setupPort(&second_port, second_port_name);
ports_first = (bi_ports *) malloc(sizeof(bi_ports));
ports_second = (bi_ports *) malloc(sizeof(bi_ports));
ports_first->from = first_port;
ports_first->to = second_port;
ports_second->from = second_port;
ports_second->to = first_port;
pthread_create(&firstToSecondThread, NULL, readFromPort, (void *) ports_first);
pthread_create(&secondToFirstThread, NULL, readFromPort, (void *) ports_second);
pthread_join(firstToSecondThread, NULL);
pthread_join(secondToFirstThread,NULL);
return 0;
}
void setupPort(HANDLE * handle, char * portName)
{
BOOL status;
*handle = CreateFile(portName, //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING,// Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (handle == INVALID_HANDLE_VALUE)
{
printf("\n%s could not be opened\n", portName);
}
else
{
printf("\n%s successfully opened.\n", portName);
}
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
status = GetCommState(*handle, &dcbSerialParams); //retreives the current settings
if (status == FALSE)
printf("\n Error! in GetCommState()");
dcbSerialParams.BaudRate = CBR_9600; // Setting BaudRate = 9600
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
status = SetCommState(*handle, &dcbSerialParams); //Configuring the port according to settings in DCB
if (status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
}
else //If Successful display the contents of the DCB Structure
{
printf("\n\n Setting DCB Structure Successful\n");
printf("\n Baudrate = %d", dcbSerialParams.BaudRate);
printf("\n ByteSize = %d", dcbSerialParams.ByteSize);
printf("\n StopBits = %d", dcbSerialParams.StopBits);
printf("\n Parity = %d", dcbSerialParams.Parity);
}
/*------------------------------------ Setting Timeouts --------------------------------------------------*/
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(*handle, &timeouts) == FALSE)
printf("\n\n Error! in Setting Time Outs");
else
printf("\n\n Setting Serial Port Timeouts Successful");
/*------------------------------------ Setting Receive Mask ----------------------------------------------*/
status = SetCommMask(*handle, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (status == FALSE)
printf("\n\n Error! in Setting CommMask");
else
printf("\n\n Setting CommMask successful");
}
void * readFromPort(void * handles)
{
bi_ports* ports;
ports = (bi_ports*) handles;
HANDLE handleFrom;
HANDLE handleTo;
handleFrom = ports->from;
handleTo = ports->to;
BOOL status;
DWORD dwEventMask; // Event mask to trigger
char TempChar; // Temporary Character
char SerialBuffer[256]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
int i = 0;
DWORD dNoOFBytestoWrite;
DWORD dNoOfBytesWritten = 0; // No of bytes written to the port
/*------------------------------------ Setting WaitComm() Event ----------------------------------------*/
while(TRUE)
{
printf("\n\n Waiting for Data Reception");
status = TRUE;//WaitCommEvent(handleFrom, &dwEventMask, NULL); //Wait for the character to be received
/*-------------------------- Program will Wait here till a Character is received ------------------------*/
if (status == FALSE)
{
printf("\n Error! in Setting WaitCommEvent()");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
printf("\n\n Characters Received\n");
do
{
status = ReadFile(handleFrom, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
SerialBuffer[i] = TempChar;
i++;
}
while (NoBytesRead > 0);
/*------------Printing the RXed String to Console----------------------*/
if(NoBytesRead > 0){
printf("\n\n ");
int j =0;
for (j = 0; j < i-1; j++) // j < i-1 to remove the dupliated last character
{
printf("%02X", (unsigned int)(unsigned char)SerialBuffer[j]);
}
dNoOFBytestoWrite = sizeof(SerialBuffer);
status = WriteFile(handleTo, // Handle to the Serialport
SerialBuffer, // Data to be written to the port
dNoOFBytestoWrite, // No of bytes to write into the port
&dNoOfBytesWritten, // No of bytes written to the port
NULL);
if (status == TRUE)
{
printf("\n\n %X - Written to port", (unsigned int)(unsigned char)SerialBuffer);
}
else
{
printf("\n\n Error %d in Writing to Serial Port",GetLastError());
}
//CloseHandle(handleTo);
i=0;
}
}
//CloseHandle(handleFrom);//Closing the Serial Port
printf("\n +==========================================+\n");
}
}
Related
I'm trying to create a simple Serial communication in C. I'm having some problems when receiving the data. I appears that the buffer size is not correct, or the data is not being retrieved from the Serial.
This is how I have created the code:
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#define BUFFERLENGTH 256
int main () {
HANDLE comm;
BOOL wComm;
char buf[] = "abcd1234 \r\n";
DWORD dwNoBytesToWrite = sizeof(buf);
DWORD dwNoBytesWritten = 0;
BOOL Read_Status;
DWORD dwEventMask;
char SerialBuffer[BUFFERLENGTH+1];
char finalStr[BUFFERLENGTH+1] = "";
DWORD NoBytesRead;
int i = 0;
comm = CreateFileA("\\\\.\\COM7",
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING,// Open existing port only
0, // Non Overlapped I/O
NULL);
if (comm == INVALID_HANDLE_VALUE)
printf("Error in opening serial port");
else
printf("opening serial port successful");
// set short timeouts on the comm port.
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(comm, &timeouts))
printf("setting port time-outs.");
//Config
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Write_Status = GetCommState(comm, &dcbSerialParams); //retreives the current settings
if (Write_Status == FALSE) {
printf("\n Error! in GetCommState()");
CloseHandle(comm);
return 1;
}
dcbSerialParams.BaudRate = CBR_57600; // Setting BaudRate = 9600
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
//dcbSerialParams.
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = ODDPARITY; // Setting Parity = None
// Write Serial
wComm = WriteFile(
comm,
buf,
dwNoBytesToWrite,
&dwNoBytesWritten,
NULL
);
if (!wComm)
{
printf("Problem writing to comm");
}
// MASK
Read_Status = SetCommMask(comm, EV_RXCHAR);
if (Read_Status == FALSE)
printf("\n\nError! in Setting CommMask");
else
printf("\n\nSetting CommMask successfull");
// WAITING DATA
printf("\n\nWaiting for Data Reception");
Read_Status = WaitCommEvent(comm, &dwEventMask, NULL);
if (Read_Status == FALSE)
{
printf("\n Error! in Setting WaitCommEvent()");
}
else
{
//fflush(stdin);
printf("\n\nCharacters Received\n");
do
{
if (ReadFile(comm, SerialBuffer, BUFFERLENGTH, &NoBytesRead, NULL))
{
printf("%c", SerialBuffer[i]);
strcat(finalStr, SerialBuffer[i]);
i++;
}
} while (NoBytesRead > 0);
}
CloseHandle(comm);
return 0;
}
Here is what I'm receiving as the response:
I've created a button that sends bytes to turn on LEDs for multiple similar devices. What I have found out is that if I don't close the handle I get instantaneous speed which is exactly what I need, but of course, if I don't close it I can't use it anymore meaning the button only works once. If I do close the handle it works, but much slower to the point where I can see the LEDs turn on one by one. How to go about this?
Here's the code for the sendBytes function, the code for the GUI is unnecessary because I get the same speed with a barebones C console program.
int sendBytes(char* command, char* COM) {
HANDLE hSerial2;
BOOL Write_Status;
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
hSerial2 = CreateFileA(COM,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // no security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // not overlapped I/O
NULL // hTemplate must be NULL for comm devices
);
printf("opening serial port successful");
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Write_Status = GetCommState(hSerial2, &dcbSerialParams); //retreives the current settings
if (Write_Status == FALSE) {
printf("\n Error! in GetCommState()");
CloseHandle(hSerial2);
return 1;
}
dcbSerialParams.BaudRate = CBR_57600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
Write_Status = SetCommState(hSerial2, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Write_Status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
CloseHandle(hSerial2);
return 1;
}
// Set COM port timeout settings
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hSerial2, &timeouts) == 0)
{
// printf("Error setting timeouts\n");
CloseHandle(hSerial2);
return 1;
}
///*----------------------------- Writing a Character to Serial Port----------------------------------------*/
int length = strlen(command);
char send[20];
strcpy(send, command);
send[length + 1] = 13;
send[length + 2] = 10;
DWORD dNoOFBytestoWrite; // No of bytes to write into the port
DWORD dNoOfBytesWritten = 0; // No of bytes written to the port
dNoOFBytestoWrite = length + 2; // Calculating the no of bytes to write into the port
if (!WriteFile(hSerial2, send, dNoOFBytestoWrite,
&dNoOfBytesWritten, NULL))
{
printf("Error writing text to %s\n", COM);
}
else
{
printf("\n %d bytes written to %s\n", dNoOfBytesWritten, COM);
}
CloseHandle(hSerial2);//Closing the Serial Port
printf("\n ==========================================\n");
return 0;
}
I managed to find a solution, it's fairly simple.
All I did was create a HANDLE variable for each device, initialized them with the corresponding COM port and passed that HANDLE to a slightly modified sendBytes function so it doesn't have to close and create a new one each time it's called when you press the button.
The problem now is that reading bytes is slow, here's the code:
int sendBytes(char* command, char* COM, HANDLE hSerial, int read) {
BOOL Write_Status;
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Write_Status = GetCommState(hSerial, &dcbSerialParams); //retreives the current settings
if (Write_Status == FALSE) {
printf("\n Error! in GetCommState()");
CloseHandle(hSerial);
return 1;
}
dcbSerialParams.BaudRate = CBR_57600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
Write_Status = SetCommState(hSerial, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Write_Status == FALSE)
{
CloseHandle(hSerial);
return 1;
}
///*----------------------------- Writing a Character to Serial Port----------------------------------------*/
int length = strlen(command);
char send[20];
strcpy(send, command);
send[length + 1] = 13;
send[length + 2] = 10;
DWORD dNoOFBytestoWrite; // No of bytes to write into the port
DWORD dNoOfBytesWritten = 0; // No of bytes written to the port
dNoOFBytestoWrite = length + 2; // Calculating the no of bytes to write into the port
if (!WriteFile(hSerial, send, dNoOFBytestoWrite, &dNoOfBytesWritten, NULL))
printf("Error writing text to %s\n", COM);
if (read) {
int maxChars = 256;
BOOL Read_Status; // Status of the various operations
DWORD dwEventMask; // Event mask to trigger
char SerialBuffer[256]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
///*------------------------------------ Setting Receive Mask ----------------------------------------------*/
Read_Status = SetCommMask(hSerial, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (Read_Status == FALSE)
printf("\n\n Error! in Setting CommMask");
else
printf("\n\n Setting CommMask successfull");
///*------------------------------------ Setting WaitComm() Event ----------------------------------------*/
printf("\n\n Waiting for Data Reception");
Read_Status = WaitCommEvent(hSerial, &dwEventMask, NULL); //Wait for the character to be received
// /*-------------------------- Program will Wait here till a Character is received ------------------------*/
if (Read_Status == FALSE)
{
printf("\n Error! in Setting WaitCommEvent()");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
printf("\n\n Characters Received \t");
if (!ReadFile(hSerial, SerialBuffer, maxChars, &NoBytesRead, NULL))
{
printf("wrong character");
return 1;
}
printf("noBytes: %d\n", NoBytesRead);
/*------------Printing the RXed String to Console----------------------*/
int j = 0;
char readArray[256];
while (SerialBuffer[j] != '\r') {
printf("%c", SerialBuffer[j]);
readArray[j] = SerialBuffer[j];
j++;
}
readArray[j++] = '\0';
}
}
}
I am using the code found here to receive data from an ATmega microcontroller to my PC. The code "USB2SERIAL_Read_W32.c" handles the Windows COM ports and receives serial data, which it then prints to the console.
I tried to modify the code to run continuously, i.e. to wait for data, print them when it receives characters, and then return to waiting for new data.
Here you can see the code, with my interventions.
#include <Windows.h>
#include <stdio.h>
void main(void)
{
HANDLE hComm; // Handle to the Serial port
char ComPortName[] = "\\\\.\\COM9"; // Name of the Serial port(May Change) to be opened,
BOOL Status; // Status of the various operations
DWORD dwEventMask; // Event mask to trigger
char TempChar; // Temperory Character
char SerialBuffer[256]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
int i = 0;
int counter=0;
printf("\n\n +==========================================+");
printf("\n | Serial Port Reception (Win32 API) |");
printf("\n +==========================================+\n");
/*---------------------------------- Opening the Serial Port -------------------------------------------*/
hComm = CreateFile( ComPortName, // Name of the Port to be Opened
GENERIC_READ | GENERIC_WRITE, // Read/Write Access
0, // No Sharing, ports cant be shared
NULL, // No Security
OPEN_EXISTING, // Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
printf("\n Error! - Port %s can't be opened\n", ComPortName);
else
printf("\n Port %s Opened\n ", ComPortName);
/*------------------------------- Setting the Parameters for the SerialPort ------------------------------*/
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Status == FALSE)
printf("\n Error! in GetCommState()");
dcbSerialParams.BaudRate = CBR_9600; // Setting BaudRate = 9600
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
Status = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
}
else //If Successfull display the contents of the DCB Structure
{
printf("\n\n Setting DCB Structure Successfull\n");
printf("\n Baudrate = %d", dcbSerialParams.BaudRate);
printf("\n ByteSize = %d", dcbSerialParams.ByteSize);
printf("\n StopBits = %d", dcbSerialParams.StopBits);
printf("\n Parity = %d", dcbSerialParams.Parity);
}
/*------------------------------------ Setting Timeouts --------------------------------------------------*/
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
if (SetCommTimeouts(hComm, &timeouts) == FALSE)
printf("\n\n Error! in Setting Time Outs");
else
printf("\n\n Setting Serial Port Timeouts Successfull");
/*------------------------------------ Setting Receive Mask ----------------------------------------------*/
dwEventMask=EV_RXCHAR;
Status = SetCommMask(hComm, dwEventMask); //Configure Windows to Monitor the serial device for Character Reception
if (Status == FALSE)
printf("\n\n Error! in Setting CommMask");
else
printf("\n\n Setting CommMask successfull");
/*------------------------------------ Setting WaitComm() Event ----------------------------------------*/
while(1){
int j =0;
i=0;
for(j=0;j<sizeof(SerialBuffer);j++){ //Clear SerialBuffer
SerialBuffer[j]=0;
}
printf("\n\n Waiting for Data Reception");
Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received
/*-------------------------- Program will Wait here till a Character is received ------------------------*/
if (Status == FALSE){
printf("\n Error! in Setting WaitCommEvent()");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
printf("\n\n Characters Received");
do{
Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
if(Status==TRUE){
if(NoBytesRead>0){
SerialBuffer[i] = TempChar;
}
i++;
}
else
printf("\n Error! in Setting ReadFile()");
}while (NoBytesRead);
/*------------Printing the RXed String to Console----------------------*/
printf("\n\n ");
for (j = 0; j < strlen(SerialBuffer); j++)
printf("%c", SerialBuffer[j]);
}
//CloseHandle(hComm);//Closing the Serial Port
printf("\n +==========================================+\n");
}
}//End of Main()
The changes I did were to add the while(1) loop, clear the buffer at the start of each loop, commented out the closing of the port handler, changed the timeouts as mentioned in the "Timeouts" section in this microsoft tutorial and few more minor tweaks and cosmetics.
The problem is that for some reason, whenever I receive the string "1234", firstly the expected event is triggered, printing the received characters, and then another event is triggered for some reason, with no characters waiting, as you can see in the following picture:
To sum up, why is the unexpected event triggered and how can I solve it?
EDIT: I haven't managed to find the solution yet, however I am posting a workaround that I found (perhaps it can help someone to spot the initial problem). If I set the Comm Mask to zero, and reset it to EV_RXCHAR in each loop iteration, it seems to work as expected; That is, when I reach the WaitCommEvent line for the second time, it is not automatically triggered as before. The bad thing is that I cannot explain why it works now, and I believe that it should be working correctly in the first place as well. So any help would be greatly appreciated. Here is the code with the workaround, which sets the CommMask to zero and back to EV_RXCHAR:
#include <Windows.h>
#include <stdio.h>
void main(void){
printf("Hello!\n");
DWORD dwCommEvent;
DWORD dwRead;
DWORD lpEvtMask;
char chRead;
char ComPortName[] = "\\\\.\\COM9"; // Name of the Serial port(May Change) to be opened,
int i=0;
HANDLE hComm;
hComm = CreateFile( ComPortName,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);
if (hComm == INVALID_HANDLE_VALUE)
printf("Error opening port.\n");
//////////////////////////////////////////////////////
DCB dcb;
FillMemory(&dcb, sizeof(dcb), 0);
if (!GetCommState(hComm, &dcb)) // get current DCB
printf("Error GetCommState.\n");
// Update DCB rate.
dcb.BaudRate = CBR_9600 ;
dcb.ByteSize = 8; // Setting ByteSize = 8
dcb.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcb.Parity = NOPARITY; // Setting Parity = None
dcb.DCBlength = sizeof(dcb);
// Set new state.
if (!SetCommState(hComm, &dcb))
printf("Error SetCommState.\n");
// Error in SetCommState. Possibly a problem with the communications
// port handle or a problem with the DCB structure itself.
/////////////////////////////////////////////////////////////////////
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(hComm, &timeouts))
printf("Error timeouts.\n");
if(!PurgeComm(hComm,PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT))
printf("Error PurgeComm.\n");
////////////////////////////////////////
for ( ; ; ) {
if (!SetCommMask(hComm, 0))
printf("Error CommMask.\n");
if (!SetCommMask(hComm, EV_RXCHAR))
printf("Error CommMask.\n");
printf("Waiting for characters.. \n\n");
if (WaitCommEvent(hComm, &dwCommEvent, NULL)) {
do {
if (ReadFile(hComm, &chRead, 1, &dwRead, NULL)){
if(dwRead!=0)
printf("Character Received: %c\n",chRead);
}
else{
printf("ErrorReadFile.\n");
break;
}
}while (dwRead);
}
else{
printf("Error WaitCommEvent.\n");
break;
}
printf("=========================\n");
}
}
I'm trying to communicate with a board a colleague made via a USB To serial cable.
It works fine when I use teraterm or putty, but I can't get it to work, when I do it with a sample code.
Since I have no idea how to do this - or at least a couple of years ago I did it last - I'm using a piece of code from github: Seerial Programming with Win32API
I know that if I transmit the command: SB50G, an LED should light up. But it doesn't. So I tried to see, if it sends an error back (It should send an 'E' char in case of any error). Though nothing is received. I then tried to transmit the command 'G', which should return a an ASCII string of 8 hex'es.
I don't get any errors upon opening the port, unless I use it in teraterm at the same time.
The code is a merge of the transmitter and receive example:
#include <Windows.h>
#include <stdio.h>
#include <string.h>
void main(void)
{
HANDLE hComm; // Handle to the Serial port
char ComPortName[] = "\\\\.\\COM3"; // Name of the Serial port(May Change) to be opened,
BOOL Status; // Status of the various operations
DWORD dwEventMask; // Event mask to trigger
char TempChar; // Temperory Character
char SerialBuffer[256]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
int i = 0;
printf("\n\n +==========================================+");
printf("\n | Serial Transmission (Win32 API) |");
printf("\n +==========================================+\n");
/*----------------------------------- Opening the Serial Port --------------------------------------------*/
hComm = CreateFile(ComPortName, // Name of the Port to be Opened
GENERIC_READ | GENERIC_WRITE, // Read/Write Access
0, // No Sharing, ports cant be shared
NULL, // No Security
OPEN_EXISTING, // Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
printf("\n Error! - Port %s can't be opened", ComPortName);
else
printf("\n Port %s Opened\n ", ComPortName);
/*------------------------------- Setting the Parameters for the SerialPort ------------------------------*/
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Status == FALSE)
printf("\n Error! in GetCommState()");
dcbSerialParams.BaudRate = CBR_19200; // Setting BaudRate = 9600
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
Status = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
}
else
{
printf("\n Setting DCB Structure Successfull\n");
printf("\n Baudrate = %d", dcbSerialParams.BaudRate);
printf("\n ByteSize = %d", dcbSerialParams.ByteSize);
printf("\n StopBits = %d", dcbSerialParams.StopBits);
printf("\n Parity = %d", dcbSerialParams.Parity);
}
Status = SetCommMask(hComm, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (Status == FALSE)
printf("\n\n Error! in Setting CommMask");
else
printf("\n\n Setting CommMask successfull");
/*------------------------------------ Setting Timeouts --------------------------------------------------*/
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hComm, &timeouts) == FALSE)
printf("\n Error! in Setting Time Outs");
else
printf("\n\n Setting Serial Port Timeouts Successfull");
/*----------------------------- Writing a Character to Serial Port----------------------------------------*/
char lpBuffer[] = "G\r"; // lpBuffer should be char or byte array, otherwise write wil fail
DWORD dNoOFBytestoWrite; // No of bytes to write into the port
DWORD dNoOfBytesWritten = 0; // No of bytes written to the port
dNoOFBytestoWrite = sizeof(lpBuffer); // Calculating the no of bytes to write into the port
Status = WriteFile(hComm, // Handle to the Serialport
lpBuffer, // Data to be written to the port
dNoOFBytestoWrite, // No of bytes to write into the port
&dNoOfBytesWritten, // No of bytes written to the port
NULL);
if (Status == TRUE)
printf("\n\n %s - Written to %s", lpBuffer, ComPortName);
else
printf("\n\n Error %d in Writing to Serial Port", GetLastError());
/*------------------------------------ Setting WaitComm() Event ----------------------------------------*/
printf("\n\n Waiting for Data Reception");
Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received
/*-------------------------- Program will Wait here till a Character is received ------------------------*/
if (Status == FALSE)
{
printf("\n Error! in Setting WaitCommEvent()");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
printf("\n\n Characters Received");
do
{
Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
SerialBuffer[i] = TempChar;
i++;
} while (NoBytesRead > 0);
/*------------Printing the RXed String to Console----------------------*/
printf("\n\n ");
int j = 0;
for (j = 0; j < i - 1; j++) // j < i-1 to remove the dupliated last character
printf("%c", SerialBuffer[j]);
}
CloseHandle(hComm);//Closing the Serial Port
printf("\n +==========================================+\n");
}
Can someone explain to me why it's not working, or any way I can find out why it's not working? The BAUD-rate and such are as they should be.
Best regards.
The problem seemed to be due to the board. After installing a sniffer, i could see the correct data being sent out, but nothin was returned.
Apparently the carriage return needed to be send separat from the data, and then it worked.
Many thanks for the comments, I'll take them in to serious consideration. :)
Here is my code which is basically opening the serial port and reading data from serial port com 5.
` /---------------------------------- Opening the Serial Port -------------------------------------------/
hComm = CreateFile( ComPortName, // Name of the Port to be Opened
GENERIC_READ | GENERIC_WRITE, // Read/Write Access
0, // No Sharing, ports cant be shared
NULL, // No Security
OPEN_EXISTING, // Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
printf("\n Error! - Port %s can't be opened. Please check port is free or not.\n", ComPortName);
else
printf("\n Port %s is Opened\n ", ComPortName);
/------------------------------- Setting the Parameters for the SerialPort ------------------------------/
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Status == FALSE)
printf("\n Error! in GetCommState()");
dcbSerialParams.BaudRate = CBR_9600; // Setting BaudRate = 9600
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
Status = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
}
else //If Successfull display the contents of the DCB Structure
{
printf("\n\n Setting DCB Structure Successfull\n");
printf("\n Baudrate = %d", dcbSerialParams.BaudRate);
printf("\n ByteSize = %d", dcbSerialParams.ByteSize);
printf("\n StopBits = %d", dcbSerialParams.StopBits);
printf("\n Parity = %d\n", dcbSerialParams.Parity);
}
/------------------------------------ Setting Receive Mask ----------------------------------------------/
Status = SetCommMask(hComm, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (Status == FALSE)
printf("\n\n Error! in Setting CommMask");
else
printf("\n\n Setting CommMask successfull");
/------------------------------------ Setting WaitComm() Event ----------------------------------------/
printf("\n\n Waiting for Data Reception");
Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received
/-------------------------- Program will Wait here till a Character is received ------------------------/
if (Status == FALSE)
{
printf("\n Error! in Setting WaitCommEvent()");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
printf("\n\n Characters Received");
do
{
Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
SerialBuffer[i] = TempChar;
i++;
}
while (NoBytesRead > 0);
/*------------Printing the recieved value to Console----------------------*/
printf("\n\n ");
int j =0;
for (j = 0; j < i-1; j++) // j < i-1 to ( '0' ), null or last character
printf("%c", SerialBuffer[j]);
}
getchar();
CloseHandle(hComm);//Closing the Serial Port
return 0;
}//End of Main()
`
And because of Setting Receive Mask and Setting WaitComm() Event.
(Status = SetCommMask(hComm, EV_RXCHAR);
Status = WaitCommEvent(hComm, &dwEventMask, NULL);)
I am receiving values only once. As shown in pic.
Please give me any suggestion how can I receive data from serial port continuously. I am not getting this problem is from these functions or because of buffer size. Any suggestion will be appreciated. Thanks in advance.