Files
Horizon-OC/pages/dist/main.js

2 lines
10 KiB
JavaScript

var __awaiter=this&&this.__awaiter||function(e,t,i,a){return new(i||(i=Promise))((function(l,r){function n(e){try{o(a.next(e))}catch(e){r(e)}}function s(e){try{o(a.throw(e))}catch(e){r(e)}}function o(e){var t;e.done?l(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(n,s)}o((a=a.apply(e,t||[])).next())}))};const CUST_REV=3;var buffer,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,a,l,r,n=[0,1e6],s=1,o=!0){this.id=e,this.name=t,this.platform=i,this.size=a,this.desc=l,this.defval=r,this.min=n[0],this.max=n[1],this.step=s,this.zeroable=o}validate(){let e=new ErrorToolTip(this.id);return e.clear(),Number.isNaN(this.value)||!this.value?(e.setMsg("Invalid value: Not a number"),e.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}.`),e.show(),!1):this.value%this.step==0||(e.setMsg(`${this.value} % ${this.step} ≠ 0`),e.show(),!1))}getInputElement(){return document.getElementById(this.id)}updateValueFromElement(){this.value=Number(this.getInputElement().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 a=document.createElement("blockquote");a.innerHTML=this.desc,a.setAttribute("for",this.id),t.appendChild(a),document.getElementById("form").appendChild(t),new ErrorToolTip(this.id).addChangeListener()}e.value=String(this.value)}setElementDefaultValue(){document.getElementById(this.id).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")}}var CustTable=[new CustEntry("mtcConf","DRAM Timing",CustPlatform.Mariko,2,"<li><b>0</b>: AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)</li> <li><b>1</b>: AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.</li> <li><b>2</b>: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected.",0,[0,2],1),new CustEntry("marikoCpuMaxClock","Mariko CPU Max Clock in kHz",CustPlatform.Mariko,4,"<li>System default: 1785000</li> <li>2397000 might be unreachable for some SoCs.</li>",2397e3,[1785e3,3e6],1),new CustEntry("marikoCpuBoostClock","Mariko CPU Boost Clock in kHz",CustPlatform.Mariko,4,"<li>System default: 1785000</li> <li>Boost clock will be applied when applications request higher CPU frequency for quicker loading.</li> <li>This will be set regardless of whether sys-clk is enabled.</li>",1785e3,[102e4,3e6],1,!1),new CustEntry("marikoCpuMaxVolt","Mariko CPU Max Voltage in mV",CustPlatform.Mariko,4,"<li>System default: 1120</li> <li>Acceptable range: 1100 ≤ x ≤ 1300</li>",1235,[1100,1300],5),new CustEntry("marikoGpuMaxClock","Mariko GPU Max Clock in kHz",CustPlatform.Mariko,4,"<li>System default: 921600</li> <li>Tegra X1+ official maximum: 1267200</li> <li>1305600 might be unreachable for some SoCs.</li>",1305600,[768e3,1536e3],100),new CustEntry("marikoEmcMaxClock","Mariko RAM Max Clock in kHz",CustPlatform.Mariko,4,"<li>Values should be ≥ 1600000, and divided evenly by 3200.</li> <li><b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM</li>",1996800,[16e5,24e5],3200),new CustEntry("marikoEmcVddqVolt","EMC Vddq (Mariko Only) Voltage in uV",CustPlatform.Mariko,4,"<li>Acceptable range: 550000 ≤ x ≤ 650000</li> <li>Value should be divided evenly by 5000</li> <li>Default: 600000</li> <li>Not enabled by default.</li> <li>This will not work without sys-clk-OC.</li>",0,[55e4,65e4],5e3),new CustEntry("eristaCpuMaxVolt","Erista CPU Max Voltage in mV",CustPlatform.Erista,4,"<li>Acceptable range: 1100 ≤ x ≤ 1300</li>",1235,[1100,1300],1),new CustEntry("eristaEmcMaxClock","Erista RAM Max Clock in kHz",CustPlatform.Erista,4,"<li>Values should be ≥ 1600000, and divided evenly by 3200.</li> <li><b>WARNING:</b> RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM</li>",1862400,[16e5,24e5],3200),new CustEntry("commonEmcMemVolt","EMC Vddq (Erista Only) & RAM Vdd2 Voltage in uV",CustPlatform.All,4,"<li>Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.</li> <li>Erista Default (HOS): 1125000 (bootloader: 1100000)</li> <li>Mariko Default: 1100000 (It will not work without sys-clk-OC)</li> <li>Not enabled by default</li>",0,[11e5,125e4],12500)];function FindMagicOffset(e){let t=new DataView(e);for(let e=0;e<t.byteLength;e+=4)if(1414747459==t.getUint32(e,!0))return e;throw new Error("Invalid loader.kip file")}class ErrorToolTip{constructor(e,t){this.id=e,this.element=document.getElementById(e),t&&this.setMsg(t)}setMsg(e){this.message=e}show(){this.element&&(this.element.setAttribute("aria-invalid","true"),this.message&&(this.element.setAttribute("title",this.message),this.element.parentElement.setAttribute("data-tooltip",this.message),this.element.parentElement.setAttribute("data-placement","top")))}clear(){this.element&&(this.element.removeAttribute("aria-invalid"),this.element.removeAttribute("title"),this.element.parentElement.removeAttribute("data-tooltip"),this.element.parentElement.removeAttribute("data-placement"))}addChangeListener(){this.element&&this.element.addEventListener("change",(e=>{let t=CustTable.filter((e=>e.id===this.id))[0];t.value=Number(this.element.value),t.validate()}))}}function SaveCust(e){let t=new DataView(e),i={};CustTable.forEach((e=>{if(e.updateValueFromElement(),!e.validate()||!e.value)throw document.getElementById(e.id).focus(),new Error(`Invalid ${e.name}`);if(!e.offset)throw document.getElementById(e.id).focus(),new Error(`Failed to get offset for ${e.name}`);switch(e.size){case 2:t.setUint16(e.offset,e.value,!0);break;case 4:t.setUint32(e.offset,e.value,!0);break;default:throw document.getElementById(e.id).focus(),new Error(`Unknown size at ${e.name}`)}i[e.id]=e.value})),i.custRev=3,localStorage.setItem("last_saved",JSON.stringify(i));let a=document.createElement("a");a.href=window.URL.createObjectURL(new Blob([e],{type:"application/octet-stream"})),a.download="loader.kip",a.click()}function LastSaved(){let e=localStorage.getItem("last_saved");if(!e)return!1;let t=JSON.parse(e);return!(!t.custRev||3!=t.custRev)||(localStorage.removeItem("last_saved"),!1)}function CustNavTabsInit(){const e=Array.from(document.querySelectorAll('nav[role="tab-control"] > button'));e.forEach((t=>{t.removeAttribute("disabled");let i=Number(t.getAttribute("data-filter"));t.addEventListener("click",(a=>{const l=["outline","secondary"];t.classList.remove(...l),e.filter((e=>e!=t)).forEach((e=>e.classList.add(...l))),CustTable.forEach((e=>{e.isAvailableFor(i)?e.showElement():e.hideElement()}))}))}))}function UpdateHTMLForm(){CustTable.forEach((e=>e.createElement()));let e=document.getElementById("load_default");e.removeAttribute("disabled"),e.addEventListener("click",(()=>{CustTable.forEach((e=>e.setElementDefaultValue()))}));let t=document.getElementById("load_saved");LastSaved()?(t.style.removeProperty("display"),t.removeAttribute("disabled"),t.addEventListener("click",(()=>{JSON.parse(localStorage.getItem("last_saved")).filter((e=>"custRev"!=e)).forEach((e=>document.getElementById(e).value=e))}))):t.style.setProperty("display","none");let i=document.getElementById("save");i.removeAttribute("disabled"),i.addEventListener("click",(()=>{try{SaveCust(buffer)}catch(e){console.log(e),alert(e)}}))}function ParseCust(e,t){let i=new DataView(t),a=e+4,l=i.getUint16(a,!0);if(a+=2,3!=l)throw new Error(`Unsupported custRev, expected: 3, got ${l}`);document.getElementById("cust_rev").innerHTML="Cust V3 is loaded.",CustTable.forEach((e=>{switch(e.offset=a,e.size){case 2:e.value=i.getUint16(a,!0);break;case 4:e.value=i.getUint32(a,!0);break;default:throw document.getElementById(e.id).focus(),new Error("Unknown size at "+e)}a+=e.size,e.validate()}))}const fileInput=document.getElementById("file");function fetchRelease(){return __awaiter(this,void 0,void 0,(function*(){try{const e=yield fetch("https://api.github.com/repos/KazushiMe/Switch-OC-Suite/releases/latest",{method:"GET",headers:{Accept:"application/json"}});if(!e.ok)throw new Error(`Failed to fetch latest release info from GitHub: ${e.status}`);const t=yield e.json(),i=t.tag_name,a=i.split(".").slice(0,3).join("."),l=t.assets.filter((e=>e.name.endsWith("loader.kip")))[0],r=t.assets.filter((e=>e.name.endsWith(".zip")))[0],n=`https://github.com/Atmosphere-NX/Atmosphere/releases/tags/${a}`;return{OCSuiteVer:i,LoaderKipUrl:l.browser_download_url,LoaderKipTime:l.updated_at,SdOutZipUrl:r.browser_download_url,SdOutZipTime:r.updated_at,AMSVer:a,AMSUrl:n}}catch(e){console.log(e),alert(e)}}))}function updateDownloadUrls(){return __awaiter(this,void 0,void 0,(function*(){const e=(e,t,i)=>{let a=document.getElementById(e);a.innerHTML=t,a.removeAttribute("aria-busy"),a.setAttribute("href",i)};let t=yield fetchRelease();if(t){e("loader_kip_btn",`loader.kip <b>${t.OCSuiteVer}</b><br>${t.LoaderKipTime}`,t.LoaderKipUrl);e("sdout_zip_btn",`SdOut.zip <b>${t.OCSuiteVer}</b><br>${t.SdOutZipTime}`,t.SdOutZipUrl);e("ams_btn",`Atmosphere-NX <b>${t.AMSVer}</b>`,t.AMSUrl)}}))}fileInput.addEventListener("change",(e=>{let t=new FileReader;t.readAsArrayBuffer(e.target.files[0]),t.onloadend=e=>{if(e.target.readyState===FileReader.DONE){buffer=e.target.result;try{let e=FindMagicOffset(buffer);CustTable.forEach((e=>e.removeElement())),ParseCust(e,buffer),CustNavTabsInit(),UpdateHTMLForm()}catch(e){console.log(e),alert(e),fileInput.value=""}}}})),addEventListener("DOMContentLoaded",(e=>__awaiter(this,void 0,void 0,(function*(){yield updateDownloadUrls()}))));