492 lines
24 KiB
JavaScript
492 lines
24 KiB
JavaScript
var __awaiter = this && this.__awaiter || function(e, t, i, n) {
|
|
return new(i || (i = Promise))((function(a, r) {
|
|
function s(e) {
|
|
try {
|
|
o(n.next(e))
|
|
} catch (e) {
|
|
r(e)
|
|
}
|
|
}
|
|
|
|
function l(e) {
|
|
try {
|
|
o(n.throw(e))
|
|
} catch (e) {
|
|
r(e)
|
|
}
|
|
}
|
|
|
|
function o(e) {
|
|
var t;
|
|
e.done ? a(e.value) : (t = e.value, t instanceof i ? t : new i((function(e) {
|
|
e(t)
|
|
}))).then(s, l)
|
|
}
|
|
o((n = n.apply(e, t || [])).next())
|
|
}))
|
|
};
|
|
const CUST_REV_ADV = 2;
|
|
var CustPlatform;
|
|
! function(e) {
|
|
e[e.Undefined = 0] = "Undefined", e[e.Erista = 1] = "Erista", e[e.Mariko = 2] = "Mariko", e[e.All = 3] = "All"
|
|
}(CustPlatform || (CustPlatform = {}));
|
|
class CustEntry {
|
|
constructor(e, t, i, n, a, r, s = [0, 1e6], l = 1, o = !0) {
|
|
this.id = e, this.name = t, this.platform = i, this.size = n, this.desc = a, this.defval = r, this.step = l, this.zeroable = o, this.min = s[0], this.max = s[1]
|
|
}
|
|
validate() {
|
|
let e = new ErrorToolTip(this.id).clear();
|
|
return Number.isNaN(this.value) || void 0 === this.value ? (e.setMsg("Invalid value: Not a number").show(), !1) : !(!this.zeroable || 0 != this.value) || (this.value < this.min || this.value > this.max ? (e.setMsg(`Expected range: [${this.min}, ${this.max}], got ${this.value}.`).show(), !1) : this.value % this.step == 0 || (e.setMsg(`${this.value} % ${this.step} ≠ 0`).show(), !1))
|
|
}
|
|
getInputElement() {
|
|
return document.getElementById(this.id)
|
|
}
|
|
updateValueFromElement() {
|
|
var e;
|
|
this.value = Number(null === (e = this.getInputElement()) || void 0 === e ? void 0 : e.value)
|
|
}
|
|
isAvailableFor(e) {
|
|
return e === CustPlatform.Undefined || this.platform === e || this.platform === CustPlatform.All
|
|
}
|
|
createElement() {
|
|
let e = this.getInputElement();
|
|
if (!e) {
|
|
let t = document.createElement("div");
|
|
t.classList.add("grid", "cust-element"), e = document.createElement("input"), e.min = String(this.zeroable ? 0 : this.min), e.max = String(this.max), e.id = this.id, e.type = "number", e.step = String(this.step);
|
|
let i = document.createElement("label");
|
|
i.setAttribute("for", this.id), i.innerHTML = this.name, i.appendChild(e), t.appendChild(i);
|
|
let n = document.createElement("blockquote");
|
|
n.innerHTML = "<ul>" + this.desc.map((e => `<li>${e}</li>`)).join("") + "</ul>", n.setAttribute("for", this.id), t.appendChild(n), document.getElementById("config-list-basic").appendChild(t), new ErrorToolTip(this.id).addChangeListener()
|
|
}
|
|
e.value = String(this.value)
|
|
}
|
|
setElementValue() {
|
|
this.getInputElement().value = String(this.value)
|
|
}
|
|
setElementDefaultValue() {
|
|
this.getInputElement().value = String(this.defval)
|
|
}
|
|
removeElement() {
|
|
let e = this.getInputElement();
|
|
e && e.parentElement.parentElement.remove()
|
|
}
|
|
showElement() {
|
|
let e = this.getInputElement();
|
|
e && e.parentElement.parentElement.style.removeProperty("display")
|
|
}
|
|
hideElement() {
|
|
let e = this.getInputElement();
|
|
e && e.parentElement.parentElement.style.setProperty("display", "none")
|
|
}
|
|
}
|
|
class AdvEntry extends CustEntry {
|
|
createElement() {
|
|
let e = this.getInputElement();
|
|
if (!e) {
|
|
let t = document.createElement("div");
|
|
t.classList.add("grid", "cust-element"), e = document.createElement("input"), e.min = String(this.zeroable ? 0 : this.min), e.max = String(this.max), e.id = this.id, e.type = "number", e.step = String(this.step);
|
|
let i = document.createElement("label");
|
|
i.setAttribute("for", this.id), i.innerHTML = this.name, i.appendChild(e), t.appendChild(i);
|
|
let n = document.createElement("blockquote");
|
|
n.innerHTML = "<ul>" + this.desc.map((e => `<li>${e}</li>`)).join("") + "</ul>", n.setAttribute("for", this.id), t.appendChild(n), document.getElementById("config-list-advanced").appendChild(t), new ErrorToolTip(this.id).addChangeListener()
|
|
}
|
|
e.value = String(this.value)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class GpuEntry extends CustEntry {
|
|
constructor(e, t, i = CustPlatform.Mariko, n = 4, a = ["range: vMin ≤ x ≤ 960 (Zero is disabled)"], r = 480, s = [0, 960], l = 5, o = !1) {
|
|
super(e, t, i, n, a, r, s, l, o), this.id = e, this.name = t, this.platform = i, this.size = n, this.desc = a, this.defval = r, this.step = l, this.zeroable = o
|
|
}
|
|
createElement() {
|
|
let e = this.getInputElement();
|
|
if (!e) {
|
|
let t = document.createElement("div");
|
|
t.classList.add("grid", "cust-element"), e = document.createElement("input"), e.min = String(this.zeroable ? 0 : this.min), e.max = String(this.max), e.id = this.id, e.type = "number", e.step = String(this.step);
|
|
let i = document.createElement("label");
|
|
i.setAttribute("for", this.id), i.innerHTML = this.name, i.appendChild(e), t.appendChild(i);
|
|
let n = document.createElement("blockquote");
|
|
n.innerHTML = "<ul>" + this.desc.map((e => `<li>${e}</li>`)).join("") + "</ul>", n.setAttribute("for", this.id), t.appendChild(n), document.getElementById("config-list-gpu").appendChild(t), new ErrorToolTip(this.id).addChangeListener()
|
|
}
|
|
e.value = String(this.value)
|
|
}
|
|
}
|
|
var CustTable = [
|
|
new CustEntry("mtcConf", "DRAM Timing", CustPlatform.All, 4, [
|
|
"<b>0</b>: AUTO_ADJ_ALL: Auto adjust mtc table with LPDDR4 3733 Mbps specs, 8Gb density. Change timing with Advanced Config (Default)",
|
|
"<b>1</b>: CUSTOM_ADJ_ALL: Adjust only non-zero preset timings in Advanced Config",
|
|
"<b>2</b>: NO_ADJ_ALL: Use 1600 mtc table wihout adjusting (Timing becomes tighter if you raise dram clock)."
|
|
], 0, [0, 2], 1),
|
|
|
|
new CustEntry("commonCpuBoostClock", "Boost Clock in kHz", CustPlatform.All, 4, [
|
|
"System default: 1785000",
|
|
"Boost clock will be applied when applications request Boost Mode via performance configuration."
|
|
], 1785000, [204000, 2907000], 1, !1),
|
|
|
|
new CustEntry("commonEmcMemVolt", "EMC Vdd2 Voltage in uV", CustPlatform.All, 4, [
|
|
"Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.",
|
|
"Erista Default: 1175000",
|
|
"Mariko Default: 1175000",
|
|
"Official LPDDR4(X) voltage: 1175mV (1175mV nominal)"
|
|
], 1175000, [11e5, 125e4], 12500),
|
|
|
|
new CustEntry("eristaCpuMaxVolt", "Erista CPU Max Voltage in mV", CustPlatform.Erista, 4, [
|
|
"Acceptable range: 1120 ≤ x ≤ 1300",
|
|
"Default: 1235"
|
|
], 1235, [1000, 1500], 1),
|
|
|
|
new CustEntry("eristaEmcMaxClock", "Erista RAM Max Clock in kHz", CustPlatform.Erista, 4, [
|
|
"Values should be ≥ 1600000, and divided evenly by 3200.",
|
|
"Recommended Clocks: 1862400, 2131200 (JEDEC)",
|
|
"<b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM"
|
|
], 1862400, [16e5, 2428800], 3200),
|
|
|
|
new CustEntry("marikoCpuMaxVolt", "Mariko CPU Max Voltage in mV", CustPlatform.Mariko, 4, [
|
|
"System default: 1120",
|
|
"Acceptable range: 1120 ≤ x ≤ 1300",
|
|
"Changing this value affects cpu voltage calculation"
|
|
], 1235, [1120, 1300], 5),
|
|
|
|
new CustEntry("marikoEmcMaxClock", "Mariko RAM Max Clock in kHz", CustPlatform.Mariko, 4, [
|
|
"Values should be ≥ 1600000, and divided evenly by 9600.",
|
|
"Recommended Clocks: 1862400, 2131200, 2400000, etc. (JEDEC)",
|
|
"<b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."
|
|
], 1996800, [16e5, 3200000], 3200),
|
|
|
|
new CustEntry("marikoEmcVddqVolt", "EMC Vddq (Mariko Only) Voltage in uV", CustPlatform.Mariko, 4, [
|
|
"Acceptable range: 550000 ≤ x ≤ 650000",
|
|
"Value should be divided evenly by 5000",
|
|
"Default: 600000",
|
|
"Official lpddr4(x) range: 570mV~650mV (600mV nominal)",
|
|
"Not enabled by default."
|
|
], 600000, [55e4, 65e4], 5e3),
|
|
|
|
new CustEntry("marikoCpuUV", "Enable Mariko CPU Undervolt", CustPlatform.Mariko, 4, [
|
|
"Reduce CPU power draw",
|
|
"<b>0</b> : Default Table",
|
|
"<b>1</b> : Undervolt Level 1 (SLT - CPU speedo < 1650)",
|
|
"<b>2</b> : Undervolt Level 1 (SLT - CPU speedo >= 1650)"
|
|
], 0, [0, 2], 1),
|
|
|
|
new CustEntry("marikoGpuUV", "Enable Mariko GPU Undervolt", CustPlatform.Mariko, 4, [
|
|
"Reduce GPU power draw",
|
|
"Your GPU might not withstand undervolt, and can hang your console, or crash games",
|
|
"Undervolting too much will drop GPU performance even if it seems stable",
|
|
"GPU voltages are dynamic and will change with temperature and gpu speedo",
|
|
"<b>0</b> : Default Table",
|
|
"<b>1</b> : Undervolt Level 1 (SLT: Aggressive)",
|
|
"<b>2</b> : Undervolt Level 2 (HiOPT: Drastic)",
|
|
"<b>3</b> : Custom static GPU Voltage Table (Use Gpu Configuation below)"
|
|
], 0, [0, 3], 1),
|
|
|
|
new CustEntry("commonGpuVoltOffset", "GPU Volt Offset", CustPlatform.All, 4, [
|
|
"Negative Voltage offset value for gpu dynamic voltage calculation",
|
|
"For example, value of 10 will decrease 10mV gpu volt from all frequencies",
|
|
"Default gpu vmin: Erista - 812.5mV / Mariko - 610mV",
|
|
"Acceptable range: 0 ~ 100"
|
|
], 0, [0, 100], 1),
|
|
|
|
new CustEntry("marikoCpuHighVoltOffset", "CPU Voltage offset at high frequencies", CustPlatform.Mariko, 4, [
|
|
"Reduce CPU power draw at high clocks",
|
|
], 0, [0, 100], 1),
|
|
|
|
new CustEntry("marikoCpuHighUV", "Enable Mariko CPU High Undervolt", CustPlatform.Mariko, 4, [
|
|
"Reduce CPU power draw at high clocks by offsetting the voltage sent to the CPU",
|
|
], 0, [0, 12], 1),
|
|
|
|
new CustEntry("cpuMaxFreq", "Maximum allowed CPU Frequency (KHz)", CustPlatform.All, 4, [
|
|
"Default: 1785000",
|
|
"This is the maximum frequency for the CPU you can set in sys-clk-ocs2.",
|
|
"The value for this setting is capped at 2091mhz for Erista units and 2907MHz for Mariko units",
|
|
"Anything above 1785MHz for Erista units and 1963MHz for Mariko units is unsafe without undervolting"
|
|
], 1785000, [204000, 2907000], 1, !1),
|
|
|
|
new CustEntry("gpuMaxFreq", "Maximum allowed GPU Frequency (KHz)", CustPlatform.All, 4, [
|
|
"Default: 921600",
|
|
"This is the maximum frequency for the GPU you can set in sys-clk-ocs2.",
|
|
"The value for this setting is capped at 998mhz for Erista units, and 1305MHz on Mariko units",
|
|
"The maximum safe value without undervolt is 921MHz for Erista units and 1152MHz for Mariko units",
|
|
"Higher frequencies via GPU UV3 bypass this setting"
|
|
], 921600, [76800, 1305600], 1, !1),
|
|
|
|
new CustEntry("gpuVmax", "Mariko Maximum allowed GPU Voltage (mV)", CustPlatform.Mariko, 4, [
|
|
"Default: 800",
|
|
"This is the maximum voltage you can use in GPU UV3.",
|
|
"Anything above 800MV is considered UNSAFE (although it depends per frequency)"
|
|
], 800, [480, 1000], 1, !1),
|
|
|
|
new CustEntry("gpuVmin", "Mariko Minimum allowed GPU Voltage (mV)", CustPlatform.Mariko, 4, [
|
|
"Default: 600",
|
|
"This is the minimum voltage you can use in GPU UV3.",
|
|
"A higher Vmin is required for a higher max ram clock"
|
|
], 600, [480, 1000], 1, !1),
|
|
|
|
|
|
];
|
|
|
|
var AdvTable = [
|
|
new AdvEntry("marikoEmcDvbShift", "Step up Mariko EMC DVB Table", CustPlatform.Mariko, 4, [
|
|
"Each number adds 25mV to SoC voltage",
|
|
"Helps with stability at higher memory clock, with the only downside being slightly higher tempratures",
|
|
"Such functionality is completely useless on Erista units",
|
|
"Acceptable range : 0~9"
|
|
], 0, [0, 9], 1),
|
|
|
|
|
|
];
|
|
|
|
var GpuTable = [
|
|
new GpuEntry("0", "76.8"),
|
|
new GpuEntry("1", "153.6"),
|
|
new GpuEntry("2", "230.4"),
|
|
new GpuEntry("3", "307.2"),
|
|
new GpuEntry("4", "384.0"),
|
|
new GpuEntry("5", "460.8"),
|
|
new GpuEntry("6", "537.6"),
|
|
new GpuEntry("7", "614.4"),
|
|
new GpuEntry("8", "691.2"),
|
|
new GpuEntry("9", "768.0"),
|
|
new GpuEntry("10", "844.8"),
|
|
new GpuEntry("11", "921.6"),
|
|
new GpuEntry("12", "998.4"),
|
|
new GpuEntry("13", "1075.2", CustPlatform.Mariko),
|
|
new GpuEntry("14", "1152.0", CustPlatform.Mariko),
|
|
new GpuEntry("15", "1228.8 <span style='color:orange; font-weight:bold;'>(UNSAFE)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("16", "1267.2 <span style='color:orange; font-weight:bold;'>(UNSAFE)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("17", "1305.6 <span style='color:orange; font-weight:bold;'>(UNSAFE)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("18", "1344.0 <span style='color:orange; font-weight:bold;'>(UNSAFE)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("19", "1382.4 <span style='color:orange; font-weight:bold;'>(UNSAFE)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("20", "1420.8 <span style='color:red; font-weight:bold;'>(DANGEROUS)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("21", "1459.2 <span style='color:red; font-weight:bold;'>(DANGEROUS)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("22", "1497.6 <span style='color:red; font-weight:bold;'>(DANGEROUS)</span>", CustPlatform.Mariko),
|
|
new GpuEntry("23", "1536.0 <span style='color:red; font-weight:bold;'>(DANGEROUS)</span>", CustPlatform.Mariko)
|
|
];
|
|
|
|
class ErrorToolTip {
|
|
constructor(e, t) {
|
|
this.id = e, this.msg = t, this.id = e, this.element = document.getElementById(e), t && this.setMsg(t)
|
|
}
|
|
setMsg(e) {
|
|
return this.msg = e, this
|
|
}
|
|
show() {
|
|
var e, t, i, n, a, r;
|
|
return null === (e = this.element) || void 0 === e || e.setAttribute("aria-invalid", "true"), this.msg && (null === (t = this.element) || void 0 === t || t.setAttribute("title", this.msg), null === (n = null === (i = this.element) || void 0 === i ? void 0 : i.parentElement) || void 0 === n || n.setAttribute("data-tooltip", this.msg), null === (r = null === (a = this.element) || void 0 === a ? void 0 : a.parentElement) || void 0 === r || r.setAttribute("data-placement", "top")), this
|
|
}
|
|
clear() {
|
|
var e, t, i, n, a, r;
|
|
return null === (e = this.element) || void 0 === e || e.removeAttribute("aria-invalid"), null === (t = this.element) || void 0 === t || t.removeAttribute("title"), null === (n = null === (i = this.element) || void 0 === i ? void 0 : i.parentElement) || void 0 === n || n.removeAttribute("data-tooltip"), null === (r = null === (a = this.element) || void 0 === a ? void 0 : a.parentElement) || void 0 === r || r.removeAttribute("data-placement"), this
|
|
}
|
|
addChangeListener() {
|
|
var e;
|
|
null === (e = this.element) || void 0 === e || e.addEventListener("change", (e => {
|
|
let t = CustTable.filter((e => e.id === this.id))[0];
|
|
t.value = Number(this.element.value), t.validate()
|
|
}))
|
|
}
|
|
}
|
|
class CustStorage {
|
|
constructor() {
|
|
this.storage = {}, this.key = "last_saved"
|
|
}
|
|
updateFromTable() {
|
|
let e = e => {
|
|
var t;
|
|
if (e.updateValueFromElement(), !e.validate()) throw null === (t = e.getInputElement()) || void 0 === t || t.focus(), new Error(`Invalid ${e.name}`)
|
|
};
|
|
CustTable.forEach(e), AdvTable.forEach(e), GpuTable.forEach(e), this.storage = {};
|
|
let t = Object.fromEntries(CustTable.map((e => [e.id, e.value])));
|
|
Object.keys(t).forEach((e => this.storage[e] = t[e])), t = Object.fromEntries(AdvTable.map((e => [e.id, e.value]))), Object.keys(t).forEach((e => this.storage[e] = t[e]))
|
|
}
|
|
setTable() {
|
|
let e = Object.keys(this.storage);
|
|
e.forEach((e => CustTable.filter((t => t.id == e))[0].value = this.storage[e])), e.forEach((e => AdvTable.filter((t => t.id == e))[0].value = this.storage[e])), CustTable.filter((t => !e.includes(t.id))).forEach((e => e.value = e.defval)), AdvTable.filter((t => !e.includes(t.id))).forEach((e => e.value = e.defval)), CustTable.forEach((e => {
|
|
var t;
|
|
if (!e.validate()) throw null === (t = e.getInputElement()) || void 0 === t || t.focus(), new Error(`Invalid ${e.name}`);
|
|
e.setElementValue()
|
|
})), AdvTable.forEach((e => {
|
|
var t;
|
|
if (!e.validate()) throw null === (t = e.getInputElement()) || void 0 === t || t.focus(), new Error(`Invalid ${e.name}`);
|
|
e.setElementValue()
|
|
})), GpuTable.forEach((e => {
|
|
var t;
|
|
if (!e.validate()) throw null === (t = e.getInputElement()) || void 0 === t || t.focus(), new Error(`Invalid ${e.name}`);
|
|
e.setElementValue()
|
|
}))
|
|
}
|
|
save() {
|
|
localStorage.setItem(this.key, JSON.stringify(this.storage))
|
|
}
|
|
load() {
|
|
let e = localStorage.getItem(this.key);
|
|
if (!e) return null;
|
|
let t = JSON.parse(e),
|
|
i = CustTable.map((e => e.id)),
|
|
n = Object.keys(t).filter((e => !i.includes(e)));
|
|
return n.length && console.log(`Ignored: ${n}`), Object.keys(t).filter((e => i.includes(e))).forEach((e => this.storage[e] = t[e])), i = AdvTable.map((e => e.id)), n = Object.keys(t).filter((e => !i.includes(e))), n.length && console.log(`Ignored: ${n}`), Object.keys(t).filter((e => i.includes(e))).forEach((e => this.storage[e] = t[e])), this.storage
|
|
}
|
|
}
|
|
class Cust {
|
|
constructor() {
|
|
this.storage = new CustStorage, this.magic = 1414747459, this.magicLen = 4, this.mapper = {
|
|
2: {
|
|
get: e => this.view.getUint16(e, !0),
|
|
set: (e, t) => this.view.setUint16(e, t, !0)
|
|
},
|
|
4: {
|
|
get: e => this.view.getUint32(e, !0),
|
|
set: (e, t) => this.view.setUint32(e, t, !0)
|
|
}
|
|
}
|
|
}
|
|
findMagicOffset() {
|
|
this.view = new DataView(this.buffer);
|
|
for (let e = 0; e < this.view.byteLength; e += this.magicLen)
|
|
if (this.mapper[this.magicLen].get(e) == this.magic) return void(this.beginOffset = e);
|
|
throw new Error("Invalid loader.kip file")
|
|
}
|
|
save() {
|
|
this.storage.updateFromTable();
|
|
let e = e => {
|
|
var t, i;
|
|
if (!e.offset) throw null === (t = e.getInputElement()) || void 0 === t || t.focus(), new Error(`Failed to get offset for ${e.name}`);
|
|
let n = this.mapper[e.size];
|
|
if (!n) throw null === (i = e.getInputElement()) || void 0 === i || i.focus(), new Error(`Unknown size at ${e.name}`);
|
|
n.set(e.offset, e.value)
|
|
};
|
|
CustTable.forEach(e), AdvTable.forEach(e), GpuTable.forEach(e), this.storage.save();
|
|
let t = document.createElement("a");
|
|
t.href = window.URL.createObjectURL(new Blob([this.buffer], {
|
|
type: "application/octet-stream"
|
|
})), t.download = "loader.kip", t.click(), this.toggleLoadLastSavedBtn(!0)
|
|
}
|
|
removeHTMLForm() {
|
|
CustTable.forEach((e => e.removeElement()))
|
|
}
|
|
toggleLoadLastSavedBtn(e) {
|
|
let t = document.getElementById("load_saved");
|
|
e ? (t.addEventListener("click", (() => {
|
|
this.storage.load() && this.storage.setTable()
|
|
})), t.style.removeProperty("display"), t.removeAttribute("disabled")) : t.style.setProperty("display", "none")
|
|
}
|
|
createHTMLForm() {
|
|
var e, t;
|
|
CustTable.forEach((e => e.createElement()));
|
|
let i = document.createElement("p");
|
|
i.innerHTML = "Advanced configuration", null === (e = document.getElementById("config-list-advanced")) || void 0 === e || e.appendChild(i);
|
|
let n = document.createElement("p");
|
|
n.innerHTML = "Gpu Volt configuration", null === (t = document.getElementById("config-list-gpu")) || void 0 === t || t.appendChild(n), AdvTable.forEach((e => e.createElement())), GpuTable.forEach((e => e.createElement()));
|
|
let a = document.getElementById("load_default");
|
|
a.removeAttribute("disabled"), a.addEventListener("click", (() => {
|
|
CustTable.forEach((e => e.setElementDefaultValue()))
|
|
})), this.toggleLoadLastSavedBtn(null !== this.storage.load());
|
|
let r = document.getElementById("save");
|
|
r.removeAttribute("disabled"), r.addEventListener("click", (() => {
|
|
try {
|
|
this.save()
|
|
} catch (e) {
|
|
console.error(e), alert(e)
|
|
}
|
|
}))
|
|
}
|
|
initCustTabs() {
|
|
const e = Array.from(document.querySelectorAll('nav[role="tablist"] > button'));
|
|
e.forEach((t => {
|
|
t.removeAttribute("disabled");
|
|
let i = Number(t.getAttribute("data-platform"));
|
|
t.addEventListener("click", (n => {
|
|
const a = ["outline"];
|
|
t.classList.remove(...a), e.filter((e => e != t)).forEach((e => e.classList.add(...a))), CustTable.forEach((e => {
|
|
e.isAvailableFor(i) ? e.showElement() : e.hideElement()
|
|
}))
|
|
}))
|
|
}))
|
|
}
|
|
parse() {
|
|
let e = this.beginOffset + this.magicLen;
|
|
if (this.rev = this.mapper[4].get(e), CUST_REV_ADV != this.rev) throw new Error(`Unsupported custRev, expected: 1, got ${this.rev}`);
|
|
e += 4, document.getElementById("cust_rev").innerHTML = `Cust v${this.rev} is loaded.`;
|
|
let t = t => {
|
|
var i;
|
|
t.offset = e;
|
|
let n = this.mapper[t.size];
|
|
if (!n) throw null === (i = t.getInputElement()) || void 0 === i || i.focus(), new Error(`Unknown size at ${t}`);
|
|
t.value = n.get(e), e += t.size, t.validate()
|
|
};
|
|
CustTable.forEach(t), AdvTable.forEach(t), GpuTable.forEach(t)
|
|
}
|
|
load(e) {
|
|
try {
|
|
this.buffer = e, this.findMagicOffset(), this.removeHTMLForm(), this.parse(), this.initCustTabs(), this.createHTMLForm()
|
|
} catch (e) {
|
|
console.error(e), alert(e)
|
|
}
|
|
}
|
|
}
|
|
class ReleaseAsset {
|
|
constructor(e) {
|
|
this.downloadUrl = e.browser_download_url, this.updatedAt = e.updated_at
|
|
}
|
|
}
|
|
class ReleaseInfo {
|
|
constructor() {
|
|
this.ocLatestApi = "https://api.github.com/repos/souldbminersmwc/Switch-OC-Suite-2/releases/latest"
|
|
}
|
|
load() {
|
|
return __awaiter(this, void 0, void 0, (function*() {
|
|
try {
|
|
this.parseOcResponse(yield this.responseFromApi(this.ocLatestApi).catch())
|
|
} catch (e) {
|
|
console.error(e), alert(e)
|
|
}
|
|
}))
|
|
}
|
|
responseFromApi(e) {
|
|
return __awaiter(this, void 0, void 0, (function*() {
|
|
const t = yield fetch(e, {
|
|
method: "GET",
|
|
headers: {
|
|
Accept: "application/json"
|
|
}
|
|
});
|
|
if (t.ok) return yield t.json();
|
|
throw new Error(`Failed to connect to "${e}": ${t.status}`)
|
|
}))
|
|
}
|
|
parseOcResponse(e) {
|
|
this.ocVer = e.tag_name, this.loaderKipAsset = new ReleaseAsset(e.assets.filter((e => e.name.endsWith("loader.kip")))[0]), this.sdOutZipAsset = new ReleaseAsset(e.assets.filter((e => e.name.endsWith("SdOut.zip")))[0]), this.sysclkOCAsset = new ReleaseAsset(e.assets.filter((e => e.name.endsWith("sys-clk-ocs2.zip")))[0])
|
|
}
|
|
}
|
|
class DownloadSection {
|
|
constructor() {
|
|
this.element = document.getElementById("download_btn_grid")
|
|
}
|
|
load() {
|
|
return __awaiter(this, void 0, void 0, (function*() {
|
|
for (; !this.isVisible();) yield new Promise((e => setTimeout(e, 1e3)));
|
|
const e = new ReleaseInfo;
|
|
yield e.load(), this.update("loader_kip_btn", `loader.kip <b>${e.ocVer}</b><br>${e.loaderKipAsset.updatedAt}`, e.loaderKipAsset.downloadUrl), this.update("sdout_zip_btn", `SdOut.zip <b>${e.ocVer}</b><br>${e.sdOutZipAsset.updatedAt}`, e.sdOutZipAsset.downloadUrl), this.update("ams_btn", `sys-clk-ocs2 <b>${e.ocVer}</b><br>${e.sysclkOCAsset.updatedAt}`, e.sysclkOCAsset.downloadUrl)
|
|
}))
|
|
}
|
|
isVisible() {
|
|
let e = this.element.getBoundingClientRect();
|
|
return e.top > 0 && e.left > 0 && e.bottom - e.height < (window.innerHeight || document.documentElement.clientHeight) && e.right - e.width < (window.innerWidth || document.documentElement.clientWidth)
|
|
}
|
|
update(e, t, i) {
|
|
let n = document.getElementById(e);
|
|
n.innerHTML = t, n.removeAttribute("aria-busy"), n.setAttribute("href", i)
|
|
}
|
|
}
|
|
const fileInput = document.getElementById("file");
|
|
fileInput.addEventListener("change", (e => {
|
|
var t = new Cust;
|
|
if (!e.target || !e.target.files) return;
|
|
let i = new FileReader;
|
|
i.readAsArrayBuffer(e.target.files[0]), i.onloadend = e => {
|
|
e.target.readyState == FileReader.DONE && t.load(e.target.result)
|
|
}
|
|
})), addEventListener("DOMContentLoaded", (e => __awaiter(this, void 0, void 0, (function*() {
|
|
yield(new DownloadSection).load()
|
|
})))); |