How to check if Intel RealSense device is ready after hardware reset? - c++

After calling
dev.hardware_reset();
How do I know if the device is ready before starting the pipeline?

void rs2::context::set_devices_changed_callback (T callback) check doc
you can set a callback using set_devices_changed_callback to get notified when the device is connected or disconnected. Inside the callback you can use query_devices to know find the available devices. if the device is available you can start reading the frames.

My code to do that :
qDebug() << "[Stream] --- --- RealSense camera hardware reset...";
rs2::context ctx;
rs2::device dev = ctx.query_devices().front(); // Reset the first device
uint32_t nbDevices = ctx.query_devices().size();
qDebug() << "[Stream] --- --- RealSense camera hardware reset... nb devices :" << nbDevices;
dev.hardware_reset();
rs2::device_hub hub(ctx);
dev = hub.wait_for_device(); // waiting
qDebug() << "[Stream] --- --- RealSense camera hardware reset... OK";

Related

SDL_OpenAudioDevice with multiple devices

I am currently writing an application that will output sound to 3 different audio devices. For that, I have installed 3 USB Audio Devices in my PC, all the same brand. I wanted to use SDL2 as output device (although I am open minded for other suggestions). I had a look at the documentation and it states as the first parameter (device):
a UTF-8 string reported by SDL_GetAudioDeviceName(); see Remarks
Now I have written a sample program, that just lists the available devices:
#include <SDL2/SDL.h>
#include <iostream>
int main()
{
SDL_Init( SDL_INIT_EVERYTHING );
std::cout << SDL_GetError() << std::endl;
atexit( SDL_Quit );
int count = SDL_GetNumAudioDevices(0);
for (int i = 0; i < count; ++i)
{
std::cout << "Device " << i << ": " << SDL_GetAudioDeviceName(i, 0) << std::endl;
}
return 0;
}
It enumerates all available devices. The problem is, that all 3 devices will give me the same name:
Device 0: Internes Audio Digital Stereo (IEC958)
Device 1: C-Media Electronics, Inc. Audio Adapter
Device 2: C-Media Electronics, Inc. Audio Adapter
Device 3: C-Media Electronics, Inc. Audio Adapter
Is there any way to use something else (e.g. the USB Path) as the parameter or to make sure that I can open all 3 devices?

Avoiding Timeout on QSerialPort when handling high speed data

