How to obtain mac address of a permanent interface in Qt - qt

My Qt application needs to uniquely identify computers it runs on. To achieve that, my current code probes its mac address using QNetworkInterface class like this:
QNetworkInterface intf;
#ifdef Q_WS_MAC
intf = QNetworkInterface::interfaceFromName(QString("en0"));
#endif
#ifdef Q_WS_WIN
intf = QNetworkInterface::interfaceFromIndex(0);
#endif
if(intf.isValid())
QString mac_address = intf.hardwareAddress();
It seems to work on the few machines I have tested it on. But is the above strategy guaranteed to work on all machines? For example, can one rename the interface name to something different from "en0" on a Mac? If so, is there a better way to probe the mac address for the interface that will not change over time?

Related

How to get Arduino/ESP32 device details in code?

I'm working on a project in which there is a server and several clients (ESP32). In short, It's client-server communication over WIFI. Right now, I'm using ESP32-wroom-32D. In future, for a client device, I might use some other Arduino device or other ESP32 module or a combination of both. For code simplicity, I shall be using the same code for both types of devices (Arduino/ ESP32) as they support a common Arduino platform. Therefore, I want to know if there is a way which I can get the device's information.
Eg.
Function: Get_device_details( ) or Get_device_id( ).
Output: "ESP32-Wroom-32D" or "Arduino Mega 2560"
The Arduino defines to identify a board are in form of ARDUINO_<board>, where <board> is the value from <x>.build.board from boards.txt for board <x>
For example for Arduino AVR boards, in the boards.txt file is uno.build.board=AVR_UNO so the define is ARDUINO_AVR_UNO.
And Arduino has 'architecture' identification define too. This has form of ARDUINO_ARCH_<arch.name>. The <arch.name> is the uppercase version of the folder name with the boards package version. For example AVR for packages/arduino/hardware/avr/1.6.21.
For esp boards, you can use the following arduino code to get chip ID,
#ifdef ESP8266
int chip_id = ESP.getChipId();
#elif defined(ESP32)
int chip_id = ESP.getEfuseMac();
#endif

Delay in Serial Communication when talking between Arduino and Python

I have an Arduino-controlled robot with a gyroscope, and I'm trying to send data from it over to a Python program run on a Raspberry Pi. However, there's a 1-2 second delay between me moving the robot, and info being printed out the python program. I've tried restarting my computer, as well as replugging the wires. Is there anything I'm doing in my code that is causing this or is it a hardware thing?
The robot is connected to a Raspberry Pi, with which I have a headless setup. The python program is being run on the Pi but can be viewed on my desktop over SSH. The program has no delay when I connect the robot to my desktop and run the python program on it as well.
Arduino Program:
#include <robot's file>
Gyro gyro; //Object using an imported class
void setup() {
Serial.begin(115200);
while (!Serial) {}
}
void loop() {
gyro.read(); //Reads the robot's yaw and puts it into variable "z"
Serial.println(gyro.z);
}
Python Program:
import serial
from serial.serialutil import SerialException
ser = serial.Serial("/dev/ttyACM0", 115200)
try:
ser.open()
except SerialException:
print("Port already opened")
while True: print(ser.readline())
looks to me that everything is good in your code.
Most of the delay is related to your PC computing time.
If you want to speed up the process I would suggest to interface an Oled display (or an LCD) to display directly your data: using your PC is good for the initial testing, but if you need immediate response it is better to manage the data interfacing directly.
This link may support you: https://www.waveshare.com/wiki/1.3inch_OLED_HAT All the best
After some testing, I think I've figured it out.
Printing to terminal takes a long time, which made the Arduino program faster than the Python program, creating a buildup of data, causing the delay. I've fixed the problem by only printing out data every 10 iterations. The problem would also be fixed if I stored the data into a variable, and did not call the print() function.

Making Linux LED class driver for serial port controlled LED device

