ryzen-controller/js/methods.js

512 lines
16 KiB
JavaScript
Raw Permalink Normal View History

/**
* Will create a nodes from an html string.
* @param {string} str An html string
*/
function parseHTML(str) {
var tmp = document.implementation.createHTMLDocument();
tmp.body.innerHTML = str;
return tmp.body.children;
};
/**
* Return the current working directory.
*/
function getCurrentWorkingDirectory() {
2019-03-01 00:03:51 +07:00
const cwd = require('electron').remote.app.getAppPath()
appendLog(`getCurrentWorkingDirectory(): ${cwd}`);
return cwd;
}
/**
* Conversion from int to hex.
* @param {int} number A number.
*/
function decimalToHexString(number) {
if (number < 0)
{
number = 0xFFFFFFFF + number + 1;
}
2019-03-01 21:38:59 +07:00
return number.toString(16).toUpperCase();
}
/**
* Will execute the given callback once document is ready.
* @param {function} fn A callback to be executed.
*/
function ready(fn) {
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading"){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
/**
* Will make sure inputs are repeated when needed.
2019-03-01 21:38:59 +07:00
*
* Use the "repeat" html attribute to define where the current value must be repeated.
*/
function registerRepeaterForAllInput() {
var ranges = document.querySelectorAll('[repeat]');
for (const range in ranges) {
if (ranges.hasOwnProperty(range)) {
const element = ranges[range];
element.addEventListener('change', function(event) {
var repeater = document.getElementById(event.target.attributes.repeat.value);
repeater.value = event.target.value;
});
}
}
}
/**
* Check that the app is running with admin right.
2019-03-01 21:38:59 +07:00
*
* Will display a warning if not.
*/
function checkForAdminRights() {
2019-03-13 02:04:02 +07:00
if (require('os').platform() !== 'win32') {
2019-03-11 18:58:24 +07:00
const isRoot = process.getuid && process.getuid() === 0;
if (!isRoot) {
notification('danger',
`Warning: you must launch this app as administrator.<br/>`
+ `Use "sudo ryzencontroller" from terminal to fix this.`
);
}
} else {
2019-04-06 05:40:09 +07:00
const child = require('child_process').execFile;
child('NET SESSION', function(err,so,se) {
if (se.length !== 0) {
notification('warning',
2019-03-11 18:58:24 +07:00
`Warning: you should launch this app as administrator, `
2019-03-01 00:03:51 +07:00
+ `ryzenadj.exe doesn't seems to work correctly without administrator rights.`
);
}
});
}
2019-03-11 18:58:24 +07:00
}
/**
* Will display a notification in ".notification-zone".
* @param {string} type "primary", "warning", "danger" or "success".
* @param {string} message The message to be displayed, new line will be replaced by <br/>.
*/
function notification(type, message) {
2019-03-01 00:03:51 +07:00
appendLog(`notification(): ${type}\n${message}`);
2019-02-28 14:07:57 +07:00
UIkit.notification({
message: (''+message).replace(/(?:\r\n|\r|\n)/g, '<br/>'),
status: type,
pos: 'top-right',
timeout: 5000
});
}
2019-02-28 14:11:03 +07:00
/**
* Will return the ryzenadj.exe path registered, or default one if not provided.
*/
function getRyzenAdjExecutablePath() {
const settings = require('electron-settings');
var ryzen_adj_path = settings.get('settings.ryzen_adj_path');
2019-03-13 02:04:02 +07:00
if (!ryzen_adj_path && require('os').platform() === 'win32') {
2019-02-28 14:11:03 +07:00
ryzen_adj_path = getCurrentWorkingDirectory() + "\\bin\\ryzenadj.exe";
}
appendLog(`getRyzenAdjExecutablePath(): "${ryzen_adj_path}"`);
2019-02-28 14:11:03 +07:00
return ryzen_adj_path;
}
/**
* Will fill settings page on render with saved data.
*/
function preFillSettings() {
var ryzen_adj_path = document.getElementById('ryzen_adj_path');
2019-03-01 21:38:59 +07:00
var fs = require('fs');
2019-02-28 14:11:03 +07:00
ryzen_adj_path.value = getRyzenAdjExecutablePath();
2019-03-01 21:38:59 +07:00
if (!fs.existsSync(ryzen_adj_path.value)) {
2019-02-28 14:11:03 +07:00
notification('danger', "Path to ryzenadj.exe is wrong, please fix it in settings tab.");
}
const settings = require('electron-settings');
// document.getElementById('start_at_boot').checked = !!settings.get('settings.start_at_boot');
document.getElementById('apply_last_settings_on_launch').checked = !!settings.get('settings.apply_last_settings_on_launch');
document.getElementById('minimize_to_tray').checked = !!settings.get('settings.minimize_to_tray');
document.getElementById('start_minimized').checked = !!settings.get('settings.start_minimized');
seconds = parseInt(settings.get('settings.reapply_periodically'));
seconds = seconds >= 0 ? seconds : 0;
document.getElementById('reapply_periodically').value = seconds;
document.getElementById('reapply_periodically_range').value = seconds;
2019-02-28 14:11:03 +07:00
}
2019-03-01 00:21:55 +07:00
/**
* Will open a dialog to let user choose where is ryzenadj.exe.
*/
2019-02-28 14:11:03 +07:00
function askingForRyzenAdjExecutablePath() {
var remote = require('electron').remote;
var dialog = remote.require('electron').dialog;
2019-03-01 21:38:59 +07:00
2019-02-28 14:11:03 +07:00
var path = dialog.showOpenDialog({
2019-03-01 00:03:51 +07:00
properties: ['openFile']
2019-02-28 14:11:03 +07:00
}, function (filePaths) {
if (typeof filePaths[0] !== 'undefined') {
const settings = require('electron-settings');
2019-06-03 17:17:13 +07:00
settings.set("settings",
Object.assign(
{},
settings.get('settings'),
{ ryzen_adj_path: filePaths[0] }
)
);
notification('primary', 'Path to ryzenAdj executable has been saved.');
2019-03-01 00:03:51 +07:00
appendLog(`askingForRyzenAdjExecutablePath(): ${filePaths[0]}`);
2019-02-28 14:11:03 +07:00
} else {
notification('warning', 'No path given, nothing changed.');
}
preFillSettings();
});
}
2019-03-01 00:03:51 +07:00
2019-03-01 00:21:55 +07:00
/**
* Will append logs to the logs tab.
* @param {string} message The message to be logged.
*/
2019-03-01 00:03:51 +07:00
function appendLog(message) {
var log_area = document.getElementById('logs');
log_area.value += message + "\n";
console.log(message);
2019-03-01 00:23:05 +07:00
}
/**
* Will save the latest used settings.
*/
function saveLatestUsedSettings() {
2019-03-20 03:31:16 +07:00
var inputs = document.querySelectorAll('#controller-tab input, #experimental-tab input');
2019-03-01 00:23:05 +07:00
var latest_controller_tabs_settings = {};
inputs.forEach(element => {
let id = element.id;
let value = element.value;
if (id.indexOf('apply_') === 0) {
value = element.checked;
}
2019-03-01 00:23:05 +07:00
latest_controller_tabs_settings[id] = value;
});
const settings = require('electron-settings');
let ret = settings.set("latest_controller_tabs_settings", latest_controller_tabs_settings);
appendLog(`saveLatestUsedSettings(): ${JSON.stringify(latest_controller_tabs_settings)}`);
appendLog(`saveLatestUsedSettings(): ${JSON.stringify(ret)}`);
}
/**
* Will load the latest settings and refresh the controller tab's values.
2019-03-01 21:38:59 +07:00
*
* Will also apply latest settings if settings.apply_last_settings_on_launch is true.
2019-03-01 00:23:05 +07:00
*/
function loadLatestUsedSettings() {
const settings = require('electron-settings');
var latest_controller_tabs_settings = settings.get("latest_controller_tabs_settings");
appendLog(`loadLatestUsedSettings(): ${JSON.stringify(latest_controller_tabs_settings)}`);
for (const id in latest_controller_tabs_settings) {
if (latest_controller_tabs_settings.hasOwnProperty(id)) {
const value = latest_controller_tabs_settings[id];
let input = document.getElementById(id);
if (input) {
if (id.indexOf('apply_') === 0) {
input.checked = value;
} else {
2019-03-01 00:23:05 +07:00
input.value = value;
}
}
}
}
2019-03-08 01:59:22 +07:00
if (document.isStarting && settings.get('settings.apply_last_settings_on_launch')) {
applyRyzenSettings();
}
}
2019-03-01 22:26:34 +07:00
/**
* Will show or display options based on apply checkboxes value.
2019-03-01 22:26:34 +07:00
*/
function toggleOptionDisplayBasedOnApplyCheckbox() {
var checkbox_toggle_options = document.querySelectorAll('#controller-tab input[id^=apply_], #experimental-tab input[id^=apply_]');
2019-03-20 03:31:16 +07:00
const hideOptionBasedOnInput = function (input) {
if (input.checked) {
input.parentElement.parentElement.nextElementSibling.removeAttribute('hidden');
} else {
input.parentElement.parentElement.nextElementSibling.setAttribute('hidden', '');
}
}
Array.from(checkbox_toggle_options).forEach(input => {
hideOptionBasedOnInput(input);
input.addEventListener('change', function(event) {
hideOptionBasedOnInput(input);
});
});
}
/**
* Listen settings tab inputs to save their values.
*/
function registerEventListenerForSettingsInput() {
const settings = require('electron-settings');
2019-03-20 03:31:16 +07:00
toggleOptionDisplayBasedOnApplyCheckbox();
2019-03-20 03:31:16 +07:00
var apply_last_settings_on_launch = document.getElementById('apply_last_settings_on_launch');
apply_last_settings_on_launch.addEventListener('change', function() {
2019-06-03 17:17:13 +07:00
settings.set(
"settings",
Object.assign(
{},
settings.get('settings'),
{ apply_last_settings_on_launch: !!apply_last_settings_on_launch.checked }
)
);
});
var minimize_to_tray = document.getElementById('minimize_to_tray');
minimize_to_tray.addEventListener('change', function() {
2019-06-03 17:17:13 +07:00
settings.set(
"settings",
Object.assign(
{},
settings.get('settings'),
{ minimize_to_tray: !!minimize_to_tray.checked }
)
);
});
var start_minimized = document.getElementById('start_minimized');
start_minimized.addEventListener('change', function() {
2019-06-03 17:17:13 +07:00
settings.set(
"settings",
Object.assign(
{},
settings.get('settings'),
{ start_minimized: !!start_minimized.checked }
)
);
});
var reapply_periodically = document.getElementById('reapply_periodically');
reapply_periodically.addEventListener('change', function() {
reApplyPeriodically(reapply_periodically.value);
2019-06-03 17:17:13 +07:00
settings.set(
"settings",
Object.assign(
{},
settings.get('settings'),
{ reapply_periodically: reapply_periodically.value }
)
);
});
// var start_at_boot = document.getElementById('start_at_boot');
// start_at_boot.addEventListener('change', function() {
2019-06-03 17:17:13 +07:00
//
// settings.set(
// "settings",
// Object.assign(
// {},
// settings.get('settings'),
// { start_at_boot: !!start_at_boot.checked }
// )
// );
//
// require('electron').remote.app.setLoginItemSettings({ openAtLogin: !!start_at_boot.checked });
// });
2019-03-01 00:23:05 +07:00
}
2019-03-01 21:38:59 +07:00
2019-03-01 22:26:34 +07:00
/**
* Simply display version in appropriate zone.
*/
2019-03-01 21:38:59 +07:00
function displayVersion() {
const pjson = require('./package.json');
document.getElementById('version').innerHTML = `v${pjson.version}`;
}
/**
* Re-apply flow for "reapply_periodically" settings.
* @param {number} seconds Interval in seconds between each apply.
*/
function reApplyPeriodically(seconds) {
seconds = parseInt(seconds) >= 0 ? parseInt(seconds) : 0;
appendLog(`reApplyPeriodically(): seconds = ${seconds}`);
appendLog(`reApplyPeriodically(): document.reapplyLoop = ${document.reapplyLoop}`);
clearInterval(document.reapplyLoop);
document.reapplyLoop = false;
if (seconds <= 0) {
if (!document.isStarting) {
notification('primary', "Ryzen Controller no more will re-apply ryzenadj periodically.");
}
return;
}
document.reapplyLoop = setInterval(applyRyzenSettings, seconds * 1000);
}
/**
* Display tooltip on each options.
*/
2019-06-05 23:08:00 +07:00
function displayOptionData() {
const options_data = require('./js/options_data.json');
for (const option in options_data) {
if (options_data.hasOwnProperty(option)) {
const label = options_data[option].label;
const description = options_data[option].description;
const min = options_data[option].min;
const max = options_data[option].max;
const default_value = options_data[option].default;
const title_container = document.getElementById(option).parentElement.parentElement.previousElementSibling;
const title = title_container.getElementsByClassName('option-label');
const inputs = title_container.nextElementSibling.getElementsByTagName('input');
title_container.setAttribute('uk-tooltip', description);
UIkit.tooltip(title_container);
title[0].innerHTML = label;
for (const input of inputs) {
input.setAttribute('min', min);
input.setAttribute('max', max);
input.value = default_value;
}
}
}
}
/**
* Will recreate shortcut on launch ... no other solution for now :(
*/
function recreateShortcut() {
const settings = require('electron-settings');
if (!!settings.get('settings.first_launch')) {
let app = require('electron').remote.app;
let fs = require('fs');
try {
var shortcut_path = app.getPath('desktop') + "\\Ryzen Controller";
fs.unlink(shortcut_path, console.log);
fs.symlink(app.getPath('exe'), shortcut_path, function (err) {
if (err) {
notification("danger", "Shortcut can't be created, please check log tabs for more info.");
appendLog(`recreateShortcut(): ${err}`);
}
else {
notification('primary', "A shortcut has been created on desktop.");
}
});
} catch (error) {
appendLog(`recreateShortcut() ${error}`);
}
}
}
2019-03-08 02:00:12 +07:00
/**
* Will return an object completed with the current settings from inputs.
* @param {string} keyType "inputId" or "ryzenadjArgs"
*/
function getCurrentSettings(keyType) {
if (keyType === "ryzenadjArgs") {
2019-03-20 03:31:16 +07:00
const optionToId = {
2019-06-01 20:57:12 +07:00
"--psi0-current=": 'psi0_current_limit',
2019-03-20 03:31:16 +07:00
"--stapm-time=": 'stapm_time_ms',
"--stapm-limit=": 'stapm_limit_w',
"--fast-limit=": 'ppt_fast_limit_w',
"--slow-limit=": 'ppt_slow_limit_w',
"--tctl-temp=": 'temperature_limit_c',
"--vrmmax-current=": 'vrm_current_m_a',
"--min-fclk-frequency=": 'min_fclk_frequency',
"--max-fclk-frequency=": 'max_fclk_frequency',
"--min-gfxclk-frequency=": 'min_gfxclk_frequency',
"--max-gfxclk-frequency=": 'max_gfxclk_frequency',
"--min-socclk-frequency=": 'min_socclk_frequency',
"--max-socclk-frequency=": 'max_socclk_frequency',
2019-03-08 02:00:12 +07:00
};
2019-03-20 03:31:16 +07:00
var settingsToBeUsed = {};
for (const option in optionToId) {
if (optionToId.hasOwnProperty(option)) {
const elementId = optionToId[option];
if (document.getElementById('apply_' + elementId).checked) {
settingsToBeUsed[option] = document.getElementById(elementId).value;
}
}
}
appendLog('getCurrentSettings(): ' + JSON.stringify(settingsToBeUsed));
return settingsToBeUsed;
2019-03-08 02:00:12 +07:00
} else {
2019-03-20 03:31:16 +07:00
var inputs = document.querySelectorAll('#controller-tab input, #experimental-tab input');
2019-03-08 02:00:12 +07:00
var currentSettings = {};
inputs.forEach(element => {
let id = element.id;
let value = element.value;
currentSettings[id] = value;
});
return currentSettings;
}
}
2019-03-08 19:02:14 +07:00
/**
* Will check for new release.
*/
function checkForNewRelease() {
var request = new XMLHttpRequest();
const version = require('./package.json').version;
request.open('GET', 'https://gitlab.com/api/v4/projects/11046417/releases', true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
var resp = JSON.parse(this.response);
if (resp[0].tag_name !== version) {
notification('primary', "A new vesion is available, please check the release tab.");
}
}
};
request.send();
}
2019-04-06 05:40:09 +07:00
/**
* Will change the BCD entry value for userplatformclock.
*
* @param {string} value BCD entry value for userplatformclock: "true" or "false".
*/
function toggleHpet(value) {
value = value === "true" ? "true" : "false";
const BcdeditExecutablePath = "C:\\Windows\\System32\\bcdedit.exe";
2019-04-06 05:40:09 +07:00
const parameters = [
"/set",
"useplatformclock",
value,
];
const child = require('child_process').execFile;
child(BcdeditExecutablePath, parameters, function(err, data) {
var output = data.toString();
if (err) {
notification('danger', err + '<br/>' + output);
}
else if (output) {
notification('success', 'Bcdedit output:<br/>' + output);
saveLatestUsedSettings();
}
});
}
function handlePlatformSpecificDisplay() {
var windows_only_elements = document.getElementsByClassName('windows-only');
if (require('os').platform() !== 'win32') {
for (const item of windows_only_elements) {
item.setAttribute('hidden', 'true');
}
}
}