Bluetooth interface control in C code ( Linux OS ) - bluetooth

Normally I can control the interface through the command
hciconfig hcix up/down
Can I do this by using c code ?
Is there sample code I can refer to ?
Thanks

You can use the c code for hciconfig itself. Just download the BlueZ source and open tools/hciconfig.c and use the following functions:-
static void cmd_up(int ctl, int hdev, char *opt)
{
...
}
and
static void cmd_down(int ctl, int hdev, char *opt)
{
...
}

Related

Debian+Unity: Game in "full screen" extended to two screen

I'm working on a Unity project in *Linux where I need to display the game/project on 2 screens using only 1 camera and 1 "display", for better performance.
What can i do to solve this problem? I will need set or modify something in the OS? Can i do it programmatically?
I'm using:
Debian with XFCE
Unity3d 2020.3.16f1
Rendering Pipeline: URP 2D
Edit:
For a exemple: I want to "combine" both monitors/display to act as one. So when i have two screen of 1920x1080 the game need to "extend" the window and work as if the screen was 1920x2160.
Current i tried to used the follow command in unity:
Screen.SetResolution(int width, int height, FullScreenMode
fullscreenMode);
with:
Width: 1920
Height: 2160
FullScreenMode: ExclusiveFullScreen, FullScreenWindow ,MaximizedWindow, Windowed.
In all the modes the game stayed in only one screen, liming it self to 1920x1080.
In Unity 2020.3.16f1, I couldn't find any direct solution for Linux (Debian).
The solution I found is to meddle with the X windows server, Xorg has been used as default since Debian 4.0.
The option I used:
Xorg has a module called Xrandr (Linux users probably already know that) that provides the xrandr commands in terminal and interacts with the configuration of the displays.
To check what displays are connected I use the command xrandr --listmonitors | grep '+' | awk {'print $4'}.
For me it return:
HDMI-0
HDMI-1
So to combine the display use the command xrandr --setmonitor CustomName auto HDMI-0,HDMI-1}, this create a virtual display.
As I want to set one screen above the other I use this xrandr --output HDMI-1 --above HDMI-0.
Now both display work as one.
I want Unity to call these commands, so that when the game opens it sets the configuration automatically, but because I am using the IL2CPP Scripting Backend I can't use Application.Process to call the commands. To solve that I create a lib in C++ 11, libSystemCommands.so, to execute the commands.
system_commands.cpp
#include "system_commands.h"
#include <vector>
#include <array>
#include <memory>
#include <cstring>
void system_command(const char * command){
std::system(command);
}
char* system_command_with_output(const char * command){
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE , decltype(&pclose)> pipe(popen(command,"r"), pclose);
if (!pipe) throw std::runtime_error("popopen() failed!");
while (fgets(buffer.data(),buffer.size(), pipe.get())!= nullptr)
result += buffer.data();
char * res = (char *) malloc(strlen(result.c_str())+1);
strcpy(res,result.c_str());
return res;
}
system_commands.h
#ifndef SYSTEMCOMMAND_LIBRARY_H
#define SYSTEMCOMMAND_LIBRARY_H
#if defined(_MSC_VER)
#ifdef NativePlugin_EXPORTS
#define NATIVEPLUGIN_API extern "C" __declspec(dllexport)
#else
#define NATIVEPLUGIN_API extern "C" __declspec(dllimport)
#endif
#else
#define NATIVEPLUGIN_API extern "C"
#endif
NATIVEPLUGIN_API void system_command(const char * command);
NATIVEPLUGIN_API char* system_command_with_output(const char * command);
#endif //SYSTEMCOMMAND_LIBRARY_H
In Unity I create the following script to control the changes:
DisplayManager.cs
using System;
using System.Runtime.InteropServices;
public static class DisplayManager
{
//List of displays/monitors connected
private static string[] _displays;
private static string[] _originalPositions;
//Detect the displays/monitors connected, using xrandr
public static void DetectDisplays()
{
//Get and set the display connected, to a list.
string result = system_command_with_output("xrandr --listmonitors | grep '+' | awk {'print $4'}");
_displays = result.Split(new string[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries);
// We want to run the rest only if there is two or more screens.
if (_displays.Length<=1) return;
// Get the original position of the two first display/monitors.
result = system_command_with_output(
"xrandr --listmonitors | grep '+' | awk '{print $3}' | awk -F'+' '{print $2,$3}'");
result = result.Replace(' ', 'x');
_originalPositions = result.Split(new string[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries);
}
//Combine two displays/monitors in one using xrandr
public static void CombineDisplays()
{
// We want to run this only if there is two or more screens.
if (_displays.Length<=1) return;
// xrandr command to create a virtual monitor combining others monitors.
system_command($"xrandr --setmonitor DisplayCombination auto {_displays[0]},{_displays[1]}");
// xrandr don´t apply the new virtual monitor automatically and don´t set a change if the input
// is equal of the current state. So the two command is to make sure to apple de combination and
// the display is one above another.
system_command($"xrandr --auto & xrandr --output {_displays[1]} --left-of {_displays[0]}");
// Set the desired position.
system_command($"xrandr --auto & xrandr --output {_displays[1]} --above {_displays[0]}");
}
//Reset the Display to before the Combination.
public static void ResetDisplays()
{
// Delete the virtual display created, if it exist
system_command("xrandr --delmonitor DisplayCombination");
// We want to run this only if there is two or more screens.
if (_displays.Length<=1) return;
// xrandr don´t apply the deletion of the virtual display automatically and don´t set a change
// if the input is equal of the current state. So the two command is to make sure to apple de
// deletion and reset the displays/monitors to the original position.
system_command($"xrandr --auto & xrandr --output {_displays[1]} --left-of {_displays[0]}");
//Set the Displays to their original position.
for(int i = 0; i <_displays.Length;i++)
system_command($"xrandr --output {_displays[i]} --pos {_originalPositions[i]}");
}
// function from the lib that intermediate the command execution with the system.
[DllImport("SystemCommands")]
private static extern void system_command(string command);
// function from the lib that intermediate the command execution with the system, with output.
[DllImport("SystemCommands")]
private static extern string system_command_with_output(string command);
}
And then in another script I only need to call this method and set the Screen.SetResolution to do the trick.
Example:
private int _newWidth;
private int _newHeight;
private void Awake()
{
_newWidth = Display.main.systemWidth;
_newHeight = Display.main.systemHeight;
if (Display.displays.Length > 1)
_newHeight += Display.displays[1].systemHeight;
DisplayManager.DetectDisplays();
DisplayManager.CombineDisplays();
}
private void Start()
{
Screen.SetResolution(_newWidth,_newHeight,FullScreenMode.FullScreenWindow);
}
private void OnApplicationQuit()
{
DisplayManager.ResetDisplays();
}
The other option (I didn’t check):
Is using the Xorg configuration folder, that is read when you login in account, together with the module Xinerama (I need to check if Xinerama is really needed).
Create a file at Xorg.conf.d, as ##-name.conf (“##” being a number identifies the priority of execution/reading, and “name” being something you can use to identify it more easily).
The folder can be at:
/etc/X11/Xorg.conf.d/
/user/shared/X11/Xorg.conf.d/
And you will need to setup a SERVERLAYOUT, and enable the option Xinerama.
Section "ServerLayout"
Identifier "name"
Screen "screen−id"
...
Option "Xinerama" "1"
...
EndSection
More information abou xorg at: https://www.x.org/releases/current/doc/man/man5/xorg.conf.5.xhtml#heading16
https://wiki.archlinux.org/title/multihead

Change remote device name and class via HCI

I have a bluetooth audio interface which I want to change the name and the CoD (Class of Device) parameter. I have tried doing this using hcitool on Ubuntu, with: sudo hcitool cmd 0x03 0x0024 0x260420 which is supposed to set the CoD to 0x260420 (it's currently 0x260404), but I've had no luck. From what I now understand, I take id that you cannot use hcitool on a Linux computer to send cmd commands to a bluetooth device connected to that computer via bluetooth. Is there a way to achieve this?
Is it at all possible to change a bluetooth devices' configuration remotely in any way?
You can try it with a small C script. We will use these two methods you can find in the hci_lib.h header file.
int hci_read_class_of_dev(int dd, uint8_t *cls, int to);
int hci_write_class_of_dev(int dd, uint32_t cls, int to);
Be aware that a Class of Device (CoD) has strict requirements you can find in the official Bluetooth documentation (here). That's why you need sudo to execute.
// Simple program to read and write Class of Device.
// To compile: `gcc -o rw_cod rw_cod.c -lbluetooth`
// To install lbluetooth: `apt-get install libbluetooth-dev`
// Execute with `sudo ./rw_cod`
// Note the original CoD first because it has strict rules, you might need to write it back later.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // for close()
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
int main(void){
int dd = hci_open_dev(hci_devid("DC:A6:32:E4:9C:05"));
int timeout = 1000;
uint8_t cls[3] = {0};
int class;
int ret;
uint32_t new_class = 0x260404;
// Read CoD
ret = hci_read_class_of_dev(dd, cls, timeout);
class = cls[0] | cls[1] << 8 | cls[2] << 16;
printf("Class of Device = 0x%06x [%d]\n", class, ret);
// Set CoD
ret = hci_write_class_of_dev(dd, new_class, 2000);
printf("Required new Class of Device = 0x%06x [%d]\n", new_class, ret);
// Check read CoD
ret = hci_read_class_of_dev(dd, cls, timeout);
class = cls[0] | cls[1] << 8 | cls[2] << 16;
printf("Actual new Class of Device = 0x%06x [%d]\n", class, ret);
close(dd);
return 0;
}
Console returns:
pi#raspberrypi:~/Work_Bluetooth $ sudo ./rw_cod
Class of Device = 0x260404 [0]
Required new Class of Device = 0x260420 [0]
Actual new Class of Device = 0x260420 [0]
pi#raspberrypi:~/Work_Bluetooth $

Processing/Bluetooth to Arduino

I want to light up a LED wirelessly through processing.
what I have so far.
I can (wirelessly) turn on my LED using a serial terminal called "Bluterm".
I can turn on my LED by pressing 1 or 0 to switch LED on and off in processing.
How can I leave Bluterm out of my equation and use processing to send the 1 and 0 through bluetooth.
Here is my code for processing:
import processing.serial.*;
Serial port;
String string;
void setup(){
String portName = Serial.list()[2]; //change the 0 to a 1 or 2 etc. to match your port
port = new Serial(this, portName, 9600);
port.bufferUntil('\n');
}
void draw() {
printArray(string);
}
void keyPressed() {
if (key =='1'){port.write('1');}
if (key=='0') {port.write('0');}
}
void serialEvent(Serial port) {
string = port.readStringUntil('\n');}
and the Arduino code
char data;
int led = 13;
void setup() {
pinMode(led, OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available()>0){
data = Serial.read();
}
if (data=='1'){
Serial.println("HELLO");
digitalWrite(led, HIGH);
}
else if (data=='0'){
digitalWrite(led, LOW);
Serial.println("BYE");}
}
I'm kind of lost, can processing talk to bluetooth or do I always need a terminal?
If something isn't clear pls don't hesitate to ask,
Thank you for your time,
Juriaan
The Processing code makes sense.
It could do with a bit of formatting and error checking, but it's all pretty much there:
import processing.serial.*;
Serial port;
String string = "";
void setup() {
String portName = Serial.list()[2]; //change the 0 to a 1 or 2 etc. to match your port
try{
port = new Serial(this, portName, 9600);
port.bufferUntil('\n');
}catch(Exception e){
e.printStackTrace();
}
}
void draw() {
background(0);
text(string,10,15);
}
void keyPressed() {
if(port != null){
if (key =='1') {
port.write('1');
}
if (key=='0') {
port.write('0');
}
}
}
void serialEvent(Serial port) {
string = port.readString();
if(string == null){
println("null serial string");
string = "";
}
}
The Arduino code looks legit too.
What's unclear is what Bluetooth module you're using and how you're setting it up.
For example, if you're using something like BlueSmirf, be sure to use the guide
supplied.
The main points are:
Make sure you're using the SerialPortProfile (SPP) Bluetooth Profile
Double check you're wiring: the way your Arduino code reads you would be connect BT module's TX to Arduino's RX pin 0 and BT module's RX pin to Arduino's TX pin 1. Note you may want to do that after you upload your firmware with Arduino (as pin's 0 and 1 are Arduino's hardware Serial), otherwise goto point 3 :) (recommeded)
If you use an Arduino with multiple hardware serial ports (like Arduino mega) go with those (e.g. Serial1 instead of Serial) otherwise use a SoftwareSerial library with a low baud rate (like 9600), avoiding high baud rates.
Update
The HC-05 module uses 3.3V logic, while the Arduino uses 5V logic.
Uses a bidirectional 3.3V <-> 5V logic level converter or resistors, otherwise you risk frying your HC-05 module:
A quick search returns a detailed HowToMechatronics.com Arduino and HC-05 Bluetooth Module Tutorial
i see u are using a hc05 bluetooth device i have this myself but i dont really get what u want to use for sending the 1 and 0 to your hc05 and are you only using a led becouse if it is i would be able to help on (if you wanna send the bluetooth signals with a mobile app try the blynk app fron app store or google play store)

Set system clock with QT on linux

How would we go about changing the system time on a linux system programatically using QT widget application ?
You can use dbus to interface with timedated daemon https://www.freedesktop.org/wiki/Software/systemd/timedated/
to set time and date.
Qt provides a way to generate interface code from xml
http://doc.qt.io/qt-5/qdbusxml2cpp.html. You can get xml by introspection.
I don't like generated code formatting so I wrote interface code myself
h:
#ifndef TIMEDATE1SERVICE_H
#define TIMEDATE1SERVICE_H
#include <QObject>
#include <QString>
#include <QVariant>
#include <QtDBus>
class Timedate1Interface: public QDBusAbstractInterface
{
Q_OBJECT
Q_PROPERTY(bool CanNTP READ CanNTP)
Q_PROPERTY(bool LocalRTC READ LocalRTC)
Q_PROPERTY(bool NTP READ NTP)
Q_PROPERTY(bool NTPSynchronized READ NTPSynchronized)
Q_PROPERTY(qulonglong RTCTimeUSec READ RTCTimeUSec)
Q_PROPERTY(qulonglong TimeUSec READ TimeUSec)
Q_PROPERTY(QString Timezone READ Timezone)
public:
explicit Timedate1Interface(QObject *parent = nullptr);
bool CanNTP() const;
bool LocalRTC() const;
bool NTP() const;
bool NTPSynchronized() const;
qulonglong RTCTimeUSec() const;
qulonglong TimeUSec() const;
QString Timezone() const;
void SetLocalRTC(bool localRTC, bool fixSystem, bool userInteraction);
void SetNTP(bool useNTP, bool userInteraction);
void SetTime(qlonglong usecUTC, bool relative, bool userInteraction);
void SetTimezone(const QString &timezone, bool userInteraction);
};
#endif // TIMEDATE1SERVICE_H
cpp:
#include "timedate1service.h"
Timedate1Interface::Timedate1Interface(QObject *parent)
: QDBusAbstractInterface("org.freedesktop.timedate1", "/org/freedesktop/timedate1",
"org.freedesktop.timedate1", QDBusConnection::systemBus(), parent)
{
}
bool Timedate1Interface::CanNTP() const
{
return qvariant_cast<bool>(property("CanNTP"));
}
bool Timedate1Interface::LocalRTC() const
{
return qvariant_cast<bool>(property("LocalRTC"));
}
bool Timedate1Interface::NTP() const
{
return qvariant_cast<bool>(property("NTP"));
}
bool Timedate1Interface::NTPSynchronized() const
{
return qvariant_cast<bool>(property("NTPSynchronized"));
}
qulonglong Timedate1Interface::RTCTimeUSec() const
{
return qvariant_cast<qulonglong>(property("RTCTimeUSec"));
}
qulonglong Timedate1Interface::TimeUSec() const
{
return qvariant_cast<qulonglong>(property("TimeUSec"));
}
QString Timedate1Interface::Timezone() const
{
return qvariant_cast<QString>(property("Timezone"));
}
void Timedate1Interface::SetLocalRTC(bool localRTC, bool fixSystem, bool userInteraction)
{
call("SetLocalRTC", localRTC, fixSystem, userInteraction);
}
void Timedate1Interface::SetNTP(bool useNTP, bool userInteraction)
{
call("SetNTP", useNTP, userInteraction);
}
void Timedate1Interface::SetTime(qlonglong usecUTC, bool relative, bool userInteraction)
{
call("SetTime", usecUTC, relative , userInteraction);
}
void Timedate1Interface::SetTimezone(const QString &timezone, bool userInteraction)
{
call("SetTimezone", timezone, userInteraction);
}
You cannot do that in pure Qt. You need to use Linux (or POSIX) specific things.
And you probably should not do that, but better yet configure your entire system to use NTP (e.g. by running some NTP client...). Most Linux distributions have that already.
If you really want to set the system time (but you should not do that directly from a Qt application, since Qt applications should not run as root, but see this), read time(7) then adjtimex(2) & settimeofday(2)
You need to be root for that, so you should not do that from a Qt application. You might use setuid techniques to run some specific command or program as root. Setuid is tricky (see credentials(7), execve(2), setreuid(2)...), could open a giant security hole if misused (and making mistakes is easy), so read something about Linux programming, e.g. the old ALP.
So if you insist doing that (and it is probably wrong), write a tiny specific program in C for that and make it setuid and run that setuid-program from your Qt application (e.g. using QProcess).
I found a simple solution. As my system is very minimalist i dont want to use things like dbus. As a root or sudoer this can be execute (fairly self explainatory )-
QString string = dateTime.toString("\"yyyy-MM-dd hh:mm\"");
QString dateTimeString ("date -s ");
dateTimeString.append(string);
int systemDateTimeStatus= system(dateTimeString.toStdString().c_str());
if (systemDateTimeStatus == -1)
{
qDebug() << "Failed to change date time";
}
int systemHwClockStatus = system("/sbin/hwclock -w");
if (systemHwClockStatus == -1 )
{
qDebug() << "Failed to sync hardware clock";
}

QAudioInput record sounds failed

For my purpose, I want to use Qt5.1 to record sounds in WAV format, 16000Hz, 16bit and 1 channel, but the sounds are all 32bit by default. So I must find a class that can set "Bit Size" and the class is QAudioFormat for there's a function setBitSize() in the class. So I can no longer use QAudioRecorder class for it can not take QAudioFormat as parameter but QAudioInput do. And I use QAudioInput to record sounds with the code below:
#include<QAudioFormat>
#include<QAudioInput>
#include<QString>
#include<QFile>
#include<QDebug>
int main()
{
QFile output;
output.setFileName("record.raw");
output.open(QIODevice::WriteOnly);
QAudioFormat settings;
settings.setCodec("audio/PCM");
settings.setSampleRate(16000);
settings.setSampleSize(16);
settings.setChannelCount(1);
settings.setByteOrder(QAudioFormat::LittleEndian);
settings.setSampleType(QAudioFormat::UnSignedInt);
QAudioInput *audio=new QAudioInput(settings);
audio->start(&output);
sleep(3);
audio->stop();
output.close();
delete audio;
return 0;
}
Well, after the program ran, the record.wav was still empty. I have successfully recorded the sounds using QAudioRecorder, and the only different is the QAudioRecorder class has setAudioInput() function (ie. "audio->setAudioInput("alsa:default");). So I think maybe it's the point of the problem, but QAudioInput has no function like this. That's my problem, maybe you can give my some advice and Thanks a lot:-)
I'm glad to have found someone with the same issue as mine. I've been trying to record from a microphone with QAudioRecorder but with a different sample size for a few days already. Thanks to your example I've succeeded by getting rid of QAudioRecorder. So it's my turn to help you.
I think while the program is in the sleep function it's not recording anymore. You need to use the concept of signal and slots provided by Qt to to record while the timer is running.
#include "AudioInput.h"
void AudioInput::setup(){
output.setFileName("record.raw");
output.open(QIODevice::WriteOnly);
QAudioFormat settings;
settings.setCodec("audio/PCM");
settings.setSampleRate(16000);
settings.setSampleSize(16);
settings.setChannelCount(1);
settings.setByteOrder(QAudioFormat::LittleEndian);
settings.setSampleType(QAudioFormat::UnSignedInt);
audio=new QAudioInput(settings);
audio->start(&output);
QTimer::singleShot(3000, this, SLOT(terminateRecording()));
}
void AudioInput::terminateRecording(){
audio->stop();
output.close();
delete audio;
}
I put your code in one class called AudioInput and the only difference is that I replaced sleep(3000) by QTimer::singleShot(3000, this, SLOT(terminateRecording()));. Contrary to sleep this function won't freeze the program during 3s but will just send a signal to terminateRecording() at the end of the time.
Here is the rest of the code:
int main(int argc, char** argv){
QCoreApplication app(argc,argv);
AudioInput t;
t.setup();
app.exec();
return 0;
}
and the header:
class AudioInput : public QObject{
Q_OBJECT
public Q_SLOTS:
void terminateRecording();
public:
void setup();
private:
QAudioInput *audio;
QFile output;
};
so basically the problem you seem to have is that the backend does not support the settings that you try to push into the QAudioInput. Luckily Qt has a way of getting the nearest usable format and here's hot to set it:
void AudioInput::setup(){
output.setFileName("record.raw");
output.open(QIODevice::WriteOnly);
QAudioFormat settings;
settings.setCodec("audio/PCM");
settings.setSampleRate(16000);
settings.setSampleSize(16);
settings.setChannelCount(1);
settings.setByteOrder(QAudioFormat::LittleEndian);
settings.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(settings)) {
settings = info.nearestFormat(settings); // This is the magic line
settings.setSampleRate(16000);
qDebug() << "Raw audio format not supported by backend. Trying the nearest format.";
}
audio=new QAudioInput(settings);
audio->start(&output);
QTimer::singleShot(3000, this, SLOT(terminateRecording()));
}

Resources