Compare commits

5 Commits
node ... main

Author SHA1 Message Date
helori_ollivier
c50c87af2d added some function (from lightbar state to speaker volume 2026-01-05 22:42:41 +01:00
helori_ollivier
ec83d74e66 added loging with log4j2 2026-01-05 22:03:19 +01:00
helori_ollivier
e2bde1fecb added getBattery() + setFeedback() 2026-01-05 21:53:27 +01:00
helori_ollivier
e22c4a2555 Merge remote-tracking branch 'dualsensgui/main' into node 2026-01-05 21:03:34 +01:00
e8a6d815cf Initial commit 2026-01-05 20:54:20 +01:00
37 changed files with 450 additions and 16 deletions

View File

@@ -0,0 +1 @@
spring.application.name=dualsensgui

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<!-- Define the appenders -->
<Appenders>
<!-- Console Appender -->
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<!-- File Appender -->
<File name="FileAppender" fileName="applogs/application_logs.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<!-- Define the loggers -->
<Loggers>
<!-- Root Logger -->
<Root level="info">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="FileAppender" />
</Root>
<!-- Logger for specific package -->
<Logger name="com.example.myapp" level="debug">
<AppenderRef ref="FileAppender" />
</Logger>
</Loggers>
</Configuration>

View File

@@ -0,0 +1 @@
spring.application.name=dualsensgui

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<!-- Define the appenders -->
<Appenders>
<!-- Console Appender -->
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<!-- File Appender -->
<File name="FileAppender" fileName="applogs/application_logs.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<!-- Define the loggers -->
<Loggers>
<!-- Root Logger -->
<Root level="info">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="FileAppender" />
</Root>
<!-- Logger for specific package -->
<Logger name="com.example.myapp" level="debug">
<AppenderRef ref="FileAppender" />
</Logger>
</Loggers>
</Configuration>

18
LICENSE Normal file
View File

@@ -0,0 +1,18 @@
MIT License
Copyright (c) 2026 risotto
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# dualsensgui
a simple gui to configure a dualsens controller

11
pom.xml
View File

@@ -54,6 +54,17 @@
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.12.4</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.12.4</version>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,45 @@
package bzh.risotto.dualsensgui;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Command {
private static final Logger logger = LogManager.getLogger(Command.class);
private Command() {
}
public static String run(String command) {
StringBuilder res = new StringBuilder();
command = "dualsensectl " + command;
String[] commandParts = command.split(" ");
logger.info("executing command: {}", command);
try {
ProcessBuilder processBuilder = new ProcessBuilder(commandParts);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
res.append(line);
}
process.waitFor();
} catch (Exception e) {
logger.error("Error while executing command: {}", command, e);
}
logger.debug(res);
return res.toString();
}
}

View File

@@ -0,0 +1,178 @@
package bzh.risotto.dualsensgui;
import bzh.risotto.dualsensgui.enums.MicrophoneLedState;
import bzh.risotto.dualsensgui.enums.MicrophoneModeState;
import bzh.risotto.dualsensgui.enums.SpeakerState;
import bzh.risotto.dualsensgui.enums.Trigger;
import bzh.risotto.dualsensgui.exception.OutOufBoundException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class DualsensController {
private static DualsensController dualsensController;
private static final Logger logger = LogManager.getLogger(DualsensController.class);
private DualsensController() {
}
//info Get the controller firmware info
/**
* get the state of the battery
*
* @return the battery level
*/
public int getBattery() {
String res = Command.run("battery");
String value = res.split(" ")[0];
return Integer.parseInt(value);
}
// lightbar STATE Enable (on) or disable (off) lightbar
public void enableLightbar() {
Command.run("lightbar on");
logger.info("lighbar enabled");
}
public void disableLightbar() {
Command.run("lightbar off");
logger.info("lighbar disabled");
}
// lightbar RED GREEN BLUE [BRIGHTNESS] Set lightbar color and brightness (0-255)
public void setLighbarColor(int red, int green, int blue) {
isBetween(red, 0, 255);
isBetween(green, 0, 255);
isBetween(blue, 0, 255);
Command.run("lightbar " + red + " " + green + " " + blue);
logger.info("lighbar color set to: R {}, G {}, B {}", red, green, blue);
}
public void setLighbarColor(int red, int green, int blue, int brightness) {
isBetween(red, 0, 255);
isBetween(green, 0, 255);
isBetween(blue, 0, 255);
isBetween(brightness, 0, 255);
Command.run("lightbar " + red + " " + green + " " + blue + " " + brightness);
logger.info("lighbar color set to: R {}, G {}, B {}, Brightness {}", red, green, blue, brightness);
}
// led-brightness NUMBER Set player and microphone LED dimming (0-2)
public void setLedBrightness(int brightness) {
isBetween(brightness, 0, 2);
Command.run("led-brightness " + brightness);
logger.info("led brightness set to: {}", brightness);
}
// player-leds NUMBER [instant] Set player LEDs (1-7) or disabled (0)
public void setLed(int playerLed) {
isBetween(playerLed, 0, 7);
Command.run("player-leds " + playerLed);
logger.info("player leds set to: {}", playerLed);
}
public void disableLed() {
Command.run("player-leds 0" );
logger.info("player leds disabled");
}
// microphone STATE Enable (on) or disable (off) microphone
public void enableMicrophone() {
Command.run("microphone on");
logger.info("microphone enabled");
}
public void disableMicrophone() {
Command.run("microphone off");
logger.info("microphone disabled");
}
// microphone-led STATE Enable (on), disable (off) or pulsate (pulse) microphone LED
public void setMicrophoneLed(MicrophoneLedState state) {
Command.run("microphone " + state);
logger.info("microphone led state set to: {}", state);
}
// microphone-mode STATE Toggle microphone usage to 'chat', 'asr' or 'both'
public void setMicrophoneMod(MicrophoneModeState state) {
Command.run("microphone-mode " + state);
logger.info("microphone mode set to: {}", state);
}
// microphone-volume VOLUME Set microphone volume (0-255)
public void setMicrophoneVolume(int volume) {
Command.run("microphone-volume " + volume);
logger.info("microphone volume set to: {}", volume);
}
// speaker STATE Toggle to 'internal' speaker, 'headphone' or 'both'
public void setSpeakerState(SpeakerState state) {
Command.run("speaker " + state);
logger.info("speaker state set to: {}", state );
}
// volume VOLUME Set audio volume (0-255) of internal speaker and headphone
public void setSpeakerVolume(int volume) {
isBetween(volume, 0, 255);
Command.run("volume " + volume);
logger.info("volume set to: {}", volume);
}
// attenuation RUMBLE TRIGGER Set the attenuation (0-7) of rumble/haptic motors and trigger vibration
// trigger TRIGGER off remove all effects
// trigger TRIGGER feedback POSITION STRENGTH set a resistance starting at position with a defined strength
public void setFeedback(Trigger trigger, int position, int strength) {
Command.run("trigger " + trigger + " feedback " + position + " " + strength);
}
// trigger TRIGGER weapon START STOP STRENGTH Emulate weapon like gun trigger
// trigger TRIGGER bow START STOP STRENGTH SNAPFORCE Emulate weapon like bow
// trigger TRIGGER galloping START STOP FIRST_FOOT SECOND_FOOT FREQUENCY Emulate a galloping
// trigger TRIGGER machine START STOP STRENGTH_A STRENGTH_B FREQUENCY PERIOD Switch vibration between to strength at a specified period
// trigger TRIGGER vibration POSITION AMPLITUDE FREQUENCY Vibrates motor arm around specified position
// trigger TRIGGER feedback-raw STRENGTH[10] set a resistance starting using array of strength
// trigger TRIGGER vibration-raw AMPLITUDE[10] FREQUENCY Vibrates motor arm at position and strength specified by an array of amplitude
// trigger TRIGGER MODE [PARAMS] set the trigger (left, right or both) mode with parameters (up to 9)
// monitor [add COMMAND] [remove COMMAND] Run shell command COMMAND on add/remove events
// power-off Turn off the controller (BT only)
public static DualsensController getController() {
if (dualsensController == null) {
dualsensController = new DualsensController();
}
return dualsensController;
}
private boolean isBetween(int number, int start, int stop) {
if (number < start || number > stop) {
throw new OutOufBoundException(number, start, stop);
}
return true;
}
}

