I have been coding on C/C++ for a while but now I have faced a major problem which I can not resolve. I am trying to communicate with COM port. First I am sending data with WriteFile(), this part works.But when it comes to receiving an answer from the port with ReadFile(), I do not get anything.
Here is the code:
#include <stdlib.h>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
int main(int argc, char *argv[])
{
int n=0;
DCB dcb={0};
HANDLE hCom;
BOOL fSuccess;
char *pcCommPort = "COM3";
DWORD dwBytesRead=0;
DWORD dwRead;
DWORD dwBytesWrite=0;
DWORD dwWrite=0;
/***************************************CommTimeouts******************************************/
COMMTIMEOUTS timeouts={0};
timeouts.ReadIntervalTimeout=200;
//timeouts.ReadTotalTimeoutConstant=1;
//timeouts.ReadTotalTimeoutMultiplier=1;
timeouts.WriteTotalTimeoutConstant=2;
//timeouts.WriteTotalTimeoutMultiplier=1;
/*******************************************Handle*******************************************/
hCom = CreateFile( pcCommPort,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, // must be opened with exclusive-access
NULL, // no security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL, // not overlapped I/O
NULL // hTemplate must be NULL for comm devices
);
/***************************************SET*UP*COM*PORT**************************************/
if (hCom == INVALID_HANDLE_VALUE)
{
printf ("CreateFile failed with error %d.\n", GetLastError());
CloseHandle(hCom);
return (1);
}
if(!SetCommTimeouts(hCom, &timeouts))
{
/*Well, then an error occurred*/
}
fSuccess = GetCommState(hCom, &dcb);
if (!fSuccess)
{
/*More Error Handling*/
printf ("GetCommState failed with error %d.\n", GetLastError());
CloseHandle(hCom);
return (2);
}
dcb.BaudRate = 9600; // set the baud rate
dcb.ByteSize = 8; // data size, xmit, and rcv
dcb.Parity = EVENPARITY; // no parity bit
dcb.StopBits = ONESTOPBIT; // one stop bit
fSuccess = SetCommState(hCom, &dcb);
if (!fSuccess)
{
printf ("SetCommState failed. Error: %d.\n", GetLastError());
CloseHandle(hCom);
return (3);
}
printf ("Serial port %s successfully configured.\n", pcCommPort);
// return (0);
/*************************************Writing************************************************/
char bytes_to_send[] = {'36'};
if(!WriteFile(hCom, bytes_to_send, 2, &dwBytesWrite, NULL))
{
fprintf(stderr, "Error\n");
CloseHandle(hCom);
return 1;
}
printf("dwBytesWrite = %d | %x\n", dwBytesWrite, (dwBytesWrite));
/*************************************Reading************************************************/
char bytes_to_receive[7];
if(!ReadFile(hCom, bytes_to_receive, 7, &dwBytesRead, NULL)){
printf ("SetCommState failed. Error: %d.\n", GetLastError());
CloseHandle(hCom);
return (4);
} else {
printf("Bytes read %d -> %d\n",dwBytesRead, bytes_to_receive);}
/********************************************************************************************/
CloseHandle(hCom);
return(0);
}
There is a file pointer, both for read and write. After the WriteFile it is at the end of the file. If you try to read from it, you will read at the end of the file. To read what you just wrote you have to reposition the file pointer at the start of the file, using the SetFilePointer function:
SetFilePointer(hCom, 0, NULL, FILE_BEGIN);
Related
I was wondering if any of you know what I'm doing wrong here? So I have this program in C, that sends AT commands to a modem. These commands have been tested on hyperterminal and work fine, but when sendind them through the modem I get, first, and "OK" for the first "AT" command, which is good, but then, upon sending the next command, the modem answers with "AT+CC"...which I have no idea what it means. Any help is appreciated.
Source:
void sendSMS(const char* port, const char* number, const char* baud)
{
HANDLE hComm;
DCB dcb;
BOOL fSuccess;
hComm = CreateFile(port, //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 (hComm == INVALID_HANDLE_VALUE)
{
printf("ERROR: Cannot open serial port\r\n");
return;
}
else
printf("STATUS: Serial port opened\r\n");
// Configure PORT
// Initialize the DCB structure.
SecureZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
// Build on the current configuration by first retrieving all current
// settings.
fSuccess = GetCommState(hComm, &dcb);
if (!fSuccess)
{
// Handle the error.
printf("GetCommState failed with error %d.\n", GetLastError());
return;
}
// Fill in some DCB values and set the com state:
// 57,600 bps, 8 data bits, no parity, and 1 stop bit.
dcb.BaudRate = atoi(baud); // baud rate
dcb.ByteSize = 8; // data size, xmit and rcv
dcb.Parity = NOPARITY; // parity bit
dcb.StopBits = ONESTOPBIT; // stop bit
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutX = FALSE;
fSuccess = SetCommState(hComm, &dcb);
if (!fSuccess)
{
// Handle the error.
printf("SetCommState failed with error %d.\n", GetLastError());
return;
}
// Get the comm config again.
fSuccess = GetCommState(hComm, &dcb);
if (!fSuccess)
{
// Handle the error.
printf("GetCommState failed with error %d.\n", GetLastError());
return;
}
// End Config
sendATCommands(hComm, number, "This is NOT a test.");
CloseHandle(hComm);//Closing the Serial Port
}
void sendATCommands(HANDLE hComm, const char* number, const char message[])
{
char str[256];
if (!writeToPort(hComm, "AT\r\n")) //Hello modem
return;
if (!readFromPort(hComm)) // Must be OK
return;
if (!writeToPort(hComm, "AT+CMGF=1\r\n")) //Modem, prepare to send text messages
return;
if (!readFromPort(hComm)) // Must be OK again
return;
memset(str, 0, 256);
strcpy_s(str, "AT+CMGS=\"");
strcat_s(str, 256, number);
strcat_s(str, 256, "\"\r\n");
if (!writeToPort(hComm, str)) //Modem, here's the number to send the message to
return;
if (!readFromPort(hComm)) // Must be ">"
return;
memset(str, 0, 256);
strcpy_s(str, message);
strcat_s(str, 256, "^Z");
if (!writeToPort(hComm, str)) //Modem, communicate this to the number I gave you.
return;
if (!readFromPort(hComm)) // Must be CMGS: ##
return;
}
int writeToPort(HANDLE hComm, const char lpBuffer[])
{
DWORD dNoOFBytestoWrite; // No of bytes to write into the port
DWORD dNoOfBytesWritten = 0; // No of bytes written to the port
dNoOFBytestoWrite = sizeof(lpBuffer);
int Status = WriteFile(hComm, // Handle to the Serial port
lpBuffer, // Data to be written to the port
dNoOFBytestoWrite, //No of bytes to write
&dNoOfBytesWritten, //Bytes written
NULL);
if (Status == FALSE)
{
printf("ERROR: Cannot write to serial port\r\n");
}
else
printf("STATUS: Command %s \n written to port.\r\n", lpBuffer);
return Status;
}
int readFromPort(HANDLE hComm)
{
char TempChar; //Temporary character used for reading
char SerialBuffer[256];//Buffer for storing Rxed Data
DWORD NoBytesRead = 0;
int i = 0;
int status;
memset(SerialBuffer, 0, 256);
printf("STATUS: Waiting response...\r\n");
do
{
status = ReadFile(hComm, //Handle of the Serial port
&TempChar, //Temporary character
sizeof(TempChar),//Size of TempChar
&NoBytesRead, //Number of bytes read
NULL);
if (!status)
{
printf("ERROR: Cannot read from serial port\r\n");
break;
}
SerialBuffer[i] = TempChar;// Store Tempchar into buffer
i++;
}
while (NoBytesRead > 0);
if (status)
printf("PORT RESPONSE: %s \r\n", SerialBuffer);
return status;
}
Can someone provide me with a sample C code that list´s all device Names that i can open with Createfile()? i always get error code 3 : path does not exist
sample code that doesnt works:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <regstr.h>
#include <devioctl.h>
#include <usb.h>
#include <usbiodef.h>
#include <usbioctl.h>
#include <usbprint.h>
#include <setupapi.h>
#include <devguid.h>
#include <wdmguid.h>
#pragma comment(lib, "Setupapi.lib")
int main(void){
HDEVINFO deviceInfoList;
deviceInfoList = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (deviceInfoList != INVALID_HANDLE_VALUE)
{
SP_DEVINFO_DATA deviceInfoData;
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoList, i, &deviceInfoData); i++)
{
LPTSTR buffer = NULL;
DWORD buffersize = 0;
while (!SetupDiGetDeviceInstanceIdA(deviceInfoList, &deviceInfoData, buffer, buffersize, &buffersize))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
if (buffer) delete buffer;
buffer = new TCHAR[buffersize];
}
else
{
printf("%ls\n", "error");
break;
}
}
HANDLE hFile = CreateFileA(buffer,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("InvalidHandle, error code: %d\n", GetLastError());
}
CloseHandle(hFile);
printf("%s\n", buffer);
if (buffer) { delete buffer; buffer = NULL; }
}
}
getchar();
}
my Goal is to print all valid device Names and try to get a valid handle on it that i can later user for sending ioctl`s
thx
EDIT:
ok abhineet so thats what i got now :
DWORD EnumerateDevices(){
DWORD dwResult = 0;
HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);// DIGCF_ALLCLASSES
/*HDEVINFO hdev =SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES); */
if (INVALID_HANDLE_VALUE != hdev) {
for (int idev = 0; idev < 100; idev++)
{
SP_DEVICE_INTERFACE_DATA did = { 0 };
did.cbSize = sizeof(did);
if (SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(hdev,
&did,
NULL,
0,
&cbRequired,
0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, cbRequired);
if (pdidd) {
pdidd->cbSize = sizeof(*pdidd);
if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0)) {
wprintf(L"%s\n", pdidd->DevicePath);
HANDLE hBattery = CreateFile(pdidd->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hBattery)
{
printf("Successfully opened Handle\n");
CloseHandle(hBattery);
}
else{
wprintf(L"CreateFile(%s) failed %d\n", pdidd->DevicePath, GetLastError());
}
}
else{
printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
}
LocalFree(pdidd);
}
}
else{
printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
}
}
else if (ERROR_NO_MORE_ITEMS == GetLastError())
{
printf("-NoMoreItems-");
break; // Enumeration failed - perhaps we're out of items
}
}
SetupDiDestroyDeviceInfoList(hdev);
}
else{
printf("SetupDiGetClassDevs() failed %d\n", GetLastError());
}
return dwResult;
}
i ripped the most from here : https://msdn.microsoft.com/en-us/library/windows/desktop/bb204769(v=vs.85).aspx
and my Output is :
\\?\acpi#pnp0c0a#1#{72631e54-78a4-11d0-bcf7-00aa00b7b32a}
Successfully opened Handle
-NoMoreItems-
at least i got a valid handle!
so i wanna do this an all devices avaible on the System , how to do that?
IMHO, I don't think, you can do a CreateFile on InstanceID. To do a CreateFile, you need the symbolic name of the device. You can use the following SetupAPIs,
SetupDiEnumDeviceInterfaces
SetupDiGetDeviceInterfaceDetail
The Remark section of both APIs state that,
SetupDiEnumDeviceInterfaces:: DeviceInterfaceData points to a structure that identifies a requested
device interface. To get detailed information about an interface, call
SetupDiGetDeviceInterfaceDetail. The detailed information includes the
name of the device interface that can be passed to a Win32 function
such as CreateFile (described in Microsoft Windows SDK documentation)
to get a handle to the interface.
SetupDiGetDeviceInterfaceDetail:: The interface detail returned by this function consists of a device path that can be passed to Win32
functions such as CreateFile. Do not attempt to parse the device path
symbolic name. The device path can be reused across system starts.
This might be of your use, how to get DevicePath from DeviceID
I am trying to send arguments to my arduino. so i made this code:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
HANDLE serialPortHandler;
char *comPort[8] = {"1", "2", "3", "4", "5", "6", "7", "8"};
char comPortName[5] = "COM";
int i = 1;
int openPort(char *name){
serialPortHandler = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if(serialPortHandler == INVALID_HANDLE_VALUE){
return -1;
}else{
DCB dcb;
FillMemory(&dcb, sizeof(dcb), 0);
if (!GetCommState(serialPortHandler, &dcb)){
return -1;
}
dcb.BaudRate = CBR_9600 ;
if (!SetCommState(serialPortHandler, &dcb)){
return -1;
}
}
return 1;
}
int writePort(char *lpBuf,DWORD dwToWrite){
DWORD dwWritten;
if(WriteFile(serialPortHandler, lpBuf, dwToWrite, &dwWritten, NULL)){
while(dwWritten < dwToWrite);
printf("User: %s, %d", lpBuf, dwWritten);
return 0;
}else{
printf("Error");
CloseHandle(serialPortHandler);
return 1;
}
return 0;
}
int main(int argc, char *argv[]){
if(argc != 2)
return 1;
strcat(comPortName, comPort[0]);
while(openPort(comPortName) < 0 && i < sizeof(comPort) / sizeof(int)){
comPortName[3] = *comPort[i];
//printf("%s", comPortName);
i++;
Sleep(0);
}if(i >= sizeof(comPort) / sizeof(int)){
printf("Cannot Find Port");
scanf("%d");
return 1;
}
printf("Port %s Is Opened - BaudRate 9600\n", comPortName);
printf("Sent Frequency: %s\n", argv[1]);
writePort(argv[1], strlen(argv[1]));
}
But it only works if i run it on debug mode and wait for a few moments at WriteFile.If i run it from cmd it doesnt output to my arduino.
The WriteFile function has the ability to run asynchronously. Have you checked for this case?
From:https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
If the function fails, or is completing asynchronously, the return value is zero (FALSE). To get extended error information, call the GetLastError function.
The WriteFile function returns when one of the following conditions occur:
The number of bytes requested is written.
A read operation releases buffer space on the read end of the pipe (if the write was blocked). For more information, see the Pipes section.
An asynchronous handle is being used and the write is occurring asynchronously.
An error occurs.
(Meta: Can't blockquote a bullet list, I guess)
The problem was it takes time to initiate these two things:
1.SetCommState(serialPortHandler, &dcb)
so i added Sleep before and it fixed the problem.
I am a student so I apologize up front for not using the correct forum protocols. I am new to C, and really new to Win32 API. My assignment is to write a small C program that copies the contents of an existing file to a new file, using only Win32 I/O system calls: CreateFile(), ReadFile(), WriteFile(), etc... File names are to be specified on the command line. Right now I'm just trying to get the basics functions in place, I will then focus on error handling. This code compiles, creates a new file, but the data does not get copied to it. Any advice? thanks for taking a look!
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char *argv[])
{
char buff[4096];
DWORD dwBytesRead, dwBytesWritten;
DWORD dwBytesToWrite = (DWORD)strlen(buff);
//open source file and read it
HANDLE source;
// Create a handle for the source file
source=CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for errors
if ( source == INVALID_HANDLE_VALUE ){
printf("Error, source file not opened.");
exit(EXIT_FAILURE);
}
else printf("The source file is %s\n", argv[1]);
//create a new file
HANDLE target;
target = CreateFile(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ( target == INVALID_HANDLE_VALUE ){
printf("Error, target file not created.");
exit(EXIT_FAILURE);
}
else printf("The source file is %s\n", argv[2]);
//copy contents
ReadFile(source, buff, 4096, &dwBytesRead, NULL);
WriteFile(target, buff, dwBytesToWrite, &dwBytesWritten, NULL);
//copy complete
CloseHandle(source);
CloseHandle(target);
return 0;
}
As mentioned in comments, your code has a few mistakes in it. Try something more like this instead:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char *argv[])
{
char buff[4096];
DWORD dwBytesRead, dwBytesWritten;
// Open the source file
HANDLE source = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for error
if (source == INVALID_HANDLE_VALUE) {
printf("Source file not opened. Error %u", GetLastError());
return EXIT_FAILURE;
}
printf("The source file is %s\n", argv[1]);
// Create a new file
HANDLE target = CreateFileA(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for error
if (target == INVALID_HANDLE_VALUE) {
printf("Target file not created. Error %u", GetLastError());
CloseHandle(source);
return EXIT_FAILURE;
}
printf("The target file is %s\n", argv[2]);
// Copy contents
bool ok = true;
do {
// Read file, check for error
if (!ReadFile(source, buff, sizeof(buff), &dwBytesRead, NULL)) {
printf("Source file not read from. Error %u", GetLastError());
ok = false;
break;
}
// Check for EOF reached
if (dwBytesRead == 0) {
break;
}
// Write file, check for error
if (!WriteFile(target, buff, dwBytesRead, &dwBytesWritten, NULL)) {
printf("Target file not written to. Error %u", GetLastError());
ok = false;
break;
}
}
while (true);
// Copy complete
CloseHandle(source);
CloseHandle(target);
// Check for error
if (!ok) {
DeleteFileA(argv[2]);
return EXIT_FAILURE;
}
// all OK
return 0;
}
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.