I have a hardware device that controls LEDs on a panel, and it has a serial port for a PC to control the LEDs.
I would like to be able to control the LEDs from a userspace application using the Linux LED class API, i.e. via /sys/class/leds/whatever/brightness. So I'd like to make a Linux kernel driver for this device.
However, from what I've read, it seems unusual for a Linux kernel driver to open a serial device. E.g. StackOverflow question Accessing a serial port from a linux kernel module. I've read about filp_open() which can be used by kernel drivers to open device files, but its use seems to be discouraged.
On the other hand, it seems impossible to implement this in userspace because I'm not aware of a way to create a Linux LED class device from userspace.
What would be a good way to provide a Linux LED class API interface to a serial port controlled LED device?
Disregard the cautions against accessing a serial port from a Linux driver using filp_open()?
Is there some userspace way to create a Linux LED class device, so I could implement this in userspace?
Give up on the idea of using the Linux LEDs class API, and use an alternative API for the userspace application to control the LEDs?
Other?
Custom tty line discipline driver
As far as I can tell, one way to do this in Linux would be to write a custom tty line discipline kernel driver that implements the Linux LED API and sends the commands to the serial port. Then the Linux LED code can be in a kernel driver, but it's not tied to a specific serial port.
Then, to link it to a particular serial port, a userspace program would open the serial port, and use an ioctl(serial_fd, TIOCSETD, ...) call to attach the serial port to the custom line discipline driver. The line discipline driver does all the work from that point. The userspace program's only purpose is really to associate the custom line discipline driver with the right serial device.
Pseudo-driver using FUSE filesystem
One alternative would be to write a userspace program that is a "pseudo-driver", that connects to the serial device, and provides an LED API resembling the Linux kernel LED class API, but at a different location, using a FUSE filesystem.
For example, the program might be named foo-serial-leds and it could provide a number of LEDs under /var/run/foo-serial-leds/ with an API resembling the Linux kernel LED class drivers.
Then another program could control the LEDs by writing to e.g. /var/run/foo-serial-leds/status/brightness. That would be very similar to the program controlling a real Linux kernel LED class at /sys/class/leds/status/brightness, except the location on the filesystem is different. That program would be portable to another platform, with different LED devices, as long as the program has a configurable filesystem path for the LEDs it wants to control.
Two disadvantages of this:
The program that wants to control the LED must be flexible enough to access the LED file API in a different location than the normal /sys/class/leds/
These pseudo-driver LEDs can't use Linux kernel LED triggers
Custom driver to allow userspace creation of LED devices
Another option would be to write a Linux kernel driver that allows for userspace programs to create LED devices in the Linux kernel LED class. The driver could use configfs to allow userspace programs to create the LED devices, which would then appear under /sys/class/leds/. It would need to provide a way to notify the userspace program when the LED brightness is changed (maybe via sysfs_notify() on a custom sysfs attribute, which the userspace program can poll()).
With that driver in place, a userspace program could implement the LED API and write to the serial device to achieve the LED control. This program is kind of a userspace driver. I.e. it would use the Linux driver to create one or more LED-class LEDs, and open the serial port to talk to the LED hardware. When it is notified that something has written to the LED brightness, it would need to send the relevant command to the serial device.
Then other userspace programs that want to control LEDs would be able to write to the LED-class API in the usual location under /sys/class/leds/.
Linux kernel 4.10 userspace LED class driver
Update November 2017: Linux kernel 4.10 adds a userspace LED class driver, uleds. It implements something like what is described above. However, control is via a device /dev/uleds, not via configfs.
An app should open the char device file /dev/uleds once for each user LED it wants to create. It should write a struct to the file, which specifies the name of the LED. Then it should do reads from the open file handle, and will receive an int which specifies the brightness of the LED whenever that LED's brightness is changed by something else in the system. If multiple LEDs are to be created, the app should open the char device file multiple times, once for each LED.
When the app closes, and the open file handle(s) to /dev/uleds is closed, then the user LED is automatically removed.
3 Ways:
1 - You must to understand the data send to CPU Board for modify as you want data for display your message on led board.
2 - You must to have a linux API, but most of time the CPU is made in china, the chinese don't like linux.
3 - You write your own API for control LED Board with arduino or raspberry to control each pins of your LED Board.
Good luck !

QSerialPortInfo : Finding the USB hardware location of a virtual serial Port

