MT166-С connection not responding. С++ Library - c++

I have a MT166-C dispenser. I am writing C ++ code to manage a dispenser.
In development use SDK (attach the link) and I have a problem.
To work with the dispenser, I open the COM port. Code:
int input_port;
string com_str = "\\\\.\\COM";
std::cin >> input_port;
std::cout << "\nInput COM value: " << input_port << std::endl;
com_str = com_str + to_string(input_port);
char* cstr = &com_str[0];
char* port_com = cstr;
HANDLE port = CommOpenWithBaut(port_com, 9600);
if (port == 0)
{
std::cout << "Cannot open connect!\n\n" << std::endl;
return -1;
}
After I use the HANDLE port to call methods.
int iRetn = 0;
BYTE byStatus = 0;
string str = "";
iRetn = MT166_GetStatus(hPortHandle, 0x98, byStatus);
Similar to documentation (p. 3.1 in MT166-C.docx - Link Too)
DLLEXPORT int APIENTRY MT166_GetStatus(HANDLE hComHandle, BYTE CardNum,BYTE &byStatus)
///Parameter:
// hComHandle: Input parameter, serial port handle, obtained by opening the serial port
// CarderNum: Input parameter, card dispenser NO. Default is 0x98
// byStatus: output parameter, card dispenser status word
//Return value:
//Succeed, return value is 0
//failed, return value is not 0 = -1 no communication
In response, I get the code -1 - no communication. For other methods, the situation is the same.
I do not understand why there is no answer from the dispenser (no communication). I would be very grateful for any help.
I use connections via rs232 cable or USB adapter rs232 - without change.
Thank you for your time.

First of all, you need to check the physical availability of an external device.
Check baud speed, data bits, stop bits, row control parameters...
Check the OS hardware list for driver correctness.

Related

windows getting serial port names using c++ [duplicate]

There are several ways to list serial ports under Windows but I'm not sure what is the proper way: the way that does detect all serial ports that are available.
One good code example is http://www.naughter.com/enumser.html - where there are 9 (nine!) ways of enumerating serial devices.
The question is: what is the optimal way of doing it.
Requirements:
to not open ports in order to check if they are available.
to be able to detect ports with different names than COMx.
to work on Windows XP SP2 or above
void SelectComPort() //added function to find the present serial
{
TCHAR lpTargetPath[5000]; // buffer to store the path of the COMPORTS
DWORD test;
bool gotPort=0; // in case the port is not found
for(int i=0; i<255; i++) // checking ports from COM0 to COM255
{
CString str;
str.Format(_T("%d"),i);
CString ComName=CString("COM") + CString(str); // converting to COM0, COM1, COM2
test = QueryDosDevice(ComName, (LPSTR)lpTargetPath, 5000);
// Test the return value and error if any
if(test!=0) //QueryDosDevice returns zero if it didn't find an object
{
m_MyPort.AddString((CString)ComName); // add to the ComboBox
gotPort=1; // found port
}
if(::GetLastError()==ERROR_INSUFFICIENT_BUFFER)
{
lpTargetPath[10000]; // in case the buffer got filled, increase size of the buffer.
continue;
}
}
if(!gotPort) // if not port
m_MyPort.AddString((CString)"No Active Ports Found"); // to display error message incase no ports found
}
If you can access the registry, the HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM key contains a list of COM ports Windows currently supports (in some cases, this information may be stale/incorrect; like, I suspect, when a plug & play device providing serial ports has not completed detection/installation or has been recently removed).
This is the way .NET Framework's SerialPort.GetPortNames() method reports available COM ports, and the above information is derived from the linked page.
Serial ports are very simple devices, dating from the stone age of computing hardware. They don't support Plug & Play, there is no way to tell that somebody plugged in a device. The only thing you can do is discover what ports are available, the SerialPort.GetPortNames() returns the list. Some USB emulators can generate a descriptive name to go with the port name, you can discover those with WMI, Win32_SerialPort class.
None of which helps you discover what COM port is connected to a particular device. Only a human knows, she physically plugged the cable in the connector. You'll need to provide a config UI that lets the user select the port number. A combo box gets the job done. Save the selection in your config data, it is very likely that the device is still connected to the same port the next time your program starts.
This is a modernized version of #michael-jacob-mathew's answer:
#include <iostream>
#include <string>
#include <Windows.h>
bool SelectComPort() //added function to find the present serial
{
char lpTargetPath[5000]; // buffer to store the path of the COMPORTS
bool gotPort = false; // in case the port is not found
for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
{
std::string str = "COM" + std::to_string(i); // converting to COM0, COM1, COM2
DWORD test = QueryDosDevice(str.c_str(), lpTargetPath, 5000);
// Test the return value and error if any
if (test != 0) //QueryDosDevice returns zero if it didn't find an object
{
std::cout << str << ": " << lpTargetPath << std::endl;
gotPort = true;
}
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
}
}
return gotPort;
}
It produces the following output on my computer:
COM1: \Device\Serial0
COM3: \Device\VCP0
Modified #Dženan answer to use wide characters and returning list of ints
#include <string>
#include <list>
list<int> getAvailablePorts()
{
wchar_t lpTargetPath[5000]; // buffer to store the path of the COM PORTS
list<int> portList;
for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
{
wstring str = L"COM" + to_wstring(i); // converting to COM0, COM1, COM2
DWORD res = QueryDosDevice(str.c_str(), lpTargetPath, 5000);
// Test the return value and error if any
if (res != 0) //QueryDosDevice returns zero if it didn't find an object
{
portList.push_back(i);
//std::cout << str << ": " << lpTargetPath << std::endl;
}
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
}
}
return portList;
}
You can check the windows registry base to list all COM ports. Here is my code > github file
CUIntArray ports;
EnumerateSerialPorts(ports);
for (int i = 0; i<ports.GetSize(); i++)
{
CString str;
str.Format(_T("COM%d"), ports.ElementAt(i));
m_ctlPort.AddString(str);
}

