this program is to receive and then send data through serial port.
After setting up serial, read a byte from serial(i'm using a tool called putty to send chars), if it is a 'a', read 16byte from a file and then send to serial, and then reads a 'b', and goes on to lettle 'p'. total 16 loops.
but now, i can have the first two loops work, when it comes to the third loop, after readfile(), the readBuff is 50h, while it is what it reads from serial for the first 2 loops, like 'a', 'b'.
it always fails at the 3rd loop.
it is weird, does someone have a clue?
hSerial = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
);
if(hSerial==INVALID_HANDLE_VALUE){
if(GetLastError()==ERROR_FILE_NOT_FOUND){
printf("create serial handle file failed!-1");
return 0;
}
printf("create serial handle file failed!-2");
return 0;
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
dcbSerialParams.fBinary = TRUE;
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams)){
printf("set serial state failed");
return 0;
}
COMMTIMEOUTS cmt;
cmt.ReadIntervalTimeout = 1;
cmt.ReadTotalTimeoutMultiplier = 100000000;
cmt.ReadTotalTimeoutConstant = 100000000;
cmt.WriteTotalTimeoutConstant = 10;
cmt.WriteTotalTimeoutConstant = 10;
if(!SetCommTimeouts(hSerial, &cmt)){
printf("set timeout failed");
return 0;
}
char readBuff; //read 1 byte from serial which indicate the send loop
DWORD dwBytesRead; //number of bytes read from binary
char writeBuff[16]; /*read 16bytes from spd binary to write to serial */
DWORD dwBytesWrite; /*stores actual number of bytes writen*/
for(int i = 0; i<=15; i++){
//initial the variables to 0 incase some weird behavior
readBuff = 0;
dwBytesRead = 0;
dwBytesWrite = 0;
for(int j=0; j<=15; j++)
writeBuff[j] = 0;
if(!ReadFile(hSerial, &readBuff, 1 , &dwBytesRead, NULL)){
if(dwBytesRead != 1){
printf("read failed, please check!\n");
return 0;
}
}
//when it comes to the 3rd loop, readfile() reads a 50h, even if i didn't send anything to serial line.
if(readBuff != ('a' + i)){
printf("failed the %dth loop\n", i);
return 0;
}
else{
//read spd binary then puts to serial
if(fread(writeBuff, 1, 16, file) != 16){
printf("read binary failed, please check!\n");
return 0;
}
//send to serial
if(!WriteFile(hSerial, writeBuff, 16, &dwBytesWrite, NULL)){
if(dwBytesWrite != 16){
printf("write to serial failed, please check!\n");
return 0;
}
}
printf("%c", readBuff);
}
}//end of for loop
If ReadFile fails you need to read again until you have found some valid data. But instead, you check dwBytesRead and makes the decision to continue based on what's in that variable. When ReadFile fails, I wouldn't trust dwBytesRead to contain a valid value. Suppose the UART read 1 byte but got an overrun/framing error?
Change the program to
while(!ReadFile(...))
;
Related
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");
}
}
Well I've been at this program for maybe four hours. I've been trying to create a little program to read what my arduino Uno is spitting out through the serial port.
What I find odd is that the program works only AFTER I've launched the arduino IDE's built in serial monitor. Perhaps this is an issue with initializing the port correctly?
If someone could help me out it'd be much appreciated. The program seems to hang during ReadFile, so maybe there's an issue with permissions...
#include Windows.h>
#include stdio.h>
#include tchar.h>//Removed to allow for stackoverflow format
void printCommState(DCB d);
int main() {
DCB dcb = { 0 };
HANDLE hPort;
BOOL success;
TCHAR *commPort = TEXT("COM3");
char buffer[40] = { 0 };
DWORD dwBytesRead = 0;
DWORD dwBytesWrite = 0;
int l;
/*COMMTIMEOUTS cTimeOut;
cTimeOut.ReadIntervalTimeout = 50;
cTimeOut.ReadTotalTimeoutConstant = 50;
cTimeOut.ReadTotalTimeoutMultiplier = 10;
cTimeOut.WriteTotalTimeoutConstant = 50;
cTimeOut.WriteTotalTimeoutMultiplier = 10;*/
dcb.DCBlength = sizeof(DCB);
dcb.BaudRate = CBR_9600;//Found on microsofts website
dcb.ByteSize = DATABITS_8;// standardized number?
dcb.Parity = NOPARITY;// found in comp management
dcb.StopBits = 1;
/*dcb.fBinary = 1;
dcb.fDtrControl = 1;
dcb.fTXContinueOnXoff = 1;
dcb.fRtsControl = 1;
dcb.XonLim = 2048;
dcb.XoffLim = 512;
dcb.XoffChar = 2;*/
//dcb.fDtrControl = DTR_CONTROL_DISABLE;//maybe unnecessary?
printCommState(dcb);
hPort = CreateFile(commPort, // This comm port is defined by TCHAR so that we can use TEXT() LPFILENAME
GENERIC_READ | GENERIC_WRITE,//DesiredAccess
0,//dwShareMode
NULL,//LPSecurity
CREATE_NEW| OPEN_EXISTING,//dwCreationDisposition
0,//Flags and attributes
NULL);//hTemplateFile
if (hPort == INVALID_HANDLE_VALUE) {
printf("CreateFile failed with the error %d.\n", GetLastError());
scanf_s("%d", &l);
return 1;
}
success = GetCommState(hPort, &dcb);
if (!success) {
printf("GetCommState failed with the error %d.\n ", GetLastError());
scanf_s("%d", &l);
return 2;
}
success = SetCommState(hPort, &dcb);
if (!success) {
printf("SetCommState failed with error %d.\n", GetLastError());
scanf_s("%d", &l);
return 3;
}
/*TIME TO READ STUFF*/
while (GetCommState(hPort, &dcb)) {
printf("We're in the while statement\n");
//+=+=+=+=+=+POSSIBLE PROBLEM?
if (ReadFile(hPort, buffer, 39, &dwBytesRead, NULL)) {
//hFile,lpBuffer,NumberofBytesToRead,LPnumberofbytestoread,lpOverlapped
printf("We're in the ifReadFile Statement!\n");
for (int j = 0; j < sizeof(buffer); j++) {
printf("in the for loop!\n");
printf("%c", buffer[j]);
}
printf("\n");
}
if (!ReadFile(hPort, &buffer, 39, &dwBytesRead, NULL)) {
printf("Error with ReadFile %d\n.", GetLastError());
}
}
scanf_s("%d", &l);
CloseHandle(hPort);
return 0;
}
void printCommState(DCB d) {
printf("\nBaudRate: %d\tByteSize: %d\tParity: %d\tStopBits: %d\n",
d.BaudRate,
d.ByteSize,
d.Parity,
d.StopBits);
}
The issue lies in the GetCommState line of the code
GetCommState code function
Here we have it setting the DCB to the settings returned by that function, so by adding another DCB (dcbRecieving, for instance as an example ) just as an error-catching device and having GetCommState point to that other DCB, we can keep our error catching DCB and set our original to the other one, or set the new parameters after the if statement.
Anyways, thanks a ton!
I'm (synchronously) reading serial input in Windows using ReadFile(), but instead of waiting for the serial port to have input then returning that as I thought it should, ReadFile() instead returns immediately with a value of FALSE, and a GetLastError() of 0. (Yes, I'm certain I have the right error code and am not making syscalls in between).
The ReadFile() documentation says that when the function "is completing asynchronously, the return value is zero (FALSE)." How is it that a synchronous read can be completing asychronously? Why would this be an error? It's worth noting that the data read is garbage data, as one might expect.
More generally, how can I force ReadFile() to behave like a simple synchronous read of a serial port, or at least behave something like the UNIX read()?
Edit: Here is some source code:
HANDLE my_connect(char *port_name)
{
DCB dcb;
COMMTIMEOUTS timeouts;
HANDLE hdl = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
GetCommState(port_name, &dcb);
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if(SetCommState(hdl, &dcb) == 0)
{
fprintf(stderr, "SetCommState failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
/* TODO: Set a variable timeout. */
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 5000; /* wait 5s for input */
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 5000;
if(SetCommTimeouts(hdl, &timeouts) == 0)
{
fprintf(stderr, "SetCommTimeouts failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
return hdl;
}
int my_disconnect(HANDLE hdl)
{
return CloseHandle(hdl);
}
int my_send(HANDLE hdl, char *cmd)
{
DWORD nb = 0;
if(WriteFile(hdl, cmd, strlen(cmd), &nb, NULL) == 0)
{
fprintf(stderr, "WriteFile failed with error code %d.\n",
GetLastError());
return -1;
}
return (int) nb;
}
int my_receive(HANDLE hdl, char *dst, int dstlen)
{
int i;
DWORD r;
BOOL err;
char c = '\0';
for (i = 0; i < dstlen; err = ReadFile(hdl, &c, 1, &r, NULL))
{
if (err == 0)
{
fprintf(stderr, "ReadFile failed with error code %d.\n",
GetLastError());
return -1;
}
if (r > 0)
{
dst[i++] = c;
if (c == '\n') break;
}
}
if (i == dstlen)
{
fprintf(stderr, "Error: read destination buffer not large enough.\
Recommended size: 256B. Your size: %dB.\n", dstlen);
return -1;
}
else
{
dst[i] = '\0'; /* null-terminate the string. */
}
return i;
}
And my test code:
HANDLE hdl = my_connect("COM4");
char *cmd = "/home\n"; /* basic command */
char reply[256];
my_send(hdl, cmd);
my_receive(hdl, reply, 256);
puts(reply);
It's not completing asynchronously. If it were, GetLastError would return ERROR_IO_PENDING.
To do synchronous I/O, open the file without FILE_FLAG_OVERLAPPED.
It should not be possible for ReadFile to fail without a valid GetLastError code. ReadFile only returns false when the driver sets a non-success status code.
I have been attempting to communicate with a device of mine via an RS232 serial port(in my case it is COM6). My code is supposed to write a string of ascii values to the device and then read the response, however I cannot seem to get any response. The program seems to work relatively fine when I have it write and read to a file in my computer, but not for when I designate COM6. Here is the latest edition of my code:
using namespace std;
const char ASCII[ ]= "0123456789ABCDEF";
char *Checksum (char *buffer)
{
static char Hex[10];
static int a1, a2;
register unsigned int i;
int sum;
printf("%s \n", buffer);
sum = 256;
for ( i=0 ; i<strlen(buffer) ; i++ )
{
sum-=buffer[i];
if ( sum<0 )
sum+= 256;
}
a1 = (sum & 0xF0) >> 4;
a2 = sum & 0x0F;
Hex[0] = ASCII[a1];
Hex[1] = ASCII[a2];
Hex[2] = 0;
printf("the checksum is %s \n",Hex);
return(Hex);
}
int main()
{
char data[80], input[80], *data2;
char *response;
DCB dcb;
bool retVal;
DWORD dwBytesTransferred;
DWORD byteswritten;
printf("the variable response is initially: %d\n", response);
dcb.BaudRate = CBR_19200; //19200 Baud
dcb.ByteSize = 8; //8 data bits
dcb.Parity = NOPARITY; //no parity
dcb.StopBits = ONESTOPBIT; //1 stop
//New open port area
HANDLE hPort;
if ((hPort = CreateFile ( "\\\\.\\COM6",
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security attrs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)) != INVALID_HANDLE_VALUE)
{
printf("SUCCESS opening the port\n");// success
}
//GetCommState
DCB Dcb;
GetCommState (hPort, &Dcb);
Dcb.BaudRate = CBR_19200;
Dcb.StopBits = ONESTOPBIT;
Dcb.ByteSize = 8;
Dcb.Parity = NOPARITY;
Dcb.fParity = 0;
Dcb.fOutxCtsFlow = 0;
Dcb.fOutxDsrFlow = 0;
Dcb.fDsrSensitivity = 0;
Dcb.fTXContinueOnXoff = TRUE;
Dcb.fOutX = 0;
Dcb.fInX = 0;
Dcb.fNull = 0;
Dcb.fErrorChar = 0;
Dcb.fAbortOnError = 0;
Dcb.fRtsControl = RTS_CONTROL_DISABLE;
Dcb.fDtrControl = DTR_CONTROL_DISABLE;
//Flushing
FlushFileBuffers( hPort );
PurgeComm (hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
COMSTAT comStat;
DWORD dwErrorFlags;
ClearCommError ( hPort, &dwErrorFlags, &comStat );
//NEW commtimeouts area
COMMTIMEOUTS CommTimeOuts;
DWORD dwTimeout = 3000; // <- set timeout in milliseconds
if(!dwTimeout)
{ // Don't use timeout -> Read the bytes already in input buffer and return immediately
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
} else
{ // Use given timeout, wait until the requested number of bytes are read - or timeout
CommTimeOuts.ReadIntervalTimeout = 0;
CommTimeOuts.ReadTotalTimeoutConstant = dwTimeout;
}
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts (hPort, &CommTimeOuts);
printf("insert ASCII code string you wish to send:");
scanf("%s", input);
strcpy(data, "{0x02}");
strcat(data, input);
printf("%s \n", data);
data2=Checksum(data);
strcat(data, data2);
strcat(data, "{0x03}");
printf("the final sent message will be: %s \n",data);
retVal = WriteFile(hPort,data, strlen(data), &byteswritten, NULL);
printf("Number of bytes written: %d\n", byteswritten);
printf("Write Success? %d\n", retVal);
retVal=ReadFile (hPort, &response, 20, &dwBytesTransferred, NULL);
printf("Read Success? %d\n", retVal);
printf("Port Response: %d\n", response);
free(response);
return 0;
}
Summary of latest discoveries: Using the Free Serial Port Monitor that Habi suggested I now know for sure that WriteFile is functioning correctly and COM6 is in receiving the message. I'm still looking for a crossover cable to double check that the message is being transferred across the line. I figure while I try to figure that out if someone could look at this new edition and tell me if there is anything wrong, particularly in relation to the ReadFile function, it would be much appreciated. It bothers me that the Free Serial Port software is only showing the data passed from my computer and not a response from the device at all. =\
Instead of
"COM6"
try
"\\\\.\\COM6"
And I would recommend to use CreateFile(), ReadFile(), WriteFile().
To open the COM port try this:
HANDLE hComDev;
if ((hComDev = CreateFile ( "\\\\.\\COM6",
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security attrs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)) != INVALID_HANDLE_VALUE)
{
// success
}
It seems that calling GetCommState() is missing in your code. Try this to configure the COM port:
DCB Dcb;
GetCommState (hComDev, &Dcb);
Dcb.BaudRate = CBR_19200;
Dcb.StopBits = ONESTOPBIT;
Dcb.ByteSize = 8;
Dcb.Parity = NOPARITY;
Dcb.fParity = 0;
Dcb.fOutxCtsFlow = 0;
Dcb.fOutxDsrFlow = 0;
Dcb.fDsrSensitivity = 0;
Dcb.fTXContinueOnXoff = TRUE;
Dcb.fOutX = 0;
Dcb.fInX = 0;
Dcb.fNull = 0;
Dcb.fErrorChar = 0;
Dcb.fAbortOnError = 0;
Dcb.fRtsControl = RTS_CONTROL_DISABLE;
Dcb.fDtrControl = DTR_CONTROL_DISABLE;
And to initially clear the COM port, I would do a reset like this before starting to send and receive bytes:
FlushFileBuffers( hComDev );
PurgeComm (hComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
COMSTAT comStat;
DWORD dwErrorFlags;
ClearCommError ( hComDev, &dwErrorFlags, &comStat );
You ask for timeouts? To configure time outs try this:
COMMTIMEOUTS CommTimeOuts;
DWORD dwTimeout = .... // <- set timeout in milliseconds
if(!dwTimeout)
{ // Don't use timeout -> Read the bytes already in input buffer and return immediately
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
}
else
{ // Use given timeout, wait until the requested number of bytes are read - or timeout
CommTimeOuts.ReadIntervalTimeout = 0;
CommTimeOuts.ReadTotalTimeoutConstant = dwTimeout;
}
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts (hComDev, &CommTimeOuts);
My code is supposed to write a string of ascii values to the device
and then read the response, however I cannot seem to get any response.
Are you sure that the bytes are really sent to the device? If you have the option, take a oscilloscope and monitor the PC's Tx line. Send some bytes and check baudrate and start/stop bits. If you have no hardware to monitor this signal, take a software based serial monitor, e.g. Free Serial Port Monitor. I have no experience with that kind of software tools but they should show you at least that the Windows drivers try to send something via the COM port of your choice.
Greetings
Habi
If you have been trying for a month then I would recommend you look at the windows function CreateFile. I have used this for serial port comms and it works fine. You might also want to look at the DCB struct and GetCommState and SetCommState functions to configure the serial port. WriteFile can be used to write data to the serial port. I cannot post all of my code as it owned by my company, but this should help you get started.
Also ClearCommError may be of help to you to query if any data is on the serial port buffer when you are waiting to read from it.
I encountered a similar problem and found the other answers helpful, but I was not receiving characters.
Ultimately I found the problem was with RTS_CONTROL_DISABLE or DTR_CONTROL_DISABLE.
By having RTS and DTR held low, the program was indicating to the modem/device that the program was not ready to receive data, and the modem was respecting this signal and dutifully not sending.
By changing these to RTS_CONTROL_ENABLE and DTR_CONTROL_ENABLE, the program indicates to the modem that data may be sent, and I began receiving characters. Not all devices respect these signals so it may work in some configurations with DTR and RTS disabled -- the modem may send data anyway.
It's possible, but you need to config com port via cmd mode command,
and there is no way to config timeout value via cmd command.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
// use mode command to config port
// mode com2 dtr=off rts=off baud=9600 parity=N data=8 stop=1 to=on
FILE *f = fopen("\\\\.\\COM2", "wb+");
setvbuf(f, NULL, _IONBF, 0);
if(f == NULL) return -1;
while(1)
{
static char p[5];
int cnt = fread(&p, 1, sizeof(p), f);
printf("read[%d]:%s\n", cnt, p);
if(p[0] == '0') break;
memset(p, 0, sizeof(p));
}
fclose(f);
return 0;
}