I'm working on a windows application that receives data from a sensor at 600Hz. In two out of five cases, my IO thread reads the 4 bytes of data from the sensor successfully and passes it on to the GUI thread.
The problem is three out of five times, QSerialPort has inexplicable timeouts where QSerialPort's waitForReadyRead() returns false and serial.errorString() has a timeout error. In which case it will never read data. If I read from the serial port despite the timeout error I will read 2000+ bytes of data in the next waitForReadyRead which will be delivered in chunks which renders the realtime data reception aspect of my application obsolete.
I've tried using the readyRead() signal of the serial port but it exhibits the same behaviour ie. if the timeout error appears, no readyRead() signal is ever fired.
UPDATE: I am able to reproduce the issue with Qt's terminal example ([QT_INSTALL_EXAMPLES]/serialport/terminal) which uses a non-blocking read. The frequency of the bug is considerably less but it's definitely still there.
UPDATE: Using Serial Port Monitor, I can see that when it gets stuck, the Qt Terminal Example gets stuck on IOCTL_SERIAL_WAIT_ON_MASK, my example gets stuck on IRP_MJ_WRITE DOWN just after the IOCT_SERIAL_WAIT_ON_MASK. This never happens with other terminal softwares leading me to think the problem is definitely with Qt.
Pastebin of Serial Port Monitor Output
void IOThread::run(){
QSerialPort serial;
serial.setPortName(portname)
serial.setBaudRage(QSerialPort::Baud115200);
serial.setStopBits(QSerialPort::OneStop)
serial.setParity(QSerialPort::NoParity);
serial.setDataBits(QSerialPort::Data8);
serial.setFlowControl(QSerialPort::NoFlowControl);
if(!serial.open(QIODevice::ReadWrite)
{
qDebug() << "Error Opening Port";
return;
}
else
{
qDebug() << "Error Message: " << serial.errorString() // prints "Unknown Error"
}
while(true)
{
if(serial.waitForReadyRead(1000))
{
qDebug() << "Normal read";
reception_buffer = serial.readAll();
}
else
{
qDebug() << "Timeout";
/* serial.readAll() here will read nothing but force next read to read huge chunk of data */
continue;
}
}
// Process data...
}
Try if this makes any difference:
while (true) {
QByteArray reception_buffer;
if (serial.waitForReadyRead(1000)) {
reception_buffer = serial.readAll();
while (serial.waitForReadyRead(10)) {
reception_buffer += serial.readAll();
}
qDebug() << "reception_buffer ready";
}
else {
qDebug() << "Timeout";
}
}
If you want to prevent from timeouting from waitForReadyRead you can set:
if(serial.waitForReadyRead(-1))
bool QSerialPort::waitForReadyRead(int msecs = 30000) will timeout after msecs milliseconds; the default timeout is 30000 milliseconds. If msecs is -1, the function will not time out.
gets stuck on IOCTL_SERIAL_WAIT_ON_MASK
Most likelly a problem is in your HW or driver. QSP use asynchronous notification, based on WaitCommEvent. If WaitCommEvent get stuck - then a problem is in your device or driver (most likelly).
Thanks to the guys at QSerialPort, this bug in Qt 5.10.1 is solved by applying this patch: https://codereview.qt-project.org/#/c/225277/
"QSP may ignore all the read events when the data comes to the device
within opening. In this case, even re-opening of a device does not
help. Reason is that the QWinOverlappedIoNotifier is enabled after
than the startAsyncCommunication() called, that probably, leads to
ignoring for all EV_RXCHAR events. A workaround is to enable the
notifier before than any of I/O operation called." - Denis Shienkov, QSerialPort Maintainer

Using FTDI D2xx and Thorlabs APT communication protocol results in delays on Linux

I am trying to communicate with the Thorlabs TDC001 controllers (apt - dc servo controller) by using the FTDI D2xx driver on Linux. However, when I send writing commands, large delays occur (1-2 seconds) until the command is actually executed on TDC001.
In particular, this can be observed when the connected linear stage is moving and a new position command is sent. It takes 1-2 seconds until the stage actually changes its direction. Also, if I request DCSTATUSUPDATE (which gives position and velocity) and then read out the queue of FTDI, I do not get the right data. Only if I wait 1 second between requesting and reading, I get the (correct) data, but for the past. I added the C++ code for this case.
I need live-data and faster execution of writing commands for closed-loop control.
I'm not sure if the problem is on the side of Thorlabs or FTDI. Everything works, except for the large delays. There are other commands, e.g. MOVE_STOP, which respond immediately. Also, if I send a new position command right after finishing homing, it is executed immediately.
Whenever I ask for FT_GetStatus, there is nothing else in the Tx or Rx queue except the 20 bytes in Rx for DCSTATUSUPDATE.
The references for D2XX and APT communication protocol can be found here:
FTDI Programmer's Guide
Thorlabs APT Communication Protocol
The initialization function:
bool CommunicationFunctions::initializeKeyHandle(string serialnumber){
//INITIALIZATION//
/*
* This function initializes the TDC motor controller and finds its corresponding keyhandle.
*/
keyHandle = NULL;
// To open the device, the vendor and product ID must be set correctly
ftStatus = FT_SetVIDPID(0x403,0xfaf0);
}
//Open device:
const char* tmp = serialnumber.c_str();
int numAttempts=0;
while (keyHandle ==0){
ftStatus = FT_OpenEx(const_cast<char*>(tmp),FT_OPEN_BY_SERIAL_NUMBER, &keyHandle);
if (numAttempts++>20){
cerr << "Device Could Not Be Opened";
return false;
}
}
// Set baud rate to 115200
ftStatus = FT_SetBaudRate(keyHandle,115200);
// 8 data bits, 1 stop bit, no parity
ftStatus = FT_SetDataCharacteristics(keyHandle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE);
// Pre purge dwell 50ms.
usleep(50);
// Purge the device.
ftStatus = FT_Purge(keyHandle, FT_PURGE_RX | FT_PURGE_TX);
// Post purge dwell 50ms.
usleep(50);
// Reset device.
ftStatus = FT_ResetDevice(keyHandle);
// Set flow control to RTS/CTS.
ftStatus = FT_SetFlowControl(keyHandle, FT_FLOW_RTS_CTS, 0, 0);
// Set RTS.
ftStatus = FT_SetRts(keyHandle);
return true;
}
How I read out my data:
bool CommunicationFunctions::read_tdc(int32_t* position, uint16_t* velocity){
uint8_t *RxBuffer = new uint8_t[256]();
DWORD RxBytes;
DWORD BytesReceived = 0;
// Manually request status update:
uint8_t req_statusupdate[6] = {0x90,0x04,0x01,0x00,0x50,0x01};
ftStatus = FT_Write(keyHandle, req_statusupdate, (DWORD)6, &written);
if(ftStatus != FT_OK){
cerr << "Command could not be transmitted: Request status update" << endl;
return false;
}
// sleep(1); //**this sleep() would lead to right result, but I don't want this delay**
// Get number of bytes in queue of TDC001
FT_GetQueueStatus(keyHandle,&RxBytes);
// Check if there are bytes in queue before reading them, otherwise do
// not read anything in
if(RxBytes>0){
ftStatus=FT_Read(keyHandle,RxBuffer,RxBytes,&BytesReceived);
if(ftStatus != FT_OK){
cerr << "Read device failed!" << endl;
return false;
}
}
// Check if enough bytes are received, i.e. if signal is right
if(!(BytesReceived >= 6)){
cerr << "Error in bytes received" << endl;
return false;
}
// Look for correct message in RxBuffer and read out velocity and position
getPosVel(position,velocity,RxBuffer);
// Delete receive buffer
delete[] RxBuffer;
RxBuffer = NULL;
return true;
}
If I use read_tdc function after homing and during movement to absolute position, I just get "Homing completed" message in the first attempt. When I try read_tdc again, I get an old value (probably the one from before). I don't understand what happens here. Why does this old data even remain in the queue (latency is 10 ms). Can anybody help me to get faster responses and reactions?