View File

@@ -1,13 +1,21 @@
package main.java.bzh.risotto.dualsensgui;
package bzh.risotto.dualsensgui;
import org.springframework.boot.SpringApplication;
import bzh.risotto.dualsensgui.enums.Trigger;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DualsensguiApplication {
public static void main(String[] args) {
SpringApplication.run(DualsensguiApplication.class, args);
DualsensController controller = DualsensController.getController();
int battery = controller.getBattery();
System.out.println(battery);
controller.setFeedback(Trigger.LEFT, 1, 1);
controller.setLighbarColor(255, 0, 150);
//SpringApplication.run(DualsensguiApplication.class, args);
}
}

View File

@@ -0,0 +1,23 @@
package bzh.risotto.dualsensgui.enums;
public enum MicrophoneLedState {
ENABLE{
@Override
public String toString() {
return "on";
}
},
DISABLE {
@Override
public String toString() {
return "off";
}
},
PULSE {
@Override
public String toString() {
return "pulse";
}
}
}

View File

@@ -0,0 +1,22 @@
package bzh.risotto.dualsensgui.enums;
public enum MicrophoneModeState {
CHAT {
@Override
public String toString() {
return "chat";
}
},
ASR {
@Override
public String toString() {
return "asr";
}
},
BOTH {
@Override
public String toString() {
return "both";
}
}
}

View File

@@ -0,0 +1,22 @@
package bzh.risotto.dualsensgui.enums;
public enum SpeakerState {
INTERNAL {
@Override
public String toString() {
return "internal";
}
},
HEADPHONE {
@Override
public String toString() {
return "headphone";
}
},
BOTH {
@Override
public String toString() {
return "both";
}
},
}

View File

@@ -0,0 +1,25 @@
package bzh.risotto.dualsensgui.enums;
public enum Trigger {
LEFT {
@Override
public String toString(){
return "left";
}
},
RIGHT {
@Override
public String toString(){
return "right";
}
},
BOTH {
@Override
public String toString(){
return "both";
}
}
}

View File

@@ -0,0 +1,12 @@
package bzh.risotto.dualsensgui.exception;
public class OutOufBoundException extends RuntimeException {
public OutOufBoundException(int value, int start, int stop) {
super("Value: " + value + " is out off bound (" + start + "-" + stop + ")");
}
public OutOufBoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<!-- Define the appenders -->
<Appenders>
<!-- Console Appender -->
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<!-- File Appender -->
<File name="FileAppender" fileName="applogs/application_logs.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<!-- Define the loggers -->
<Loggers>
<!-- Root Logger -->
<Root level="info">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="FileAppender" />
</Root>
<!-- Logger for specific package -->
<Logger name="com.example.myapp" level="debug">
<AppenderRef ref="FileAppender" />
</Logger>
</Loggers>
</Configuration>

View File

@@ -1,13 +0,0 @@
package test.java.bzh.risotto.dualsensgui;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DualsensguiApplicationTests {
@Test
void contextLoads() {
}
}