I am trying to write data to the tap adapter(a virtual network interface) through its file descriptor. I opened the file by calling the "CreateFile" API and I am able to write the data. I am writing some 100 bytes of data to the file which is sometimes taking more time to complete which I could not figure out what is causing that issue.
I am not getting any error codes and the call is getting success. The only problem is, it is taking more time to complete. I am writing the data 100 times in a loop and only some say 10 iterations "WriteFile" calls are taking more time to complete which is causing some delay in further processing of the packets.
#include <stdio.h>
#include <pcap.h>
#include <sys/types.h>
#include <ntddndis.h>
#define LINE_LEN 16
#define ETHER_MAX_LEN 65535
#ifdef WIN32
#include <tchar.h>
BOOL LoadNpcapDlls()
{
_TCHAR npcap_dir[512];
UINT len;
len = GetSystemDirectory(npcap_dir, 480);
if (!len) {
fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
return FALSE;
}
_tcscat_s(npcap_dir, 512, _T("\\Npcap"));
if (SetDllDirectory(npcap_dir) == 0) {
fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
return FALSE;
}
return TRUE;
}
#endif
void physical_dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *);
HANDLE hTapAdapter;
pcap_t *port_a;
DWORD WINAPI DataReceiveHandlerThread(LPVOID lpParam)
{
pcap_loop(port_a, 0, physical_dispatcher_handler, NULL);
return 0;
}
#define BUFFERSIZE 65535
CRITICAL_SECTION m_cs;
int main(int argc, char **argv)
{
BOOL bErrorFlag = FALSE;
//Initilize the critical section
InitializeCriticalSection(&m_cs);
printf("\n");
/*if (argc != 2)
{
printf("Usage Error:\tIncorrect number of arguments\n\n");
_tprintf(TEXT("%s <file_name>\n"), argv[0]);
return;
}*/
hTapAdapter = CreateFile("\\\\.\\Global\\{A2AC038D-EBC1-48F9-B507-BB822AE1C393}.tap", // name of the write
GENERIC_READ | GENERIC_WRITE, // open for writing
0, // do not share
NULL, // default security
OPEN_EXISTING, // create new file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hTapAdapter == INVALID_HANDLE_VALUE)
{
//DisplayError(TEXT("CreateFile"));
_tprintf(TEXT("Terminal failure: Unable to open file \"%s\" for write.\n"), argv[1]);
return;
}
DWORD threadIdentifier = 0;
HANDLE threadHandle = CreateThread(
NULL, // default security attributes
0, // use default stack size
DataReceiveHandlerThread, // thread function name
NULL, // argument to thread function
0, // use default creation flags
&threadIdentifier); // returns the thread identifier
// Check the return value for success.
// If CreateThread fails, terminate execution.
// This will automatically clean up threads and memory.
if (threadHandle == NULL)
{
//ErrorHandler(TEXT("CreateThread"));
ExitProcess(3);
}
WaitForSingleObject(threadHandle, INFINITE);
CloseHandle(threadHandle);
return;
}
void physical_dispatcher_handler(u_char *temp1,
const struct pcap_pkthdr *header,
const u_char *pkt_data)
{
u_int i = 0;
/*
* unused variable
*/
(VOID*)temp1;
DWORD dwBytesWritten = 0;
time_t my_time = time(NULL);
// ctime() used to give the present time
printf("Data received in port A - %s", ctime(&my_time));
// Lock the Critical section
EnterCriticalSection(&m_cs);
BOOL bErrorFlag = WriteFile(
hTapAdapter, // open file handle
pkt_data, // start of data to write
header->len, // number of bytes to write
&dwBytesWritten, // number of bytes that were written
NULL); // no overlapped structure
if (FALSE == bErrorFlag)
{
//DisplayError(TEXT("WriteFile"));
printf("Terminal failure: Unable to write to file.\n");
}
else
{
if (dwBytesWritten != header->len)
{
// This is an error because a synchronous write that results in
// success (WriteFile returns TRUE) should write all data as
// requested. This would not necessarily be the case for
// asynchronous writes.
printf("Error: dwBytesWritten != dwBytesToWrite\n");
}
else
{
time_t my_time = time(NULL);
// ctime() used to give the present time
printf("Data written to tap - %s", ctime(&my_time));
_tprintf(TEXT("Wrote %d bytes to successfully.\n"), dwBytesWritten);
}
}
//Release the Critical section
LeaveCriticalSection(&m_cs);
return;
}
Related
Suppose I have a usb drive with two partition e:, f:. How do I know from which offset the partition e: or f: starts so that I can write raw data starting from that offset. I could not find any function that would provide me the offset in c++. In Dos I could easily get this with wmic partition get Index, Name, StartingOffset.
To get the StartingOffset of partitions in a Physical Drive(such as \\\\.\\PhysicalDrive1), you could use IOCTL_DISK_GET_DRIVE_LAYOUT_EX to get PARTITION_INFORMATION_EX arrays for each partition:
#include <windows.h>
#include <stdio.h>
#define wszDrive L"\\\\.\\PhysicalDrive1"
int wmain(int argc, wchar_t* argv[])
{
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
BOOL bResult = FALSE; // results flag
DWORD junk = 0; // discard results
DWORD error;
DWORD szNewLayout = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 4 * 25;
hDevice = CreateFileW(wszDrive, // drive to open
GENERIC_READ, // no access to the drive
FILE_SHARE_READ,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
0); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
error = GetLastError();
printf("CreateFileW error: %d\n", error);
return -1;
}
DRIVE_LAYOUT_INFORMATION_EX* pdg = (DRIVE_LAYOUT_INFORMATION_EX*)malloc(szNewLayout);
if (pdg == NULL)
{
error = GetLastError();
printf("malloc error: %d\n", error);
CloseHandle(hDevice);
return -1;
}
ZeroMemory(pdg, szNewLayout);
bResult = DeviceIoControl(hDevice, // device to be queried
IOCTL_DISK_GET_DRIVE_LAYOUT_EX, // operation to perform
NULL, 0, // no input buffer
pdg, szNewLayout,// sizeof(*pdg)*2, // output buffer
&junk, // # bytes returned
(LPOVERLAPPED)NULL); // synchronous I/O
if (!bResult)
{
error = GetLastError();
printf("DeviceIoControl error: %d\n", error);
free(pdg);
CloseHandle(hDevice);
return -1;
}
for (int i = 0; i < pdg->PartitionCount; i++) {
printf("partition %d: %lld\n", i, pdg->PartitionEntry[i].StartingOffset.QuadPart);
}
free(pdg);
CloseHandle(hDevice);
return 0;
}
To get the StartingOffset of a specified partition(such as \\\\.\\E:), you could use IOCTL_DISK_GET_PARTITION_INFO_EX:
#include <windows.h>
#include <stdio.h>
#define wszDrive L"\\\\.\\E:"
int wmain(int argc, wchar_t* argv[])
{
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
BOOL bResult = FALSE; // results flag
DWORD junk = 0; // discard results
DWORD error;
PARTITION_INFORMATION_EX piex;
ZeroMemory(&piex, sizeof(PARTITION_INFORMATION_EX));
hDevice = CreateFileW(wszDrive, // drive to open
GENERIC_READ, // no access to the drive
FILE_SHARE_READ,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
0); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
error = GetLastError();
printf("CreateFileW error: %d\n", error);
return -1;
}
bResult = DeviceIoControl(hDevice,
IOCTL_DISK_GET_PARTITION_INFO_EX,
NULL, 0,
&piex, sizeof(PARTITION_INFORMATION_EX),
&junk,
(LPOVERLAPPED)NULL);
if (!bResult)
{
error = GetLastError();
printf("DeviceIoControl error: %d\n", error);
CloseHandle(hDevice);
return -1;
}
wprintf(L"%s StartingOffset: %lld\n", wszDrive, piex.StartingOffset.QuadPart);
CloseHandle(hDevice);
return 0;
}
Im trying to record audio using ALSA and pass it to be processed. The audio sample is returned from this which is char* to a float*
Ive tried so many solutions I think I understand that it's not really a char buffer but a byte buffer but how I get it a float.
This returns the buffer:
const unsigned char* arBuffer(void)
{
return buffer;
}
I need to consume the output of the microphone as a float
int32_t O_DecodeAudioBuffer(float *audioBuffer, int size, void *oxyingObject)
{
Core *oxying = (COxyCore*)oxyingObject;
//Decode audioBuffer to check if begin token is found, we should keep previous buffer to check if token was started in previous
//var mDecoding > 0 when token has been found, once decoding is finished, mDecoding = 0
return oxying->mDecoder->DecodeAudioBuffer(audioBuffer, size);
}
Im writing a program to consume the the above as api:
void* mOxyCore; is declared
I then try and pass the arBuffer() which wouldn't work as expected.
while(arIsRunning())
{
int ret = DecodeAudioBuffer(arBuffer(), arBufferSize(), mCore);
}
The Alsa:
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <pthread.h>
#include "settings.h"
#include "audiorecorder.h"
pthread_t thr;
pthread_mutex_t mutex;
snd_pcm_t *handle;
snd_pcm_uframes_t frames;
unsigned char* buffer;
BOOL running;
size_t buffersize;
BOOL arIsRunning(void)
{
return running;
}
void arAcquireBuffer(void)
{
//printf("Acquired buffer\n");
pthread_mutex_lock(&mutex);
}
void arReleaseBuffer(void)
{
//printf("Released buffer\n");
pthread_mutex_unlock(&mutex);
}
const unsigned char* arBuffer(void)
{
return buffer;
}
const size_t arBufferSize(void)
{
return buffersize;
}
void* entry_point(void *arg)
{
int rc;
fprintf(stderr, "Listening...\n");
while (running)
{
arAcquireBuffer();
rc = snd_pcm_readi(handle, buffer, frames);
//stream to stdout - useful for testing/debugging
//write(1, buffer, buffersize);
arReleaseBuffer();
if (rc == -EPIPE) {
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
}
else if (rc < 0) {
fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
running = FALSE;
}
else if (rc != (int)frames) {
fprintf(stderr, "short read, read %d frames\n", rc);
}
}
return NULL;
}
int arInitialise(void)
{
snd_pcm_hw_params_t *params;
unsigned int val;
int rc, dir;
running = FALSE;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, RECORDER_DEVICE, SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
return rc;
}
else
{
fprintf(stderr, "Successfully opened default capture device.\n");
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
fprintf(stderr, "Format set to PCM Signed 16bit Little Endian.\n");
/* Channels */
snd_pcm_hw_params_set_channels(handle, params, NUM_CHANNELS);
fprintf(stderr, "Channels set to %d.\n", NUM_CHANNELS);
/* sampling rate */
val = SAMPLE_RATE;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
fprintf(stderr, "Samplerate set to %d.\n", val);
/* Set period to FRAMES_PER_BUFFER frames. */
frames = FRAMES_PER_BUFFER;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
return rc;
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
buffersize = frames * 2 * NUM_CHANNELS; /* 2 bytes/sample * channels */
buffer = (unsigned char*) malloc(buffersize);
/* We want to loop forever */
//snd_pcm_hw_params_get_period_time(params, &val, &dir);
return 0;
}
int arStartRecording(void)
{
if(running) return 1;
if(pthread_mutex_init(&mutex, NULL))
{
printf("Unable to initialize mutex\n");
return -1;
}
if(pthread_create(&thr, NULL, &entry_point, NULL))
{
fprintf(stderr, "Could not create recorder thread!\n");
running = FALSE;
return -1;
}
running = TRUE;
return 0;
}
void arStopRecording(void)
{
running = FALSE;
}
void arFree(void)
{
running = FALSE;
sleep(500);
snd_pcm_drain(handle);
snd_pcm_close(handle);
pthread_mutex_destroy(&mutex);
free(buffer);
}
The problem here isn't a cast, but a representation issue.
Audio is generally represented as a series of samples. There are quite a few ways to represent each sample: on a scale from -1.0f to +1.0f, or -32767 to +32767, or many others.
Alsa supports in fact many formats, and you chose SND_PCM_FORMAT_S16_LE so that's -32767 to +32767. You could cast that to std::int16_t*, assuming your C++ environment is Little-Endian (almost certain). You can't cast it to float*, for that you'd need to ask for SND_PCM_FORMAT_FLOAT_LE
I am working on a project that has a serial communication between a Windows PC and an Arduino Uno card.
In the C++ code I have a SerialClass.h and a Serial.cpp
My problem is that I get a compiler fault: identifier "SP" undefined
in the function
void Serial::SendtoArd(int val, int var)
{
if (SP->IsConnected())
{
bool writeData = false;
writeData = SP->WriteData("test",4);
}
I know if I define the SP in this function I get rid of this fault, but
I do not want to activate the Serial port in that function . I want to activate the serial port in this function
bool Serial::OpenPtoArd()
{
Serial* SP = new Serial("\\\\.\\COM3"); // adjust as needed
if (SP->IsConnected())
{
bool status = true;
}
}
and keep it active as long as my app is running.
Can anyone help me out here?
Here is the SerialClass.h
#ifndef SERIALCLASS_H_INCLUDED
#define SERIALCLASS_H_INCLUDED
#define ARDUINO_WAIT_TIME 2000
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class Serial
{
private:
//Serial comm handler
HANDLE hSerial;
//Connection status
bool connected;
//Get various information about the connection
COMSTAT status;
//Keep track of last error
DWORD errors;
public:
//Initialize Serial communication with the given COM port
Serial(char *portName);
//Close the connection
~Serial();
//Read data in a buffer, if nbChar is greater than the
//maximum number of bytes available, it will return only the
//bytes available. The function return -1 when nothing could
//be read, the number of bytes actually read.
int ReadData(char *buffer, unsigned int nbChar);
//Writes data from a buffer through the Serial connection
//return true on success.
bool WriteData(char *buffer, unsigned int nbChar);
//Check if we are actually connected
bool IsConnected();
bool OpenPtoArd();
void SendtoArd(int val, int var);
};
Here is the Serial.cpp
#endif // SERIALCLASS_H_INCLUDED
#include "stdafx.h"
#include "SerialClass.h"
#define LEN 1
bool status = false;
Serial::Serial(char *portName)
{
//We're not yet connected
this->connected = false;
//Try to connect to the given port throuh CreateFile
this->hSerial = CreateFile(portName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
//Check if the connection was successfull
if (this->hSerial == INVALID_HANDLE_VALUE)
{
//If not success full display an Error
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
//Print Error if neccessary
printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else
{
//If connected we try to set the comm parameters
DCB dcbSerialParams = { 0 };
//Try to get the current
if (!GetCommState(this->hSerial, &dcbSerialParams))
{
//If impossible, show an error
printf("failed to get current serial parameters!");
}
else
{
//Define serial connection parameters for the arduino board
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
//Set the parameters and check for their proper application
if (!SetCommState(hSerial, &dcbSerialParams))
{
printf("ALERT: Could not set Serial Port parameters");
}
else
{
//If everything went fine we're connected
this->connected = true;
//We wait 2s as the arduino board will be reseting
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
Serial::~Serial()
{
//Check if we are connected before trying to disconnect
if (this->connected)
{
//We're no longer connected
this->connected = false;
//Close the serial handler
CloseHandle(this->hSerial);
}
}
int Serial::ReadData(char *buffer, unsigned int nbChar)
{
//Number of bytes we'll have read
DWORD bytesRead;
//Number of bytes we'll really ask to read
unsigned int toRead;
//Use the ClearCommError function to get status info on the Serial port
ClearCommError(this->hSerial, &this->errors, &this->status);
//Check if there is something to read
if (this->status.cbInQue>0)
{
//If there is we check if there is enough data to read the required number
//of characters, if not we'll read only the available characters to prevent
//locking of the application.
if (this->status.cbInQue>nbChar)
{
toRead = nbChar;
}
else
{
toRead = this->status.cbInQue;
}
//Try to read the require number of chars, and return the number of read bytes on success
if (ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL) && bytesRead != 0)
{
return bytesRead;
}
}
//If nothing has been read, or that an error was detected return -1
return -1;
}
bool Serial::WriteData(char *buffer, unsigned int nbChar)
{
DWORD bytesSend;
//Try to write the buffer on the Serial port
if (!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0))
{
//In case it don't work get comm error and return false
ClearCommError(this->hSerial, &this->errors, &this->status);
return false;
}
else
return true;
}
bool Serial::IsConnected()
{
//Simply return the connection status
return this->connected;
}
void readme()
{
Serial serial("COM3");
char c[LEN + 1];
int numBytes = 0;
while (true)
{
numBytes = serial.ReadData(c, LEN);
if (numBytes != -1)
{
// Terminate the string if we want to use c variable as a string
c[numBytes] = 0;
break;
}
}
}
bool Serial::OpenPtoArd()
{
Serial* SP = new Serial("\\\\.\\COM3"); // adjust as needed
if (SP->IsConnected())
{
bool status = true;
}
}
void Serial::SendtoArd(int val, int var)
{
if (SP->IsConnected())
{
bool writeData = false;
writeData = SP->WriteData("test",4);
}
}
The problem with this code
bool Serial::OpenPtoArd()
{
Serial* SP = new Serial("\\\\.\\COM3"); // adjust as needed
if (SP->IsConnected())
{
bool status = true;
}
}
is that you are creating the new Serial - and then losing the pointer to that Serial when the function exits. If you want other functions to be able to access it, you need the SP variable to be outside the OpenPtoArd() function.
You can (should?) either make it a member of your class (which by the way will clash with Arduino's Serial class - call it something else!), or make it a global variable: put the following line near the top of the file:
YourSerialClass *SP = NULL;
Note that I set the variable to NULL. Your other code needs to know whether the SP port has been created yet or not - and to not use it if it hasn't been:
if ((SP!=NULL) && (SP->IsConnected()) {
... do SP things
} // if
I want to access serial port by visual c++
I get the program from internet but when I run the program, it seems the port can not open
here my program serialClass.cpp
#ifndef SERIALCLASS_H_INCLUDED
#define SERIALCLASS_H_INCLUDED
#define ARDUINO_WAIT_TIME 2000
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class Serial
{
private:
HANDLE hSerial;
bool connected;
COMSTAT status;
DWORD errors;
public:
Serial(char *portName);
//Serial();
~Serial();
int ReadData(char *buffer, unsigned int nbChar);
bool WriteData(char *buffer, unsigned int nbChar);
bool IsConnected();
};
#endif // SERIALCLASS_H_INCLUDED
and my Serial.cpp
#include "SerialClass.h"
Serial::Serial(char *portName)
//Serial::Serial()
{
//We're not yet connected
this->connected = false;
//Try to connect to the given port throuh CreateFile
this->hSerial = CreateFile((LPCWSTR) portName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
//Check if the connection was successfull
if(this->hSerial==INVALID_HANDLE_VALUE)
{
//If not success full display an Error
if(GetLastError()==ERROR_FILE_NOT_FOUND){
printf("ERROR: Handle was not attached. Reason: COM1 not available.\n");
}
else
{
printf("ERROR!!!");
}
}
else
{
//If connected we try to set the comm parameters
DCB dcbSerialParams = {0};
//Try to get the current
if (!GetCommState(this->hSerial, &dcbSerialParams))
{
//If impossible, show an error
printf("failed to get current serial parameters!");
}
else
{
//Define serial connection parameters for the arduino board
dcbSerialParams.BaudRate=CBR_19200;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
dcbSerialParams.fOutX=TRUE;
dcbSerialParams.fInX=TRUE;
//Set the parameters and check for their proper application
if(!SetCommState(hSerial, &dcbSerialParams))
{
printf("ALERT: Could not set Serial Port parameters");
}
else
{
//If everything went fine we're connected
this->connected = true;
//We wait 2s as the arduino board will be reseting
//Sleep(ARDUINO_WAIT_TIME);
printf("Current Settings\n Baud Rate %d\n Parity %d\n Byte Size %d\n Stop Bits %d", dcbSerialParams.BaudRate,
dcbSerialParams.Parity, dcbSerialParams.ByteSize, dcbSerialParams.StopBits);
}
}
}
}
Serial::~Serial()
{
//Check if we are connected before trying to disconnect
if(this->connected)
{
//We're no longer connected
this->connected = false;
//Close the serial handler
CloseHandle(this->hSerial);
}
}
int Serial::ReadData(char *buffer, unsigned int nbChar)
{
//Number of bytes we'll have read
DWORD bytesRead;
//Number of bytes we'll really ask to read
unsigned int toRead;
//Use the ClearCommError function to get status info on the Serial port
ClearCommError(this->hSerial, &this->errors, &this->status);
//Check if there is something to read
if(this->status.cbInQue>0)
{
//If there is we check if there is enough data to read the required number
//of characters, if not we'll read only the available characters to prevent
//locking of the application.
if(this->status.cbInQue>nbChar)
{
toRead = nbChar;
}
else
{
toRead = this->status.cbInQue;
}
//Try to read the require number of chars, and return the number of read bytes on success
if(ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL) && bytesRead != 0)
{
return bytesRead;
}
}
//If nothing has been read, or that an error was detected return -1
return -1;
}
bool Serial::WriteData(char *buffer, unsigned int nbChar)
{
DWORD bytesSend;
//Try to write the buffer on the Serial port
if(!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0))
{
//In case it don't work get comm error and return false
ClearCommError(this->hSerial, &this->errors, &this->status);
return false;
}
else
return true;
}
bool Serial::IsConnected()
{
//Simply return the connection status
return this->connected;
}
The result is always
ERROR: Handle was not attached. Reason: COM1 not available.
any body can help?
The problem is with casting to a wide string instead of converting, I replaced that part of the code opening the port with the following and it worked:
wchar_t wcPort[64];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, wcPort, strlen(portName), portName, _TRUNCATE);
this->hSerial = CreateFile(wcPort,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
Or as Ben Voigt has pointed out in a comment you could also call the CreateFileA variant so that Windows performs the conversion for you.
I am trying jni interfacing for serial port programming, using Microsoft Visual Studio 11 with .NET 4.0.
I get he following error when I try to read from the comm port:
time out happened in PortRead()
The read time out value is set to 5sec.
The following is a part of the code:
Also, since my laptop is 64 bit I'm using a bafo ie a 64 to 32 bit converter, and then attach the rs232 wire.
JNIEXPORT jint JNICALL Java_JavaSerial_Read(JNIEnv *env, jobject obj)
{
jint idata = 0;
char cdata[8];
ERR_CODE rc = OK;
CommPortClass* commClass;
commClass = new CommPortClass;
commClass->iMaxChars = 1;
rc = PortRead(commClass);
if (rc != OK)
Msg("ERROR in PortRead()! ");
sprintf_s(cdata, "%d", commClass->pcBuffer[0]);
idata = atoi(cdata);
delete commClass;
return idata;
}
//Port read function
ERR_CODE PortRead(CommPortClass *hCommPort)
{
HANDLE hThread; // handler for port read thread
DWORD IDThread;
DWORD Ret, ExitCode;
DWORD dTimeout = 5000; // define time out value: 5 sec.
ERR_CODE ecStatus = OK;
if (!(hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunc, (LPVOID)hCommPort, CREATE_SUSPENDED, &IDThread) ) )
// no security attributes, use default stack size, parameter to thread function, creation flag - suspended, returns thread ID
{
Msg("Create Read Thread failed");
return EC_CREATE_THREAD;
}
ResumeThread(hThread); // start thread now
Ret = WaitForSingleObject(hThread, dTimeout);
if (Ret == WAIT_OBJECT_0)
{
// Data received & process it... need to do nothing because the data is stored in the
// hCommPort in the Thread Function. The only thing is to close thread handle
CloseHandle(hThread);
}
else if (Ret == WAIT_TIMEOUT) // Time out happened
{
// Warning & kill thread
Ret = GetExitCodeThread(hThread, &ExitCode);
Msg("Time out happened in PortRead() ");
if (ExitCode == STILL_ACTIVE)
{
TerminateThread(hThread, ExitCode);
CloseHandle(hThread);
return EC_RECV_TIMEOUT;
}
else
{
CloseHandle(hThread);
Msg("ERROR in GetExitCodeThread: != STILL_ACTIVE ");
ecStatus = EC_EXIT_CODE;
}
}
else
{
Msg("ERROR in WaitFor SingleObject ");
ecStatus = EC_WAIT_SINGLEOBJ;
}
return ecStatus;
}
//Thread() function
void WINAPI ThreadFunc(void* hCommPorts)
{
char Byte;
BOOL bResult, fDone;
int nTotRead = 0;
DWORD dwCommModemStatus, dwBytesTransferred;
CommPortClass* CommPorts;
ERR_CODE ecStatus = OK;
CommPorts = (CommPortClass* )hCommPorts;
// Specify a set of events to be monitored for the port.
SetCommMask(hPort, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
fDone = FALSE;
while (!fDone)
{
// Wait for an event to occur for the port.
WaitCommEvent(hPort, &dwCommModemStatus, 0);
// Re-specify the set of events to be monitored for the port.
SetCommMask(hPort, EV_RXCHAR | EV_CTS | EV_DSR |EV_RLSD| EV_RING);
if (dwCommModemStatus & EV_RXCHAR||dwCommModemStatus & EV_RLSD)
{
// received the char_event & loop to wait for the data.
do
{
// Read the data from the serial port.
bResult = ReadFile(hPort, &Byte, 1, &dwBytesTransferred, 0);
if (!bResult)
{
Msg("ERROR in ReadFile !");
fDone = TRUE;
break;
}
else
{
// Display the data read.
if (dwBytesTransferred == 1)
{
CommPorts->pcBuffer[nTotRead] = Byte;
nTotRead++;
if (nTotRead == CommPorts->iMaxChars)
{
fDone = TRUE;
break;
}
}
else
{
if (Byte == 0x0D ||Byte == 0x0A) // null char or CR
{
Msg("Received null character ");
fDone = TRUE;
break;
}
}
}
} while (dwBytesTransferred == 1); //while (nTotRead < pRecv->iMaxChars);
} // if
} // while
return;
}