Can't open a serial port in g++ on Ubuntu - c++

I am trying to run the sample programs that came with a development lidar unit (RPLIDAR A1M8 360 Degree Laser Scanner Kit). The sample code for a Linux target compiles without error using g++
(Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0 however when I run it, it stops with the message 'Error, cannot bind to the specified serial port /dev/ttyUSB0'. Using gdb I can trace the code down to the serial port open call to __libc_open64 where I don't have source anymore...
__libc_open64 (file=0x5555557832a9 "/dev/ttyUSB0", oflag=2306) at ../sysdeps/unix/sysv/linux/open64.c:36}
36 ../sysdeps/unix/sysv/linux/open64.c: No such file or directory.
Here is what I tried so far to eliminate obvious failure modes:
The serial port, a USB-to-serial converter on ttyUSB0, works just fine from Putty (115200, 8, none, 1, software flow control only). I connect it to a Raspberry Pi as the console to get a large amount of data without issue and can bidirectionally interact with the console. Therefore I conclude the port and converter work fine
The section of code that calls __libc_open64 is...
bool raw_serial::open(const char * portname, uint32_t baudrate, uint32_t flags)
{
if (isOpened()) close();
serial_fd = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
I looked up the constants that are ORed together and hard coded the value (04403) just in case there was some issue with the version of the header files. Oddly the value is off by 1 from the oflag value in the gdb line. Compiled and ran it, no difference
I verified the call to ::open returned -1 which is treated as a failure in the code immediately after
I can see in dmesg that ttyUSB0 is open and available
I am not a c++ guy. This looks to me like an issue with the g++ __libc_open64 code but that also seems very unlikely. I don't know where to go next. Any advice would be greatly appreciated.
The first comments received pointed to permissions. I chmoded /dev/ttyUSB0 wide open before starting this exercise.
I ran strace and see the line...
openat(AT_FDCWD, "/dev/ttyUSB0", O_ACCMODE|O_NOCTTY|O_NONBLOCK) = -1 ENOENT (No such file or directory)
Well, that's embarrassing! It returns Permission Denied! Yes, I chmoded permissions wide open, then promptly forgot that being a USB device, it goes away and gets redefined when I unplug/plug it in again. Thank you for your help!

The prediction that strace would show "Permission denied" was correct. I was forgetting this is not a fixed serial port but rather a USB-to-serial converter. Even though I chmoded the permissions and verified it use with Putty, I forgot that as soon as I rebooted, or unplugged the USB, the /dev/ttyUSB0 device goes away and is recreated again when I rebooted or plugged it in, requiring that I set the permissions again.

Related

Get inode for lookup in /proc/net/udp

I am trying to programmatically track the amount of data in my receive buffer. I am receiving UDP data. After doing some research it seems that the only way to do this in Linux is to look at /proc/net/udp. This seems like a good solution until I realized that two applications could be listening to the same multicast group and I need to tell them apart. It seems that I am supposed to do this by determining what my inode is.
I spend some time looking into this and there are suggestions that sockfd_lookup or sock_from_file is the way to go but on my CentOS Linux machine, these functions do not seem to be available.
Can someone please help me to figure out which line in /proc/net/udp belongs to my application?
I started using the ioctl (handle, FIONREAD, &bytesInBuffer) call only to discover that in Linux this only returns the size of the first datagram packet in the buffer.
Google seems to suggest that the sockfd_lookup call can be used to get the inode but a grep in my /usr/local/include/ does not return these functions.
My linux/net.h seems pretty bare-bone compared to some I can find on google which includes structs like "socket" which has the sock member which I believe has the inode information. My linux/net.h on CentOs only is 58 lines long and has only a few #defines and an enum.
after a bit of fiddling I noticed that readlink("/proc/self/fd/$fd") (under Linux 5.3) gives me something like:
socket:[3753088]
back. I can parse this and use the resulting digits to look up the relevant line in /proc/net/udp:
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
2867: 00000000:0BB8 00000000:0000 07 00000000:00000000 00:00000000 00000000 1000 0 3753088 2 000000003ae8e911 0
that said, I don't understand why you'd want to do this, but never mind!
I'm also not sure why you don't just look up by sock&peer name, which might be easier

operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full

I have a machine running multiple applications which constantly perform UNC access (\\server-ip\share) so:
std::ifstream src(fileName, std::ios::binary);
std::ofstream dst(newFileName, std::ios::binary);
CopyFromRemote(ifstream &src, ofstream &dst);
dst.flush();
dst.close();
src.close();
void CopyFromRemote(ifstream src, ofstream dst)
{
char buffer[8192]; // read 8KB each chunk
while (src.read(buffer, sizeof(buffer)))
{
dst.write(buffer, sizeof(buffer));
// Here there is code that checks that some timer !> max read time so as
// to not be stuck if there is network issue with this src.
}
if (src.eof() && src.gcount() > 0)
{
dst.write(buffer, src.gcount()); // few bytes left
}
}
As can be seen the network is heavily strained by traversing it for each 8KB (files are several MB large). The benefit here is the ability to abort a file copy in case it takes too long from specific source.
The problem I'm facing is after several days all UNC become non-accessible from this machine with error above. I'm not sure what the source of the problem is but it's sporadic & hard to nail. When the problem happens the 1st line fails (std::ifstream src...). telnet also stops to work.
Also: When killing the applications the UNC is accessible again. When restarting the processes the UNC is immediately not accessible again. Restarting the machine solves the problem for several days.
Initially I thought it was Port exhaustion but netstat does not reveal too many connections or hanging connections and the task manager performance tab does not show abnormal figures. TcpQry shows normal TCP/UDP mapping numbers.
Also: Packet capture shows there is no request when problem happens (request not reaching network). Event viewer does not reveal anything. Did following registry changes although this would probably just delay problem not eliminate it but anyway it didn't help:
Find the autodisconnect value in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters. If it's not there, create a new REG_DWORD called autodisconnect. Edit the value as Hexadecimal and set it to ffffffff.
Find KeepConn in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parameters. If it doesn't exist create it as a REG_DWORD value and assign it the value 65534.
Find HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters and create a new DWORD value named MaxUserPort. Set the value to 65534.
Eventually this was due to Microsoft OS bug. Since machine is an offline machine it does not get regular updates automatically. Installing all OS updates solved the problem.

C++ - RtMidi send nothing to out ports

I'm working on a program using RtMidi to communicate with MIDI applications.
Compilation, opening input and output ports, reading input ports works as well, but when I send message with output port, nothing happens.
No exception, no message in terminal, everything seems to be ok, but other apps never receives MIDI message.
$ uname
Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt7-1 (2015-03-01) x86_64 GNU/Linux
Audio server is ALSA 1.0.28.
$ cat /proc/asound/version
Advanced Linux Sound Architecture Driver Version k3.16.0-4-amd64.
MidiConnection::MidiConnection(QString Name, QObject *Object) : QThread(Object)
{
/*...*/
midiIn = new RtMidiIn(RtMidi::UNSPECIFIED, "Mecanique");
midiIn->openPort(0, Name.toStdString());
midiOut = new RtMidiOut(RtMidi::UNSPECIFIED, "Mecanique");
midiOut->openPort(0, Name.toStdString());
/*...*/
}
void MidiConnection::sendMessage(QVector<unsigned char> message)
{
std::vector<unsigned char> tempVector = message.toStdVector();
midiOut->sendMessage(&tempVector);
}
When I'm testing, tempVector contains right bytes (which are correct about the MIDI specs) (see answer below).
Solution found: this code is absolutely correct, it was the data given to the function sendMessage() which was wrong. When execution start, a value upper than 127 was included in a vector. As result, it seems that ALSA don't listen more the connection without force to close it.
Thanks for your suggestions!

Debug Assertion Failed during opening COM port

I'm working on a program to take readings from a proximity sensor using Arduino UNO. While I can get the readings just fine using Arduino's build-in Serial Monitor, somehow I cannot open the same port from MS VC++.
Following is (one part of) the program:
int main(void)
{
/*used for port"COM13"*/
HANDLE hCom=INVALID_HANDLE_VALUE;
char input[30];
string ss,ss1,ss2,ss3,ss4;
/*Open "COM13"*/
hCom=CreateFile("COM13",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if(hCom==INVALID_HANDLE_VALUE)
{
printf("can't open file");
}
/*Communication Setting*/
DCB dcb;
memset(&dcb,0,sizeof (DCB));
dcb.DCBlength=sizeof (DCB);
dcb.BaudRate=CBR_9600;
dcb.ByteSize=8;
dcb.Parity=NOPARITY;
dcb.StopBits=ONESTOPBIT;
SetCommState(hCom,&dcb);
while(1)
{
//using the data string inputs, printout the readings, process it etc...
}
}
When I try to debug it, I'll get this error:
and I got can't open file from debug windows showing there is problem during port opening.
Some additional infos:
Why VC++? I'm also using OpenCV and some mathematical computation in the same program so it is easier for me to work in VC++
I've also tested my UNO program with TeraTerm for data readings with no problem (=no problem with my UNO)
I've tested above program with another microcontroller(non-Arduino) with no problem.
I'll upload my UNO program if needed.
Thanks in advance!
From the MSDN page on CreateFile:
To specify a COM port number greater than 9, use the following syntax:
"\.\COM10". This syntax works for all port numbers and hardware that
allows COM port numbers to be specified.

RS-232 confusion under C++

What's the problem in given code? Why it is not showing the output for rs232 when we connect it by the d-9 connector with the short of pin number 2 & 3 in that?
#include <bios.h>
#include <conio.h>
#define COM1 0
#define DATA_READY 0x100
#define SETTINGS ( 0x80 | 0x02 | 0x00 | 0x00)
int main(void)
{
int in, out, status;
bioscom(0, SETTINGS, COM1); /*initialize the port*/
cprintf("Data sent to you: ");
while (1)
{
status = bioscom(3, 0, COM1); /*wait until get a data*/
if (status & DATA_READY)
if ((out = bioscom(2, 0, COM1) & 0x7F) != 0) /*input a data*/
putch(out);
if (kbhit())
{
if ((in = getch()) == 27) /* ASCII of Esc*/
break;
bioscom(1, in, COM1); /*output a data*/
}
}
return 0;
}
Well, the code looks alright. Have you really connected the remaining pins correctly in the plug, see serial and pin connections.
Nothing obvious stands out from your code as the cause. Check all your bases as you are dealing with hardware/software. The following Microsoft article has a different implementation using _bios_serialcom (from bios.h) which might be a good reference point for you.
http://support.microsoft.com/kb/39501
Suggestions for where to go from here:
I would also suggest replacing the literals (eg 0x08) using the constants predefined for Baud rate, Parity (eg _COM_NOPARITY) to make the code more readable in your question.
Check that the Com port is actually open, as its a assumption which is unchecked in your code example above.
Also check up on the pin connections for the DB9. To connect two computers/devices you will need to null modem it, eg pin 2 to pin 3 at the other end, plus the Signal Ground. Make sure you are disabling/not looking for DTR.
If the other computer/device is setup then I would suggest first running HyperTerminal (Programs->Accessories->Communication) and connect to your COM 1 and check you can see characters from the other device. If not its most likely related to your cable.
Hope that helps.
Before checking with your code always check your serial communication with a terminal program. I don't have much experience with Windows environment but in Linux you have programs like cutecom or gtkterm where you can send/receive data from serial port. We extensively used these programs for serial communication in Linux, they are great for debugging potential problems with serial port interface (both h/w & s/w as well). So, before suspecting your code check with a terminal emulator program.
Hey, I am not an expert on Win32, but it seems to be easier to use another article as a source (the one mentioned here before looks outdated):
http://msdn.microsoft.com/en-us/library/ms810467
This is old too, dated around 1995, but it looks still effective. The NT architecture is very restrictive when it comes to grant access to hardware, for example, to send bytes to a PC paralell port one needs to rely on workarounds dll written by open source developers.
I'm assuming from your comment about "pin 2 & 3" that you've connected a loopback cable, so you're expecting to see anything you type come up on the screen (and stop doing so when you disconnect the cable).
I think there's a bug in the code: the if (kbhit()) is inside the if (status & DATA_READY).
That means you only check the keyboard if there is some input ready to receive from the serial port - which there won't be, because you haven't sent it anything yet! Try moving the test and see if it improves matters.
(Here is some similar serial port code that puts the if (kbhit()) test outside the DATA_READY check. It doesn't claim to work, but provides some evidence that this might be the source of the problem...)