I'm trying to communicate with an USB-uart module using Libserial.
Following is my code for initial part:
serial_port.Open("/dev/ttyUSB0");
if ( ! serial_port.good() )
{
std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
<< "Error: Could not open serial port."
<< std::endl ;
exit(1) ;
}
serial_port.SetBaudRate( SerialStreamBuf::BAUD_115200 ) ;
if ( ! serial_port.good() )
{
std::cerr << "Error: Could not set the baud rate." <<
std::endl ;
exit(1) ;
}
When I run it on Ubuntu 12.04 and 13.04 with the same USB module, they all say
Error: Could not set the baud rate.
I did some tests and finally found this error would occur if I set the baud rate as or higher than 115200. It works well on 57600 and 19200.
But I'm wondering is there any possible way for me to set the baud rate as 115200?
I downloaded a serial test tool, it can work as the 115200(but I didn't checked the msg content, I just notice the transmit led is flash).
Or is it the hardware limit so I need to buy another module if I want a higher baud rate?
Thanks
===========
UPDATE:
There is no problem with the hardware. I tested it in Windows VS using 115200 and it works well. But it failed on two Ubuntu desktop(12.04 and 13.04).
I print the baudrate out after I set it
serial_port.SetBaudRate( SerialStreamBuf::BAUD_115200) ;
int rate = serial_port.BaudRate();
cout << SerialStreamBuf::BAUD_115200 << endl;
cout << rate << endl;
the result shows their values are the same, both are 4098.
Then I tried to comment all the .good() part with and after the SetBaudRate part, the program start successfully but the transmit LED doesn't flash. So I think there is really something wrong with the baudrate set so the serial initial failed, although the baudrate it returns is correct.
Now I have no idea what to do next...
in case you need to see all my
code
I'm guessing it's this bug, but haven't verified it.
http://ehc.ac/p/libserial/bugs/10/
Now in SerialStreamBuf.h
enum BaudRateEnum {
BAUD_50 = SerialPort::BAUD_50,
BAUD_75 = SerialPort::BAUD_75,
BAUD_110 = SerialPort::BAUD_110,
BAUD_134 = SerialPort::BAUD_134,
BAUD_150 = SerialPort::BAUD_150,
BAUD_200 = SerialPort::BAUD_200,
BAUD_300 = SerialPort::BAUD_300,
BAUD_600 = SerialPort::BAUD_600,
BAUD_1200 = SerialPort::BAUD_1200,
BAUD_1800 = SerialPort::BAUD_1800,
BAUD_2400 = SerialPort::BAUD_2400,
BAUD_4800 = SerialPort::BAUD_4800,
BAUD_9600 = SerialPort::BAUD_9600,
BAUD_19200 = SerialPort::BAUD_19200,
BAUD_38400 = SerialPort::BAUD_38400,
BAUD_57600 = SerialPort::BAUD_57600,
BAUD_115200 = SerialPort::BAUD_115200, // 4098
BAUD_230400 = SerialPort::BAUD_230400,
#ifdef __linux__
BAUD_460800 = SerialPort::BAUD_460800,
#endif
BAUD_DEFAULT = SerialPort::BAUD_DEFAULT, // 4097
BAUD_INVALID
} ;
So BAUD_INVALID will be 4098, exactly the same as BAUD_115200. That's why you get error.
hello i had the same problem and even i tried everything using c++ API for libSerial couldn't solve until i used the bellow code in my serial initialization!!
I used the system call once at the initialization and that worked GREAT!!
NOTE instead of /dev/ttyACM0 use the name of your serial device /dev/ttyXXX
LibSerial::SerialStream serial;
//serial.SetBaudRate(LibSerial::SerialStreamBuf::BAUD_9600);//THAT DOESNT WORKS
serial.SetCharSize( LibSerial::SerialStreamBuf::CHAR_SIZE_8);
serial.Open("/dev/ttyACM0");
system("sudo stty -F /dev/ttyACM0 115200");//YOU HAVE TO RUN THE EXCECUTABLE FROM COMMAND LINE WITH SU PRIVILEGES
Related
I'm programming on Visual Studio 2017 and i'm fed up with an error which took my entire day.
More precisely, i'm working on an Serial Communication project.
The code will send on every port availiable (GetPortName()) a string.
I installed a log header (plog) which will log all actions.
For each port, the program will log ("Testing port" port).
The variable which stands for port is "s".
The problem is when i lauch : LOGI << s; everything mess up and got a big error.
I tried "&s" instead of simply "s" on LOGI and i have not got any error but there's an adress like 0059EBF0 instead of the port.
I search and research but found nothing.
Can someone help me please ?
Thanks
for each (String^ s in SerialPort::GetPortNames())
{
SerialPort^ mySerialPort = gcnew SerialPort();
LOGI << &s;
mySerialPort->PortName = s;
mySerialPort->BaudRate = 115200;
mySerialPort->Open();
mySerialPort->Write("q");
String^ incom = mySerialPort->ReadLine();
if (incom == "Okay") {
LOGI << "Tt va bien mon fwewe";
setup = false;
}
mySerialPort->Close();
_getch();
}
I'm writing a C++ app that will need to connect to various PLCs over modbus, the IPs of these PLCs is given by user input. Currently when the user puts in an IP that cannot be connected to, my program hangs for around 2 minutes in an attempt to connect and having my app hang for 2 minutes is not an option.
An example program illustrates the issue and my attempted fixes:
#include <modbus/modbus.h>
#include <string>
#include <errno.h>
#include <iostream>
#define PRINT_TIMEVAL(timeval) std::cout << "timeval sec: " << timeval.tv_sec << " usec: " << timeval.tv_usec << std::endl;
int main()
{
std::string ip = "192.168.2.5";
int port = 502;
int slaveNum = 1;
int address = 1;
int nb = 1;
struct timeval currentTimeout;
struct timeval responseTimeout;
responseTimeout.tv_sec = 1;
responseTimeout.tv_usec = 0;
struct timeval byteTimeout;
byteTimeout.tv_sec = 1;
byteTimeout.tv_usec = 0;
modbus_t *mb = modbus_new_tcp(ip.c_str(), port);
modbus_set_debug(mb, true);
modbus_set_error_recovery(mb, MODBUS_ERROR_RECOVERY_NONE);
modbus_flush(mb);
modbus_set_slave(mb, slaveNum);
modbus_get_response_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
modbus_set_response_timeout(mb, &responseTimeout);
modbus_get_response_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
modbus_get_byte_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
modbus_set_byte_timeout(mb, &byteTimeout);
modbus_get_byte_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
std::cout << "About to connect to " << ip << std::endl;
int errno;
if((errno = modbus_connect(mb)))
{
std::cout << "Error when connecting: " << modbus_strerror(errno) << std::endl;
}
std::cout << "Done connecting to " << ip << std::endl;
modbus_close(mb);
modbus_free(mb);
return 0;
}
As you can see I've tried setting both the response and byte timeout variables to 1 second (I've also tried 500 and 5000 microseconds). When I read the timeout values they have been set properly so I'm assuming that they don't have anything to do with the initial connection attempt. I've also tried explicitly setting the error recovery mode to none in case it was trying to reconnect on its own.
I would like something that will either stop modbus_connect after x amount of time or another command that will allow me to check to see if the IP is valid before attempting to connect through modbus, this would also need to timeout after a short amount of time.
I'm using libmodbus version 3.0.1-2
The issue was with my version of libmodbus (3.0.1), which is the current release version. In that version they were using the linux connect command but they weren't passing a NONBLOCKING flag, thus connect would become blocked for 2m7s. We resolved this issue by upgrading to libmodbus v3.1.1 which is marked as unstable but is not under active development (they're developing on v3.1.2). Unfortunately that version of libmodbus does not work for windows.
Use threads to listen for each device and push those messages into a queue that can be processed without holding up the other threads.
I am trying to set my device to monitor mode, and i know its capable of being in monitor mode doing a "iwconfig wlan0 mode monitor" works, i run my code and i can capture packets from anywhere.
The problem is that in libpcap it fails to set my device to monitor mode at all(without entering the above-mentioned command line).I can't capture any packets until i manually connect to a access point.
pcap_t *handler = pcap_create("wlan0",errbuff);
if(pcap_set_rfmon(handler,1)==0 )
{
std::cout << "monitor mode enabled" << std::endl;
}
handler=pcap_open_live ("wlan0", 2048,0,512,errbuff);
int status = pcap_activate(handler); //it returns 0 here.
so is this a code problem, or the pcap library problem?Anybody successfully set their device to monitor mode without using command lines?I am using a Realtek2500 btw.
You're not supposed to use pcap_open_live and pcap_create/pcap_activate in the same code. Try doing
pcap_t *handler = pcap_create("wlan0",errbuff);
if (handler == NULL)
{
std::cerr << "pcap_create failed: " << errbuf << std::endl;
return; // or exit or return an error code or something
}
if(pcap_set_rfmon(handler,1)==0 )
{
std::cout << "monitor mode enabled" << std::endl;
}
pcap_set_snaplen(handler, 2048); // Set the snapshot length to 2048
pcap_set_promisc(handler, 0); // Turn promiscuous mode off
pcap_set_timeout(handler, 512); // Set the timeout to 512 milliseconds
int status = pcap_activate(handler);
and, of course, check the value of status.
in addtion to Guy Harris's answer.
using pcap_open_live to open your device will make it been activated. you will get PCAP_ERROR_ACTIVATED -4, , when you continue to call pcap_set_rfmon.
/* the operation can't be performed on already activated captures */
#define PCAP_ERROR_ACTIVATED -4
so use pcap_create to open the handle, and set rfmon, and call pcap_activate to activate it.
caution: pcap_set_rfmon() returns 0 on success...
so this code is correct:
pcap_t *handler = pcap_create("wlan0",errbuff);
**if(pcap_set_rfmon(handler,1) )**
{
std::cout << "monitor mode enabled" << std::endl;
}
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).
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);
}