VIDIOC_DQBUF hangs on camera disconnection

My application is using v4l2 running in a separate thread. If a camera gets disconnected then the user is given an appropriate message before terminating the thread cleanly. This works in the vast majority of cases. However, if the execution is inside the VIDIOC_DQBUF ioctl when the camera is disconnected then the ioctl doesn't return causing the entire thread to lock up.
My system is as follows:
Linux Kernel: 4.12.0
OS: Fedora 25
Compiler: gcc-7.1
The following is a simplified example of the problem function.
// Get Raw Buffer from the camera
void v4l2_Processor::get_Raw_Frame(void* buffer)
{
struct v4l2_buffer buf;
memset(&buf, 0, sizeof (buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
// Grab next frame
if (ioctl(m_FD, VIDIOC_DQBUF, &buf) < 0)
{ // If the camera becomes disconnected when the execution is
// in the above ioctl, then the ioctl never returns.
std::cerr << "Error in DQBUF\n";
}
// Queue for next frame
if (ioctl(m_FD, VIDIOC_QBUF, &buf) < 0)
{
std::cerr << "Error in QBUF\n";
}
memcpy(buffer, m_Buffers[buf.index].buff,
m_Buffers[buf.index].buf_length);
}
Can anybody shed any light on why this ioctl locks up and what I might do to solve this problem?
I appreciate any help offered.
Amanda
I am currently having the same issue. However, my entire thread doesn't lock up. The ioctl times out (15s) but thats way too long.
Is there a what to query V4L2 (that wont hang) if video is streaming? or at least change the ioctl timeout ?
UPDATE:
#Amanda you can change the timeout of the dequeue in the v4l2_capture driver source & rebuild the kernel/kernel module
modify the timeout in the dqueue function:
if (!wait_event_interruptible_timeout(cam->enc_queue,
cam->enc_counter != 0,
50 * HZ)) // Modify this constant
Best of luck!

What is the interface I have to inspect for detecting connected USB?

I'm trying to detect that a USB device was plugged or removed from within a qt programm via the method: http://doc.qt.io/qt-4.8/qdbusconnection.html#connect
My current code of the corresponding class looks like this:
#include "usbhandler.h"
#include <QDebug>
USBHandler::USBHandler()
{
QDBusConnection *bus;
bool success;
bus = new QDBusConnection("DeviceAdded");
if (bus == NULL)
{
qDebug() << "Allocation Error";
return;
}
if (!QDBusConnection::systemBus().isConnected())
{
qDebug() << "Cannot connect to system bus";
}
success = QDBusConnection::systemBus().connect(
"org.freedesktop.UDisks",
"/org/freedesktop/UDisks",
"org.freedesktop.UDisks",
"DeviceAdded",
this, SLOT(deviceAdded(QDBusObjectPath)));
if (success != true)
{
qDebug() << "Unsuccesfully connected!";
delete bus;
return;
}
}
void USBHandler::deviceAdded(QDBusObjectPath dev)
{
qDebug() << "device added!"<<dev.path();
}
When I'm running solid-hardware listen I get when plugging / unplugging, the following notifications:
Device Added:
udi = '/org/freedesktop/UDisks2/block_devices/sdb'
"/org/freedesktop/UDisks2/block_devices/sdb1" has new interfaces: ("org.freedesktop.UDisks2.Block", "org.freedesktop.UDisks2.Filesystem", "org.freedesktop.UDisks2.Partition")
Device Added:
udi = '/org/freedesktop/UDisks2/block_devices/sdb1'
"/org/freedesktop/UDisks2/block_devices/sdb1" lost interfaces: ("org.freedesktop.UDisks2.Partition", "org.freedesktop.UDisks2.Filesystem", "org.freedesktop.UDisks2.Block")
Device Removed:
udi = '/org/freedesktop/UDisks2/block_devices/sdb1'
"/org/freedesktop/UDisks2/block_devices/sdb" lost interfaces: ("org.freedesktop.UDisks2.PartitionTable", "org.freedesktop.UDisks2.Block")
Device Removed:
udi = '/org/freedesktop/UDisks2/block_devices/sdb'
So I was sure that the system notifys the USB stickAnd I'm now allready playing around for hours with the for the usb named interfaces but I can't get any success for my apllication reacting on pluggining/unplugging the stick.
So what Am I doing wrong?
What should be the interface and name paramter of connect() be like?
And can you explain me what exactly they do?
Device Added:
udi = '/org/freedesktop/UDisks2/block_devices/sdb'
"/org/freedesktop/UDisks2/block_devices/sdb1" has new interfaces:
I am not sure it is your problem, but the udi contains UDisks2, not UDisks. I suggest you adjust your call to connect(). Something like this:
success = QDBusConnection::systemBus().connect(
"org.freedesktop.UDisks",
"/org/freedesktop/UDisks2",
"org.freedesktop.UDisks2",
[...]);