I have a USB hub chip, and a micro controller connected to it on one of its ports.
I am able to enumerate, and communicate with the micro controller with QSerialPortInfo / QSerialPort.
My problem is, that I have to tell if a general USB device is connected to the same USB hub as my micro controller or not.
This should be easy, I can tell the general USB device's hardware location, like "Port_#0001.Hub_#0010", so if the Hub_# number is the same as where the micro controller is connected, I can tell that it is the same hub they are connected to.
The problem is that QSerialPortInfo.systemLocation() return with "\.\COM31" string, and not someting like "Port_#0002.Hub_#0010".
How can I obtain what USB hardware path does the QSerialPortInfo / QSerialPort belong to?
Additional info:
Windows 7, Qt 5.3, C++11
QSerialPortInfo returns information:
QSerialPortInfo.portName() == "COM31"
QSerialPortInfo.description() == "LPC USB VCom Port"
QSerialPortInfo.serialNumber() == "" // (Empty string)
While windows device manager shows the real USB correctly: (sorry can't post images yet)
DeviceManager > Ports(COM & LPT) > LPC USB VCom Port (COM31)
Properties > General > Location: Port_#0002.Hub_#0010
How could I access this information from my Qt code?
Well, managed to get is working, but its not the desired solution:
I use the SetupDiGetClassDevs windows api call to get all devices for a specific GUID, then with the SetupDiGetDeviceRegistryProperty winApi I get properties until I find the specific port the MCU is located on, and initialize a QSerialPort with that port name. Then the properties SPDRP_LOCATION_PATHS and SPDRP_LOCATION_INFORMATION provide information that is usable to detect if a general USB device is on the same hub.
The problem is that this is a "Throw away the high level API that Qt provides and start to mess around with winApi" solution. I would rather avoid this. If there is a more Qt like, and less direct winApi dependent solutions for this it would be appreciated.

List machine's serial ports

I have an Arduino-based device which connects through USB.
I'd like to detect it from my Qt 4 application, using QExtSerialPort (or whatever necessary), when it's plugged in.
If this weren't possible, I thought I could somehow get a list of the system's port names and just try all of them in search for my Arduino (where I'd implement some kind of handshaking procedure for it to detect it correctly). My concern in this approach is that I'm not sure if a device (for example, printer) would get damaged if I send some kind of handshaking ack at a different baud rate.
So, I don't really know where to start for any of them. Which would be the best approach? How would I implement it?
I believe you can find list of serial ports on Windows by looking into
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
registry key
Each serial port on a UNIX system has one or more device files (files in the /dev directory) associated with it:
System Port 1 Port 2
IRIX® /dev/ttyf1 /dev/ttyf2
HP-UX /dev/tty1p0 /dev/tty2p0
Solaris®/SunOS® /dev/ttya /dev/ttyb
Linux® /dev/ttyS0 /dev/ttyS1
Digital UNIX® /dev/tty01 /dev/tty02
more details on serial programing on POSIX systems here
Since your device is USB, your UART port will be emulated by some kind of conversor in his hardware. So first you must understand what driver is being used on your system.
The most common SERIAL->USB conversor uses PL2303/PL2301 chip, so it would create a path on /dev, if its the first device, it will appear as "/dev/ttyUSB0", but you may also see the list reading the proc path (like "cat /proc/bus/usb/devices").
Under Windows it usually creates a virtual "COM", just go to device manager and check the port.
When you are sure about how the HW talks to your system, you may use QExtSerialPort for wrapping the system API and talk to the device.
Way too hard and too platform specific, using weird Windows Registry keys or rely on hard wired device nodes on Linux.
You are on the right way. Get QextSerialPort or QSerialDevice (which I preffer in my projects, because it got integrated in Qt5), have a look at the examples and simply use it. In both libraries you get some kind of port enumerator class which returns you a list of all configures serial ports. Only platform/device specific settings you will have to do manually (like getting RS485 in half-duplex mode on my current embedded project), but "standard" problems are perfectly encapsulated in a QIODevice implementation.
You can use both QextSerialPort and QSerialDevice like a file. Open it (instead of a filename you specify the device name ie. "COM1" on Windows or "/dev/tty0" on Linux, depending on your configuration) and then read or write like you are doing it with an ordinary QFile, QBuffer, Qwhatever-inherits-from-QIODevice.
If you have any problems opening the port and communicating, don't hesitate to ask! :)

Resources