I'm trying to establish a UART interface between an external Microcontroller and Windows using C.
I'm using the following code to set up the UART Parameters and then send in a character to the designated COM port.
I'm successful in sending a character. But How do I receive one back ? The code is as follows:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
HANDLE hSerial;
int main()
{
// OPEN SERIAL PORT AND SET INITAL UART PARAMETERS
//=================================================
DCB dcbSerialParams = {0}; COMMTIMEOUTS timeouts = {0};
fprintf(stderr, "Opening serial port...");
hSerial = CreateFile("\\\\.\\COM3", GENERIC_READ|GENERIC_WRITE, 0, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (hSerial == INVALID_HANDLE_VALUE){fprintf(stderr, "Error\n");return 1;}
else {fprintf(stderr, "OK\n");}
// Set device parameters (115200 baud, 1 start bit, 1 stop bit, no parity)
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (GetCommState(hSerial, &dcbSerialParams) == 0){fprintf(stderr, "Error getting device state\n");CloseHandle(hSerial);return 1;}
dcbSerialParams.BaudRate = CBR_57600; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY;
if(SetCommState(hSerial, &dcbSerialParams) == 0){fprintf(stderr, "Error setting device parameters\n");CloseHandle(hSerial);return 1;}
// Set COM port timeout settings
timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10;
if(SetCommTimeouts(hSerial, &timeouts) == 0){fprintf(stderr, "Error setting timeouts\n"); CloseHandle(hSerial); return 1;}
// SETUP AND SEND DATA FROM UART
//==============================
int VarNum=8;
char str[15];
sprintf(str,"%ld",VarNum);
DWORD bytes_written, total_bytes_written = 0;
fprintf(stderr, "Sending bytes...");
if(!WriteFile(hSerial,str, strlen(str), &bytes_written, NULL))
{
fprintf(stderr, "Error\n");
CloseHandle(hSerial);
return 1;
}
fprintf(stderr, "%d bytes written\n", bytes_written);
// CLOSE SERIAL PORT AND EXIT MAIN FUNCTION
//=========================================
fprintf(stderr, "Closing serial port...");
if (CloseHandle(hSerial) == 0){fprintf(stderr, "Error\n"); return 1;}
fprintf(stderr, "OK\n");return 0;
}
You can use ReadFile() for that:
BOOL bOk = ReadFile(hSerial, buffer, sizeof(buffer) - 1, &bytesRead, NULL);
if (bOk && (bytesRead > 0)) {
buffer[bytesRead] = '\0';
}
When reading from a serial port, ReadFile() should block until there is more data, or a timeout occurs. (this should be done in a seperate thread (in a loop), or maybe by using ReadFileEx() for asynchronous operation).
When reading from a communications device, the behavior of ReadFile is
governed by the current communication time-outs as set and retrieved
using the SetCommTimeouts and GetCommTimeouts functions. Unpredictable
results can occur if you fail to set the time-out values.
Also checkout SetCommState() and PurgeComm().
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");
}
}
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");
}
}
I'm building a cnc machine for a school project, it consists of an Intel galileo with a shield that controls stepper motors, this is controlled by a program on a windows machine(windows 7), what the program basically does is read a text file containing gcode and then sends it line by line to the Galileo, the Galileo then takes that line breaks it down into coordinates and instructions, moves the spindle to where it needs to go and when the instruction is finished it sends a message back to the computer through serial telling it that its finished, the computer then sends the next line of code and the process is repeated.
so far I can read the gcode file and send it line by line (using a keypress to send each line) to the galileo and everything works fine. my problem is reading from the galileo I have tried a few methods with no joy. this is what I think is closest to what I should be doing. I wont post the whole source because I think it will be just to much to read through, ive posted the main() which has all the setup functions and the function that is supposed to read the serial.
/************************************************************************************************************
application for controling galileo or arduino cnc machine
by brendan scullion
10/11/2014
**********************************************************************************************************/
#include <string.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <ctype.h>
#include <conio.h>
#include "functions.h"
int main()
{
system("COLOR 1F");
// Declare variables and structures
unsigned char text_to_send[MAX_PATH];
unsigned char digits[MAX_PATH];
int baudrate = 19200;
int dev_num = 50;
char dev_name[MAX_PATH];
HANDLE hSerial;
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
DCB dcbSerialParams = {0};
COMMTIMEOUTS timeouts = {0};
printf("Searching serial ports...\n");
while(dev_num >= 0)
{
printf("\r ");
printf("\rTrying COM%d...", dev_num);
sprintf(dev_name, "\\\\.\\COM%d", dev_num);
hSerial = CreateFile(
dev_name,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if (hSerial == INVALID_HANDLE_VALUE) dev_num--;
else break;
}
if (dev_num < 0)
{
printf("No serial port available\n");
return 1;
}
printf("OK\n");
// Set device parameters (38400 baud, 1 start bit,
// 1 stop bit, no parity)
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (GetCommState(hSerial, &dcbSerialParams) == 0)
{
printf("Error getting device state\n");
CloseHandle(hSerial);
return 1;
}
//dcbSerialParams.BaudRate = CBR_38400;
dcbSerialParams.BaudRate = baudrate;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if(SetCommState(hSerial, &dcbSerialParams) == 0)
{
printf("Error setting device parameters\n");
CloseHandle(hSerial);
return 1;
}
// Set COM port timeout settings
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if(SetCommTimeouts(hSerial, &timeouts) == 0)
{
printf("Error setting timeouts\n");
CloseHandle(hSerial);
return 1;
}
char *cmd = NULL;
char *para1 = NULL;
char *para2 = NULL;
char *para3 = NULL;
char comPort[10];
float baudRate;
int keepGoing = 1;
unsigned char message[MAX_STRING_LENGHT];
//*********************************************************************************************************************
char cmdLine[200];
heading();
while(keepGoing == 1)
{
printf(">>");
gets(cmdLine);
cmd = strtok(cmdLine, " ");
if(cmd!=false)
{
if(cmd != NULL)
{
para1 = strtok(NULL, " ");
}
else if(para1 != NULL)
{
para2 = strtok(NULL, " ");
}
else if(para2 != NULL)
{
para3 = strtok(NULL, " ");
}
if(strcmp(cmd, "help")== 0)
{
help();
}
else if(strcmp(cmd, "comset")== 0)
{
setupComs(comPort, baudRate);
}
else if(strcmp(cmd, "getg")== 0)
{
getgcode(hSerial,text_to_send,dev_name);
}
else if(strcmp(cmd, "readserial")== 0)
{
read_serial(hSerial, message, dev_name);
}
else if(strcmp(cmd, "offset")==0)
{
getOffset(hSerial, text_to_send, dev_name);
}
else if(strcmp(cmd, "setup") == 0)
{
setup(hSerial, text_to_send, dev_name);
}
else if(strcmp(cmd, "exit") == 0)
{
keepGoing = 0;
}
else
{
printf("Unknown command!\n");
}
printf("\n");
}
}
// Close serial port
printf("Closing serial port...");
if (CloseHandle(hSerial) == 0)
{
printf("Error\n");
return 1;
}
printf("OK\n");
return 0;
}
and the function for reading
void read_serial(HANDLE hComm, HANDLE screen, char *message, char *devName )
{
char buffer[MAX_STRING_LENGHT];
unsigned char ch;
DWORD bytes_recieved = MAX_STRING_LENGHT, written = 0;
strcpy(buffer,""); //empty buffer
strcpy(buffer,"");
while(buffer!=NULL){ // wait untill serail message revieved
ReadFile(hComm, &buffer,sizeof(buffer), // read serial
&bytes_recieved, NULL );
if(bytes_recieved){ // if something to read
WriteFile(screen, buffer, bytes_recieved, &written, NULL);
strcpy(message, buffer);
printf("%s", message);
if(kbhit()){
ch = getch();
if(ch== 'q')
break;
}
}
}
}
i can post the entire source code if anybody wants to have a look at it
In read_serial, you can try replacing &buffer with buffer in the call to ReadFile. Name of a character array should be a pointer to the first element of the array.
What i would do is i would frame every message that goes from and to the Galileo board in a simple and useful protocol. For example i would use STX and ETX to frame and send messages from the Windows 7 via serial to the board, use ACK NAK to acknowledge the received packet and use SYN for signalling end of execution of a line on Galileo.
With the above framing you can construct receive and send functions where you can wait for specific characters (ETX,STX,SYN,ACK,etc) and exit once you have a full frame or an control character.
I am working on a project having GSM module and it is also communicating serially with computer.
I have written a code in C on Visual Studio 2010 to transmit and receive data serially.
Code is given below:-
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <commdlg.h>
int nread,nwrite;
int main()
{
COMMTIMEOUTS timeouts;
COMMCONFIG dcbSerialParams;
char *words, *buffRead, *buffWrite;
DWORD dwBytesWritten,dwBytesRead;
HANDLE hSerial= CreateFile(L"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(" serial port does not exist \n");
}
printf(" some other error occured. Inform user.\n");
}
//DCB dcbSerialParams ;
//GetCommState( hSerial, &dcbSerialParams.dcb);
if (!GetCommState(hSerial, &dcbSerialParams.dcb))
{
printf("error getting state \n");
}
dcbSerialParams.dcb.DCBlength = sizeof(dcbSerialParams.dcb);
dcbSerialParams.dcb.BaudRate = CBR_9600;
dcbSerialParams.dcb.ByteSize = 8;
dcbSerialParams.dcb.StopBits = ONESTOPBIT;
dcbSerialParams.dcb.Parity = NOPARITY;
dcbSerialParams.dcb.fBinary = TRUE;
dcbSerialParams.dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcbSerialParams.dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcbSerialParams.dcb.fOutxCtsFlow = FALSE;
dcbSerialParams.dcb.fOutxDsrFlow = FALSE;
dcbSerialParams.dcb.fDsrSensitivity= FALSE;
dcbSerialParams.dcb.fAbortOnError = TRUE;
if (!SetCommState(hSerial, &dcbSerialParams.dcb))
{
printf(" error setting serial port state \n");
}
GetCommTimeouts(hSerial,&timeouts);
//COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = 1000;
timeouts.ReadTotalTimeoutConstant = 1000;
timeouts.ReadTotalTimeoutMultiplier = 1000;
timeouts.WriteTotalTimeoutConstant = 1000;
timeouts.WriteTotalTimeoutMultiplier= 1000;
if(!SetCommTimeouts(hSerial, &timeouts))
{
printf("error setting port state \n");
}
while(1)
{
//****************Write Operation*********************//
char data_tx[]="at\r";
words=&data_tx[0];
nwrite = strlen(words);
buffWrite = words;
dwBytesWritten = 0;
if (!WriteFile(hSerial, buffWrite, nwrite, &dwBytesWritten, NULL))
{
printf("error writing to output buffer \n");
}
printf("Data written to write buffer is\n %s \n",buffWrite);
//***************Read Operation******************//
dwBytesRead = 0;
nread = strlen(words);
buffRead = new char[nread +1];
memset(buffRead, 0, nread+1); // ensure that string will be null-terminated
if (!ReadFile(hSerial, buffRead, nread, &dwBytesRead, NULL))
{
printf("error reading from input buffer \n");
}
printf("Data read from read buffer is \n %s \n ",buffRead);
Sleep(10000);
}
CloseHandle(hSerial);
}
When command "at\r" is transmitted from computer to GSM module it receive it should respond to it by sending OK.
Now I am getting only O. If I send "at\r" again I am getting K.
I have verified it on hyper terminal GSM module is working properly.If I send "at" and enter it responds with OK.
Also I have verified my C code on other program it is working properly.
I want to know why it is not working properly with GSM module.
You need to call sleep before reading the result. 250 ms is more than enough