1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { SpSystemTrace } from '../SpSystemTrace'; 17import { TraceRow } from '../trace/base/TraceRow'; 18import { renders } from '../../database/ui-worker/ProcedureWorker'; 19import { info } from '../../../log/Log'; 20import { XpowerRender, XpowerStruct } from '../../database/ui-worker/ProcedureWorkerXpower'; 21import { ColorUtils } from '../trace/base/ColorUtils'; 22import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 23import { xpowerDataSender } from '../../database/data-trafic/XpowerDataSender'; 24import { queryXpowerData, queryXpowerMeasureData } from '../../database/sql/Xpower.sql'; 25import { BaseStruct } from '../../bean/BaseStruct'; 26 27export class SpXpowerChart { 28 private readonly trace: SpSystemTrace; 29 private rowFolder!: TraceRow<BaseStruct>; 30 private systemFolder!: TraceRow<BaseStruct>; 31 32 constructor(trace: SpSystemTrace) { 33 this.trace = trace; 34 } 35 36 async init(traceId?: string): Promise<void> { 37 let XpowerMeasureData = await queryXpowerMeasureData(traceId); 38 if (XpowerMeasureData.length <= 0) { 39 return; 40 } 41 let xpowerList = await queryXpowerData(traceId); 42 if (xpowerList.length <= 0) { 43 return; 44 } 45 await this.initXpowerFolder(traceId); 46 await this.initSystemFolder(traceId); 47 await this.initSystemData(this.systemFolder, xpowerList, traceId); 48 } 49 50 initXpowerFolder = async (traceId?: string): Promise<void> => { 51 let xpowerFolder = TraceRow.skeleton(traceId); 52 xpowerFolder.rowId = 'Xpowers'; 53 xpowerFolder.index = 0; 54 xpowerFolder.rowType = TraceRow.ROW_TYPE_XPOWER; 55 xpowerFolder.rowParentId = ''; 56 xpowerFolder.style.height = '40px'; 57 xpowerFolder.folder = true; 58 xpowerFolder.name = 'Xpower'; 59 xpowerFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler; 60 xpowerFolder.selectChangeHandler = this.trace.selectChangeHandler; 61 xpowerFolder.supplier = (): Promise<BaseStruct[]> => new Promise<Array<BaseStruct>>((resolve) => resolve([])); 62 xpowerFolder.onThreadHandler = (useCache): void => { 63 xpowerFolder.canvasSave(this.trace.canvasPanelCtx!); 64 if (xpowerFolder.expansion) { 65 this.trace.canvasPanelCtx?.clearRect(0, 0, xpowerFolder.frame.width, xpowerFolder.frame.height); 66 } else { 67 (renders.empty as EmptyRender).renderMainThread( 68 { 69 context: this.trace.canvasPanelCtx, 70 useCache: useCache, 71 type: '', 72 }, 73 xpowerFolder 74 ); 75 } 76 xpowerFolder.canvasRestore(this.trace.canvasPanelCtx!, this.trace); 77 }; 78 this.rowFolder = xpowerFolder; 79 this.trace.rowsEL?.appendChild(xpowerFolder); 80 } 81 82 initSystemFolder = async (traceId?: string): Promise<void> => { 83 let systemFolder = TraceRow.skeleton(traceId); 84 systemFolder.rowId = 'system'; 85 systemFolder.rowParentId = 'Xpowers'; 86 systemFolder.rowHidden = !this.rowFolder.expansion; 87 systemFolder.rowType = TraceRow.ROW_TYPE_XPOWER_SYSTEM; 88 systemFolder.folder = true; 89 systemFolder.name = 'System'; 90 systemFolder.folderPaddingLeft = 20; 91 systemFolder.style.height = '40px'; 92 systemFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler; 93 systemFolder.selectChangeHandler = this.trace.selectChangeHandler; 94 systemFolder.supplier = (): Promise<BaseStruct[]> => new Promise<Array<BaseStruct>>((resolve) => resolve([])); 95 systemFolder.onThreadHandler = (useCache): void => { 96 systemFolder.canvasSave(this.trace.canvasPanelCtx!); 97 if (systemFolder.expansion) { 98 this.trace.canvasPanelCtx?.clearRect(0, 0, systemFolder.frame.width, systemFolder.frame.height); 99 } else { 100 (renders.empty as EmptyRender).renderMainThread( 101 { 102 context: this.trace.canvasPanelCtx, 103 useCache: useCache, 104 type: '', 105 }, 106 systemFolder 107 ); 108 } 109 systemFolder.canvasRestore(this.trace.canvasPanelCtx!, this.trace); 110 }; 111 this.systemFolder = systemFolder; 112 this.rowFolder?.addChildTraceRow(systemFolder); 113 } 114 115 private xpowerSupplierFrame( 116 traceRow: TraceRow<XpowerStruct>, 117 it: { 118 name: string; 119 num: number; 120 maxValue?: number; 121 }, 122 ): void { 123 traceRow.supplierFrame = (): Promise<XpowerStruct[]> => { 124 let promiseData = null; 125 // @ts-ignore 126 promiseData = xpowerDataSender(it.name, traceRow); 127 if (promiseData === null) { 128 // @ts-ignore 129 return new Promise<Array<unknown>>((resolve) => resolve([])); 130 } else { 131 // @ts-ignore 132 return promiseData.then((resultXpower: Array<unknown>) => { 133 for (let j = 0; j < resultXpower.length; j++) { 134 // @ts-ignore 135 if ((resultXpower[j].value || 0) > it.maxValue!) { 136 // @ts-ignore 137 it.maxValue = resultXpower[j].value || 0; 138 } 139 if (j > 0) { 140 // @ts-ignore 141 resultXpower[j].delta = (resultXpower[j].value || 0) - (resultXpower[j - 1].value || 0); 142 } else { 143 // @ts-ignore 144 resultXpower[j].delta = 0; 145 } 146 } 147 return resultXpower; 148 }); 149 } 150 }; 151 } 152 153 private xpowerThreadHandler( 154 traceRow: TraceRow<XpowerStruct>, 155 it: { 156 name: string; 157 num: number; 158 maxValue?: number; 159 }, 160 xpowerId: number 161 ): void { 162 traceRow.onThreadHandler = (useCache): void => { 163 let context: CanvasRenderingContext2D; 164 if (traceRow.currentContext) { 165 context = traceRow.currentContext; 166 } else { 167 context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 168 } 169 traceRow.canvasSave(context); 170 (renders.xpower as XpowerRender).renderMainThread( 171 { 172 context: context, 173 useCache: useCache, 174 type: it.name, 175 maxValue: it.maxValue === 0 ? 1 : it.maxValue!, 176 index: xpowerId, 177 maxName: it.maxValue!.toString() 178 }, 179 traceRow 180 ); 181 traceRow.canvasRestore(context, this.trace); 182 }; 183 } 184 185 async initSystemData(folder: TraceRow<BaseStruct>, xpowerList: Array<{ 186 name: string; 187 num: number; 188 maxValue?: number; 189 }>, traceId?: string): Promise<void> { 190 info('xpowerList data size is: ', xpowerList!.length); 191 XpowerStruct.maxValue = xpowerList.map((item) => item.num).reduce((a, b) => Math.max(a, b)); 192 for (let i = 0; i < xpowerList.length; i++) { 193 const it = xpowerList[i]; 194 it.maxValue = 0; 195 let traceRow = TraceRow.skeleton<XpowerStruct>(traceId); 196 traceRow.rowId = it.name; 197 traceRow.rowType = TraceRow.ROW_TYPE_XPOWER_SYSTEM; 198 traceRow.rowParentId = folder.rowId; 199 traceRow.style.height = '40px'; 200 traceRow.name = it.name; 201 traceRow.rowHidden = !folder.expansion; 202 traceRow.folderTextLeft = 40; 203 traceRow.xpowerRowTitle = this.convertTitle(it.name); 204 traceRow.setAttribute('children', ''); 205 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 206 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 207 this.xpowerSupplierFrame(traceRow, it); 208 traceRow.getCacheData = (args: unknown): Promise<XpowerStruct[]> | undefined => { 209 let result: Promise<XpowerStruct[]> | undefined; 210 result = xpowerDataSender(it.name, traceRow, args); 211 return result; 212 }; 213 traceRow.focusHandler = (ev): void => { 214 this.trace?.displayTip( 215 traceRow, 216 XpowerStruct.hoverXpowerStruct, 217 `<span>${it.name === 'ThermalReport.ShellTemp' ? XpowerStruct.hoverXpowerStruct?.value! : 218 ColorUtils.formatNumberComma(XpowerStruct.hoverXpowerStruct?.value!)}</span>` 219 ); 220 }; 221 traceRow.findHoverStruct = (): void => { 222 XpowerStruct.hoverXpowerStruct = traceRow.getHoverStruct(); 223 }; 224 this.xpowerThreadHandler(traceRow, it, i); 225 folder.addChildTraceRow(traceRow); 226 } 227 } 228 229 convertTitle(title: string): string { 230 switch (title) { 231 case 'Battery.Capacity': 232 return '电池容量(单位mAh)'; 233 case 'Battery.Charge': 234 return '充电状态(充电1,非充电0)'; 235 case 'Battery.GasGauge': 236 return '电池剩余电量(单位mAh)'; 237 case 'Battery.Level': 238 return '电池百分比'; 239 case 'Battery.RealCurrent': 240 return '实时电流(单位mAh,充电时为正数,耗电时为负数)'; 241 case 'Battery.Screen': 242 return '屏幕状态(亮屏1,灭屏0)'; 243 case 'ThermalReport.ShellTemp': 244 return '外壳温度(单位℃)'; 245 case 'ThermalReport.ThermalLevel': 246 return '温度等级'; 247 default: 248 return title; 249 } 250 } 251 252} 253