Flush queued GPIB responses

Architecture ->GBIP from external interface is connected to target ( linux) system via gpib bus.
Inside Linux box , there is ethernet cable from GPIB to motherboard.
The PIC_GPIB card on external interface is IEEE 488.2
I am sending a query from external interface to linux box.
Few scenarios
1) If I send a query which does not expect a response back , then next query send will work.
2) If I send a query which expect response back , and when I have received the response and read it and then fire next query it works fine.
3) BUT if I send a query from external interface and got response back and I ignore to read the response , then Next query fails.
I am requesting help for scenario 3.
The coding is done on linux side and its a socket programming , which uses linux inbuilt function from unistd.h for read and write.
My investigation : I have found there is a internal memory on gbib card on external interface which stores the value of previous response until we have the read. Generally I use IEEE string utility software to write commands that goes to linux box and read reposne via read button .
Could someone please direct me how to clean input buffer or memory which stores value so that write from external command contiunues without bothering to read it.
My code on linux side has been developed in C++ and socket programming. I have used in bulit write and read function to write and read to the gpib and to json server.
Sample code is shown below
bool GpibClass::ReadWriteFromGPIB()
{
bool check = true;
int n = 0;
char buffer[BUFFER_SIZE];
fd_set read_set;
struct timeval lTimeOut;
// Reset the read mask for the select
FD_ZERO(&read_set);
FD_SET(mGpibFd, &read_set);
FD_SET(mdiffFd, &read_set);
// Set Timeout to check the status of the connection
// when no data is being received
lTimeOut.tv_sec = CONNECTION_STATUS_CHECK_TIMEOUT_SECONDS;
lTimeOut.tv_usec = 0;
cout << "Entered into this function" << endl;
// Look for sockets with available data
if (-1 == select(FD_SETSIZE, &read_set, NULL, NULL, &lTimeOut))
{
cout << "Select failed" << endl;
// We don't know the cause of select's failure.
// Close everything and start from scratch:
CloseConnection(mGpibFd);
CloseConnection(mdifferntServer); // this is different server
check = false;
}
// Check if data is available from GPIB server,
// and if any read and push it to gpib
if(true == check)
{
cout << "Check data from GPIB after select" << endl;
if (FD_ISSET(mGpibFd, &read_set))
{
n = read(mGpibFd, buffer, BUFFER_SIZE);
cout << "Read from GPIB" << n << " bytes" << endl;
if(0 < n)
{
// write it to different server and check if we get response from it
}
else
{
// Something failed on socket read - most likely
// connection dropped. Close socket and retry later
CloseConnection(mGpibFd);
check = false;
}
}
}
// Check if data is available from different server,
// and if any read and push it to gpib
if(true == check)
{
cout << "Check data from diff server after select" << endl;
if (FD_ISSET(mdiffFd, &read_set))
{
n = read(mdiffFd, buffer, BUFFER_SIZE);
cout << "Read from diff servewr " << n << " bytes" << endl;
if (0 < n)
{
// Append, just in case - makes sure data is sent.
// Extra cr/lf shouldn't cause any problem if the json
// server has already added them
strcpy(buffer + n, "\r\n");
write(mGpibFd, buffer, n + 2);
std::cout <<" the buffer sixze = " << buffer << std::endl;
}
else
{
// Something failed on socket read - most likely
// connection dropped. Close socket and retry later
CloseConnection(mdiffFd);
check = false;
}
}
}
return check;
}
You should ordinarily be reading responses after any operation which could generate them.
If you fail to do that, an easy solution would be to read responses in a loop until you have drained the queue to empty.
You can reset the instrument (probably *RST), but you would probably loose other state as well. You will have to check it's documentation to see if there is a command to reset only the response queue. Checking the documentation is always a good idea, because the number of instruments which precisely comply with the spec is dwarfed by the number which augment or omit parts in unique ways.

