diff --git a/core.js b/core.js
index c8e428a..f919d6c 100644
--- a/core.js
+++ b/core.js
@@ -1,7 +1,10 @@
var device = null;
var devname = "";
var mode = 0;
-var disable_btn = false;
+
+// bitmask: 1: clone, 2: update ds5 firmware, 4: battery low, 8: ds-edge not supported
+var disable_btn = 0;
+var last_disable_btn = 0;
var lang_orig_text = {};
var lang_cur = {};
@@ -94,11 +97,18 @@ function is_rare(hw_ver) {
async function ds4_info() {
try {
+ var ooc = l("unknown");
+ var is_clone = false;
+
const view = lf("ds4_info", await device.receiveFeatureReport(0xa3));
var cmd = view.getUint8(0, true);
- if(cmd != 0xa3 || view.buffer.byteLength != 49) {
- return false;
+
+ if(cmd != 0xa3 || view.buffer.byteLength < 49) {
+ if(view.buffer.byteLength != 49) {
+ ooc = l("clone");
+ is_clone = true;
+ }
}
var k1 = new TextDecoder().decode(view.buffer.slice(1, 0x10));
@@ -110,19 +120,16 @@ async function ds4_info() {
var hw_ver_minor= view.getUint16(0x23, true)
var sw_ver_major= view.getUint32(0x25, true)
var sw_ver_minor= view.getUint16(0x25+4, true)
- var ooc = l("unknown");
-
- ooc = l("original");
-
- var is_clone = false;
try {
- const view = await device.receiveFeatureReport(0x81);
- ooc = l("original");
+ if(!is_clone) {
+ const view = await device.receiveFeatureReport(0x81);
+ ooc = l("original");
+ }
} catch(e) {
la("clone");
is_clone = true;
ooc = "" + l("clone") + "";
- disable_btn = true;
+ disable_btn |= 1;
}
clear_info();
@@ -145,7 +152,7 @@ async function ds4_info() {
}
} catch(e) {
ooc = "" + l("clone") + "";
- disable_btn = true;
+ disable_btn |= 1;
}
return true;
}
@@ -516,7 +523,7 @@ async function ds5_info() {
old_controller = build_date.search(/ 2020| 2021/);
if(old_controller != -1) {
la("ds5_info_error", {"r": "old"})
- disable_btn = true;
+ disable_btn |= 2;
return true;
}
@@ -784,7 +791,7 @@ async function disconnect() {
mode = 0;
device.close();
device = null;
- disable_btn = false;
+ disable_btn = 0;
reset_circularity();
$("#offlinebar").show();
$("#onlinebar").hide();
@@ -1118,6 +1125,46 @@ function refresh_sticks() {
setTimeout(timeout_ok, 20);
}
+var last_bat_txt = "";
+var last_bat_disable = null;
+
+function bat_percent_to_text(bat_charge, is_charging, is_error) {
+ var icon_txt = "";
+
+ if(bat_charge < 20) {
+ icon_txt = 'fa-battery-empty';
+ } else if(bat_charge < 40) {
+ icon_txt = 'fa-battery-quarter';
+ } else if(bat_charge < 60) {
+ icon_txt = 'fa-battery-half';
+ } else if(bat_charge < 80) {
+ icon_txt = 'fa-battery-three-quarters';
+ } else {
+ icon_txt = 'fa-battery-full';
+ }
+
+ var icon_full = '';
+ var bolt_txt = '';
+ if(is_charging)
+ bolt_txt = '';
+ bat_txt = bat_charge + "%" + ' ' + bolt_txt + ' ' + icon_full;
+
+ if(is_error) {
+ bat_txt = '' + l("error") + '';
+ }
+ return bat_txt;
+}
+
+function update_battery_status(bat_capacity, cable_connected, is_charging, is_error) {
+ var bat_txt = bat_percent_to_text(bat_capacity, is_charging);
+ var can_use_tool = (bat_capacity >= 30 && cable_connected && !is_error);
+
+ if(bat_txt != last_bat_txt) {
+ $("#d-bat").html(bat_txt);
+ last_bat_txt = bat_txt;
+ }
+}
+
function process_ds4_input(data) {
var lx = data.data.getUint8(0);
var ly = data.data.getUint8(1);
@@ -1137,8 +1184,46 @@ function process_ds4_input(data) {
ll_updated = true;
refresh_sticks();
}
+
+ // Read battery
+ var bat = data.data.getUint8(29);
+ var bat_data = bat & 0x0f;
+ var bat_status = (bat >> 4) & 1;
+
+ var bat_capacity = 0;
+ var cable_connected = false;
+ var is_charging = false;
+ var is_error = false;
+
+ if(bat_status == 1) {
+ cable_connected = true;
+ if(bat_data < 10) {
+ bat_capacity = Math.min(bat_data * 10 + 5, 100);
+ is_charging = true;
+ } else if(bat_data == 10) {
+ bat_capacity = 100;
+ is_charging = true;
+ } else if(bat_data == 11) {
+ bat_capacity = 100;
+ // charged
+ } else {
+ // error
+ bat_capacity = 0;
+ is_error = true;
+ }
+ } else {
+ cable_connected = false;
+ if(bat_data < 10) {
+ bat_capacity = bat_data * 10 + 5;
+ } else {
+ bat_capacity = 100;
+ }
+ }
+
+ update_battery_status(bat_capacity, cable_connected, is_charging, is_error);
}
+
function process_ds_input(data) {
var lx = data.data.getUint8(0);
var ly = data.data.getUint8(1);
@@ -1158,6 +1243,30 @@ function process_ds_input(data) {
ll_updated = true;
refresh_sticks();
}
+
+ var bat = data.data.getUint8(52);
+ var bat_charge = bat & 0x0f;
+ var bat_status = bat >> 4;
+
+ var bat_capacity = 0;
+ var cable_connected = false;
+ var is_charging = false;
+ var is_error = false;
+
+ if(bat_status == 0) {
+ bat_capacity = Math.min(bat_charge * 10 + 5, 100);
+ } else if(bat_status == 1) {
+ bat_capacity = Math.max(bat_charge * 10 + 5, 100);
+ is_charging = true;
+ cable_connected = true;
+ } else if(bat_status == 2) {
+ bat_capacity = 100;
+ cable_connected = true;
+ } else {
+ is_error = true;
+ }
+
+ update_battery_status(bat_capacity, cable_connected, is_charging, is_error);
}
async function continue_connection(report) {
@@ -1202,7 +1311,7 @@ async function continue_connection(report) {
connected = true;
mode = 0;
devname = l("Sony DualSense Edge");
- disable_btn = true;
+ disable_btn |= 8;
}
} else {
$("#btnconnect").prop("disabled", false);
@@ -1228,17 +1337,8 @@ async function continue_connection(report) {
return;
}
- if(disable_btn) {
- if(device.productId == 0x0ce6) {
- show_popup(l("This DualSense controller has outdated firmware.") + "
" + l("Please update the firmware and try again."), true);
- } else if(device.productId == 0x0df2) {
- show_popup(l("Calibration of the DualSense Edge is not currently supported."));
- } else {
- show_popup(l("The device appears to be a DS4 clone. All functionalities are disabled."));
- }
- }
-
- $(".ds-btn").prop("disabled", disable_btn);
+ if(disable_btn != 0)
+ update_disable_btn();
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
@@ -1250,10 +1350,36 @@ async function continue_connection(report) {
}
}
+function update_disable_btn() {
+ if(disable_btn == last_disable_btn)
+ return;
+
+ if(disable_btn == 0) {
+ $(".ds-btn").prop("disabled", false);
+ last_disable_btn = 0;
+ return;
+ }
+
+ $(".ds-btn").prop("disabled", true);
+
+ // show only one popup
+ if(disable_btn & 1 && !(last_disable_btn & 1)) {
+ show_popup(l("The device appears to be a DS4 clone. All functionalities are disabled."));
+ } else if(disable_btn & 2 && !(last_disable_btn & 2)) {
+ show_popup(l("This DualSense controller has outdated firmware.") + "
" + l("Please update the firmware and try again."), true);
+ } else if(disable_btn & 8 && !(last_disable_btn & 8)) {
+ show_popup(l("Calibration of the DualSense Edge is not currently supported."));
+ } else if(disable_btn & 4 && !(last_disable_btn & 4)) {
+ show_popup(l("Please charge controller battery over 30% to use this tool."));
+ }
+ last_disable_btn = disable_btn;
+}
+
async function connect() {
gj = crypto.randomUUID();
reset_circularity();
la("begin");
+ last_bat_txt = "";
try {
$("#btnconnect").prop("disabled", true);
$("#connectspinner").show();
diff --git a/index.html b/index.html
index 2873c5e..d5ef6e6 100644
--- a/index.html
+++ b/index.html
@@ -10,9 +10,14 @@
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
+
+