What is proper way to detect all available serial ports on Windows?

There are several ways to list serial ports under Windows but I'm not sure what is the proper way: the way that does detect all serial ports that are available.
One good code example is http://www.naughter.com/enumser.html - where there are 9 (nine!) ways of enumerating serial devices.
The question is: what is the optimal way of doing it.
Requirements:
to not open ports in order to check if they are available.
to be able to detect ports with different names than COMx.
to work on Windows XP SP2 or above
void SelectComPort() //added function to find the present serial
{
TCHAR lpTargetPath[5000]; // buffer to store the path of the COMPORTS
DWORD test;
bool gotPort=0; // in case the port is not found
for(int i=0; i<255; i++) // checking ports from COM0 to COM255
{
CString str;
str.Format(_T("%d"),i);
CString ComName=CString("COM") + CString(str); // converting to COM0, COM1, COM2
test = QueryDosDevice(ComName, (LPSTR)lpTargetPath, 5000);
// Test the return value and error if any
if(test!=0) //QueryDosDevice returns zero if it didn't find an object
{
m_MyPort.AddString((CString)ComName); // add to the ComboBox
gotPort=1; // found port
}
if(::GetLastError()==ERROR_INSUFFICIENT_BUFFER)
{
lpTargetPath[10000]; // in case the buffer got filled, increase size of the buffer.
continue;
}
}
if(!gotPort) // if not port
m_MyPort.AddString((CString)"No Active Ports Found"); // to display error message incase no ports found
}
If you can access the registry, the HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM key contains a list of COM ports Windows currently supports (in some cases, this information may be stale/incorrect; like, I suspect, when a plug & play device providing serial ports has not completed detection/installation or has been recently removed).
This is the way .NET Framework's SerialPort.GetPortNames() method reports available COM ports, and the above information is derived from the linked page.
Serial ports are very simple devices, dating from the stone age of computing hardware. They don't support Plug & Play, there is no way to tell that somebody plugged in a device. The only thing you can do is discover what ports are available, the SerialPort.GetPortNames() returns the list. Some USB emulators can generate a descriptive name to go with the port name, you can discover those with WMI, Win32_SerialPort class.
None of which helps you discover what COM port is connected to a particular device. Only a human knows, she physically plugged the cable in the connector. You'll need to provide a config UI that lets the user select the port number. A combo box gets the job done. Save the selection in your config data, it is very likely that the device is still connected to the same port the next time your program starts.
This is a modernized version of #michael-jacob-mathew's answer:
#include <iostream>
#include <string>
#include <Windows.h>
bool SelectComPort() //added function to find the present serial
{
char lpTargetPath[5000]; // buffer to store the path of the COMPORTS
bool gotPort = false; // in case the port is not found
for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
{
std::string str = "COM" + std::to_string(i); // converting to COM0, COM1, COM2
DWORD test = QueryDosDevice(str.c_str(), lpTargetPath, 5000);
// Test the return value and error if any
if (test != 0) //QueryDosDevice returns zero if it didn't find an object
{
std::cout << str << ": " << lpTargetPath << std::endl;
gotPort = true;
}
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
}
}
return gotPort;
}
It produces the following output on my computer:
COM1: \Device\Serial0
COM3: \Device\VCP0
Modified #Dženan answer to use wide characters and returning list of ints
#include <string>
#include <list>
list<int> getAvailablePorts()
{
wchar_t lpTargetPath[5000]; // buffer to store the path of the COM PORTS
list<int> portList;
for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
{
wstring str = L"COM" + to_wstring(i); // converting to COM0, COM1, COM2
DWORD res = QueryDosDevice(str.c_str(), lpTargetPath, 5000);
// Test the return value and error if any
if (res != 0) //QueryDosDevice returns zero if it didn't find an object
{
portList.push_back(i);
//std::cout << str << ": " << lpTargetPath << std::endl;
}
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
}
}
return portList;
}
You can check the windows registry base to list all COM ports. Here is my code > github file
CUIntArray ports;
EnumerateSerialPorts(ports);
for (int i = 0; i<ports.GetSize(); i++)
{
CString str;
str.Format(_T("COM%d"), ports.ElementAt(i));
m_ctlPort.AddString(str);
}

Problems capturing audio from the second sound card

I have written a program that captures sound via waveInOpen() in Wuindows. It works great on the michrophone-device on the main-board, but when I try to capture from the second sound-card, I get only [static] noise. Recording with SoundRecorder works great on both cards. Does any1 know if there are any known problems with waveInOpen() and multiple input-devices?
The code that opens the input-device looks like this:
void Audio::OpenDevice(const int device,
const Audio::SamplingRate samplingRate)
throw (Exception, std::exception)
{
switch(samplingRate)
{
...
case AUDIO_16BIT_44KHZ_STEREO:
bits_per_sample_ = 16;
hertz_ = 44100;
channels_ = 2;
break;
...
default:
throw Exception("Audio::OpenDevice(): Invalid enum value");
}
// Open the device
const UINT_PTR dev = (-1 == device) ? (UINT_PTR)WAVE_MAPPER : (UINT_PTR)device;
WAVEFORMATEX wf = {0};
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = channels_;
wf.wBitsPerSample = bits_per_sample_;
wf.nSamplesPerSec = hertz_;
wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
`
const MMRESULT result = waveInOpen(&hwi_, dev, &wf,
(DWORD_PTR)OnWaveEvent, (DWORD_PTR)this, CALLBACK_FUNCTION);
if (MMSYSERR_NOERROR != result)
throw Exception("waveInOpen()");
std::cout << "Audio: Sampling at " << hertz_ << " hertz from "
<< channels_ << " channel(s) with " << bits_per_sample_
<< " bits per sample. "
<< std::endl;
}
Did you check the microphone gain settings, mixer settings, that the microphone hardware you're using is compatible with the input you have it hooked to, etc? Hooking most microphones to a line in connection does not work well. The microphone doesn't have enough output voltage to drive that kind of input.
My guess (purely a guess) is that the bit depth or sample rate is somehow incorrect. If you are using 16/44100, then I would assume it is supported (pretty common). But maybe the sound card is not set for those rates. I have an external Edirol sound card that I have to physically turn on and off when I change bit depth (and adjust a separate switch on it).

C++ Serial Port Question

Problem:
I have a hand held device that scans those graphic color barcodes on all packaging. There is a track device that I can use that will slide the device automatically. This track device functions by taking ascii code through a serial port. I need to get this thing to work in FileMaker on a Mac. So no terminal programs, etc...
What I've got so far:
I bought a Keyspan USB/Serial adapter. Using a program called ZTerm I was successful in sending commands to the device.
Example:
"C,7^M^J"
I was also able to do the same thing in Terminal using this command: screen /dev/tty.KeySerial1 57600
and then type in the same command above(but when I typed in I just hit Control-M and Control-J for the carriage return and line feed)
Now I'm writing a plug-in for FileMaker(in C++ of course). I want to get what I did above happen in C++ so when I install that plug-in in FileMaker I can just call one of those functions and have the whole process take place right there.
I'm able to connect to the device, but I can't talk to it. It is not responding to anything.
I've tried connecting to the device(successfully) using these:
FILE *comport;
if ((comport = fopen("/dev/tty.KeySerial1", "w")) == NULL){...}
and
int fd;
fd = open("/dev/tty.KeySerial1", O_RDWR | O_NOCTTY | O_NDELAY);
This is what I've tried so far in way of talking to the device:
fputs ("C,7^M^J",comport);
or
fprintf(comport,"C,7^M^J");
or
char buffer[] = { 'C' , ',' , '7' , '^' , 'M' , '^' , 'J' };
fwrite (buffer , 1 , sizeof(buffer) , comport );
or
fwrite('C,7^M^J', 1, 1, comport);
Questions:
When I connected to the device from Terminal and using ZTerm, I was able to set my baud rate of 57600. I think that may be why it isn't responding here. But I don't know how to do it here.... Does any one know how to do that? I tried this, but it didn't work:
comport->BaudRate = 57600;
There are a lot of class solutions out there but they all call these include files like termios.h and stdio.h. I don't have these and, for whatever reason, I can't find them to download. I've downloaded a few examples but there are like 20 files in them and they're all calling other files I can't find(like the ones listed above). Do I need to find these and if so where? I just don't know enough about C++ Is there a website where I can download libraries??
Another solution might be to put those terminal commands in C++. Is there a way to do that?
So this has been driving me crazy. I'm not a C++ guy, I only know basic programming concepts. Is anyone out there a C++ expert? I ideally I'd like this to just work using functions I already have, like those fwrite, fputs stuff.
Thanks!
Sending a ^ and then a M doesn't send control-M, thats just the way you write it,
to send a control character the easiest way is to just use the ascii control code.
ps. ^M is carriage return ie "\r" and ^J is linefeed "\n"
edit: Probably more than you will (hopefully) ever need to know - but read The Serial Port Howto before going any further.
This isn't a C++ question. You're asking how to interact with the TTY driver to set teh baud rate. The fact that you're opening the file under /dev tells me that you're on a unix derivative, so the relevant man page to read on a linux system is "man 3 termios".
Basically, you use the open() variant above, and pass the file descriptor to tcsetattr/tcgetattr.
Are you sure you've installed all the compiler tools properly? On my OS X 10.5.8 Mac,
termios.h and stdio.h are right there under /usr/include, just as I'd expect. The
code you've already found for serial port programming on other Unix variants should
only require minor changes (if any) to work on a Mac. Can you tell us a bit more about
what you've tried, and what went wrong?
mgb also has a good point about how the control characters need to be represented.
You can set the baud rate with ioctl. Here's a link to an example.
You don't specify which Unix you are using, so below I'm posting some Linux production code I use.
Pleae note below code is a class method so ignore any external (ie undeclared) references.
Steps are as follows -
Configure your termio structure, this is where you set any needed flags etc (ie the step you accomplished using zterm. The termio settings below configure the port to 8 databits, 1 stopbit and no parity (8-n-1). Also the port will be in "raw" (as opposed to cooked) mode so its a character stream, text isn't framed into lines etc The baud constants match the actual value, ie for 56700 baud you use "57600".
The timing parameters mean that characters are returned from the device as soon as they are available.
Once you have your termainal parameters set, you open the device (using POSIX open()), and then can use tcgetattr/tcsetattr to configure the device via the fd.
At this point you can read/write to the device using the read()/write() system calls.
Note that in the below example read() will block if no data is available so you may want to use select()/poll() if blocking is undesirable.
Hope that helps.
termios termio
tcflag_t baud_specifier;
//reset device state...
memset (&termio, 0, sizeof (termios));
read_buffer.clear();
//get our boad rate...
if (!(baud_specifier = baud_constant (baud))) {
ostringstream txt;
txt << "invalid baud - " << baud;
device_status_msg = txt.str();
status = false;
return (true);
}
//configure device state...
termio.c_cflag = baud_specifier | CS8 | CLOCAL | CREAD;
//do we want handshaking?
if (rtscts) {
termio.c_cflag |= CRTSCTS;
}
termio.c_iflag = IGNPAR;
termio.c_oflag = 0;
termio.c_lflag = 0;
//com port timing, no wait between characters and read unblocks as soon as there is a character
termio.c_cc[VTIME] = 0;
termio.c_cc[VMIN] = 0;
//open device...
if ((fd = open (device.c_str(), O_RDWR | O_NOCTTY)) == -1) {
ostringstream txt;
txt << "open(\"" << device << "\") failed with " << errno << " - "
<< std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
//keep a copy of curret device state...
if (tcgetattr (fd, &old_termio) == -1) {
ostringstream txt;
txt << "tcgetattr() failed with " << errno << " - " << std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
//flush any unwanted bytes
if (tcflush (fd, TCIOFLUSH) == -1) {
ostringstream txt;
txt << "tcflush() failed with " << errno << " - " << std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
//apply our device config...
if (tcsetattr (fd, TCSANOW, &termio) == -1) {
ostringstream txt;
txt << "tcsetattr() failed with " << errno << " - " << std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
node_log_f ("successfully initialised device %s at %i baud", "open_device()",
device.c_str(), baud);
status = true;
return (true);
}