1fb726d48Sopenharmony_ci/* 2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd. 3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License. 5fb726d48Sopenharmony_ci * You may obtain a copy of the License at 6fb726d48Sopenharmony_ci * 7fb726d48Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fb726d48Sopenharmony_ci * 9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and 13fb726d48Sopenharmony_ci * limitations under the License. 14fb726d48Sopenharmony_ci */ 15fb726d48Sopenharmony_ci 16fb726d48Sopenharmony_ciimport { SpSystemTrace } from '../SpSystemTrace'; 17fb726d48Sopenharmony_ciimport { info } from '../../../log/Log'; 18fb726d48Sopenharmony_ciimport { TraceRow } from '../trace/base/TraceRow'; 19fb726d48Sopenharmony_ciimport { BaseStruct } from '../../bean/BaseStruct'; 20fb726d48Sopenharmony_ciimport { EnergyAnomalyRender, EnergyAnomalyStruct } from '../../database/ui-worker/ProcedureWorkerEnergyAnomaly'; 21fb726d48Sopenharmony_ciimport { EnergySystemStruct, EnergySystemRender } from '../../database/ui-worker/ProcedureWorkerEnergySystem'; 22fb726d48Sopenharmony_ciimport { EnergyPowerStruct, EnergyPowerRender } from '../../database/ui-worker/ProcedureWorkerEnergyPower'; 23fb726d48Sopenharmony_ciimport { EnergyStateStruct, EnergyStateRender } from '../../database/ui-worker/ProcedureWorkerEnergyState'; 24fb726d48Sopenharmony_ciimport { renders } from '../../database/ui-worker/ProcedureWorker'; 25fb726d48Sopenharmony_ciimport { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 26fb726d48Sopenharmony_ciimport { TreeItemData } from '../../../base-ui/tree/LitTree'; 27fb726d48Sopenharmony_ciimport { 28fb726d48Sopenharmony_ci energySysEventSender, 29fb726d48Sopenharmony_ci hiSysEnergyAnomalyDataSender, 30fb726d48Sopenharmony_ci hiSysEnergyPowerSender, 31fb726d48Sopenharmony_ci hiSysEnergyStateSender, 32fb726d48Sopenharmony_ci} from '../../database/data-trafic/EnergySysEventSender'; 33fb726d48Sopenharmony_ciimport { 34fb726d48Sopenharmony_ci queryAnomalyData, 35fb726d48Sopenharmony_ci queryConfigEnergyAppName, 36fb726d48Sopenharmony_ci queryEnergyAppName, 37fb726d48Sopenharmony_ci queryEnergyEventExits, 38fb726d48Sopenharmony_ci queryMaxStateValue, 39fb726d48Sopenharmony_ci queryStateInitValue, 40fb726d48Sopenharmony_ci} from '../../database/sql/SqlLite.sql'; 41fb726d48Sopenharmony_ciimport { queryPowerData } from '../../database/sql/ProcessThread.sql'; 42fb726d48Sopenharmony_ciimport { NUM_200, NUM_3 } from '../../bean/NumBean'; 43fb726d48Sopenharmony_ci 44fb726d48Sopenharmony_ciexport class SpHiSysEnergyChart { 45fb726d48Sopenharmony_ci static app_name: string | null; 46fb726d48Sopenharmony_ci trace: SpSystemTrace; 47fb726d48Sopenharmony_ci private energyTraceRow: TraceRow<BaseStruct> | undefined; 48fb726d48Sopenharmony_ci private timer: number | undefined; 49fb726d48Sopenharmony_ci private eventNameMap: Map<number, string> = new Map(); 50fb726d48Sopenharmony_ci private appKeyMap: Map<number, string> = new Map(); 51fb726d48Sopenharmony_ci private eventValueMap: Map<number, string> = new Map(); 52fb726d48Sopenharmony_ci private powerEventNameMap: Map<number, string> = new Map(); 53fb726d48Sopenharmony_ci private powerAppKeyNameMap: Map<number, string> = new Map(); 54fb726d48Sopenharmony_ci private powerEventValueMap: Map<number, string> = new Map(); 55fb726d48Sopenharmony_ci private stateName: Array<string> = [ 56fb726d48Sopenharmony_ci 'BRIGHTNESS_NIT', 57fb726d48Sopenharmony_ci 'SIGNAL_LEVEL', 58fb726d48Sopenharmony_ci 'WIFI_EVENT_RECEIVED', 59fb726d48Sopenharmony_ci 'AUDIO_STREAM_CHANGE', 60fb726d48Sopenharmony_ci 'AUDIO_VOLUME_CHANGE', 61fb726d48Sopenharmony_ci 'WIFI_STATE', 62fb726d48Sopenharmony_ci 'BLUETOOTH_BR_SWITCH_STATE', 63fb726d48Sopenharmony_ci 'BR_SWITCH_STATE', 64fb726d48Sopenharmony_ci 'LOCATION_SWITCH_STATE', 65fb726d48Sopenharmony_ci 'SENSOR_STATE', 66fb726d48Sopenharmony_ci ]; 67fb726d48Sopenharmony_ci private initValueList: Array<string> = [ 68fb726d48Sopenharmony_ci 'brightness', 69fb726d48Sopenharmony_ci 'nocolumn', 70fb726d48Sopenharmony_ci 'nocolumn', 71fb726d48Sopenharmony_ci 'nocolumn', 72fb726d48Sopenharmony_ci 'nocolumn', 73fb726d48Sopenharmony_ci 'wifi', 74fb726d48Sopenharmony_ci 'bt_state', 75fb726d48Sopenharmony_ci 'bt_state', 76fb726d48Sopenharmony_ci 'location', 77fb726d48Sopenharmony_ci 'nocolumn', 78fb726d48Sopenharmony_ci ]; 79fb726d48Sopenharmony_ci private stateList: Array<string> = [ 80fb726d48Sopenharmony_ci 'Brightness Nit', 81fb726d48Sopenharmony_ci 'Signal Level', 82fb726d48Sopenharmony_ci 'Wifi Event Received', 83fb726d48Sopenharmony_ci 'Audio Stream Change', 84fb726d48Sopenharmony_ci 'Audio Volume Change', 85fb726d48Sopenharmony_ci 'Wifi State', 86fb726d48Sopenharmony_ci 'Bluetooth Br Switch State', 87fb726d48Sopenharmony_ci 'Br Switch State', 88fb726d48Sopenharmony_ci 'Location Switch State', 89fb726d48Sopenharmony_ci 'Sensor State', 90fb726d48Sopenharmony_ci ]; 91fb726d48Sopenharmony_ci 92fb726d48Sopenharmony_ci constructor(trace: SpSystemTrace) { 93fb726d48Sopenharmony_ci this.trace = trace; 94fb726d48Sopenharmony_ci } 95fb726d48Sopenharmony_ci 96fb726d48Sopenharmony_ci async init(): Promise<void> { 97fb726d48Sopenharmony_ci let result = await queryEnergyEventExits(); 98fb726d48Sopenharmony_ci if (result.length <= 0) { 99fb726d48Sopenharmony_ci return; 100fb726d48Sopenharmony_ci } 101fb726d48Sopenharmony_ci let anomalyData = await queryAnomalyData(); 102fb726d48Sopenharmony_ci let powerData = await queryPowerData(); 103fb726d48Sopenharmony_ci for (let index = 0; index < anomalyData.length; index++) { 104fb726d48Sopenharmony_ci let item = anomalyData[index]; 105fb726d48Sopenharmony_ci this.eventNameMap.set(item.id!, item.eventName ?? ''); 106fb726d48Sopenharmony_ci this.appKeyMap.set(item.id!, item.appKey ?? ''); 107fb726d48Sopenharmony_ci this.eventValueMap.set(item.id!, item.eventValue ?? ''); 108fb726d48Sopenharmony_ci } 109fb726d48Sopenharmony_ci for (let index = 0; index < powerData.length; index++) { 110fb726d48Sopenharmony_ci let item = powerData[index]; 111fb726d48Sopenharmony_ci this.powerEventNameMap.set(item.id, item.eventName ?? ''); 112fb726d48Sopenharmony_ci this.powerAppKeyNameMap.set(item.id, item.appKey ?? ''); 113fb726d48Sopenharmony_ci this.powerEventValueMap.set(item.id, item.eventValue ?? ''); 114fb726d48Sopenharmony_ci } 115fb726d48Sopenharmony_ci await this.initEnergyRow(); 116fb726d48Sopenharmony_ci this.initAnomaly(); 117fb726d48Sopenharmony_ci this.initSystem(); 118fb726d48Sopenharmony_ci this.initPower(); 119fb726d48Sopenharmony_ci await this.initState(); 120fb726d48Sopenharmony_ci } 121fb726d48Sopenharmony_ci 122fb726d48Sopenharmony_ci private async initEnergyRow(): Promise<void> { 123fb726d48Sopenharmony_ci await this.initEnergyChartRow(); 124fb726d48Sopenharmony_ci this.energyTraceRow!.favoriteChangeHandler = this.trace.favoriteChangeHandler; 125fb726d48Sopenharmony_ci this.energyTraceRow!.selectChangeHandler = this.trace.selectChangeHandler; 126fb726d48Sopenharmony_ci this.energyTraceRow!.supplier = (): Promise<BaseStruct[]> => 127fb726d48Sopenharmony_ci new Promise<Array<BaseStruct>>((resolve) => resolve([])); 128fb726d48Sopenharmony_ci this.energyTraceRow!.onThreadHandler = (useCache: boolean): void => { 129fb726d48Sopenharmony_ci this.energyTraceRow?.canvasSave(this.trace.canvasPanelCtx!); 130fb726d48Sopenharmony_ci if (this.energyTraceRow!.expansion) { 131fb726d48Sopenharmony_ci // @ts-ignore 132fb726d48Sopenharmony_ci this.trace.canvasPanelCtx?.clearRect(0, 0, this.energyTraceRow!.frame.width, this.energyTraceRow!.frame.height); 133fb726d48Sopenharmony_ci } else { 134fb726d48Sopenharmony_ci (renders.empty as EmptyRender).renderMainThread( 135fb726d48Sopenharmony_ci { 136fb726d48Sopenharmony_ci context: this.trace.canvasPanelCtx, 137fb726d48Sopenharmony_ci useCache: useCache, 138fb726d48Sopenharmony_ci type: '', 139fb726d48Sopenharmony_ci }, 140fb726d48Sopenharmony_ci this.energyTraceRow! 141fb726d48Sopenharmony_ci ); 142fb726d48Sopenharmony_ci } 143fb726d48Sopenharmony_ci this.energyTraceRow?.canvasRestore(this.trace.canvasPanelCtx!, this.trace); 144fb726d48Sopenharmony_ci }; 145fb726d48Sopenharmony_ci this.energyTraceRow!.addEventListener('expansion-change', () => { 146fb726d48Sopenharmony_ci TraceRow.range!.refresh = true; 147fb726d48Sopenharmony_ci this.trace.refreshCanvas(false); 148fb726d48Sopenharmony_ci if (this.timer) { 149fb726d48Sopenharmony_ci clearTimeout(this.timer); 150fb726d48Sopenharmony_ci } 151fb726d48Sopenharmony_ci this.timer = window.setTimeout((): void => { 152fb726d48Sopenharmony_ci TraceRow.range!.refresh = false; 153fb726d48Sopenharmony_ci }, NUM_200); 154fb726d48Sopenharmony_ci }); 155fb726d48Sopenharmony_ci this.trace.rowsEL?.appendChild(this.energyTraceRow!); 156fb726d48Sopenharmony_ci } 157fb726d48Sopenharmony_ci 158fb726d48Sopenharmony_ci private initAnomaly = (): void => { 159fb726d48Sopenharmony_ci let time = new Date().getTime(); 160fb726d48Sopenharmony_ci let anomalyTraceRow = this.initAnomalyChartRow(); 161fb726d48Sopenharmony_ci anomalyTraceRow.supplierFrame = async (): Promise<EnergyAnomalyStruct[]> => { 162fb726d48Sopenharmony_ci return hiSysEnergyAnomalyDataSender(anomalyTraceRow).then((res: EnergyAnomalyStruct[]) => { 163fb726d48Sopenharmony_ci for (let index = 0; index < res.length; index++) { 164fb726d48Sopenharmony_ci let item = res[index]; 165fb726d48Sopenharmony_ci item.eventName = this.eventNameMap.get(res[index].id!); 166fb726d48Sopenharmony_ci item.appKey = this.appKeyMap.get(res[index].id!); 167fb726d48Sopenharmony_ci item.eventValue = this.eventValueMap.get(res[index].id!); 168fb726d48Sopenharmony_ci } 169fb726d48Sopenharmony_ci return res; 170fb726d48Sopenharmony_ci }); 171fb726d48Sopenharmony_ci }; 172fb726d48Sopenharmony_ci anomalyTraceRow.findHoverStruct = (): void => { 173fb726d48Sopenharmony_ci EnergyAnomalyStruct.hoverEnergyAnomalyStruct = anomalyTraceRow.getHoverStruct(); 174fb726d48Sopenharmony_ci }; 175fb726d48Sopenharmony_ci anomalyTraceRow.onThreadHandler = (useCache: boolean): void => { 176fb726d48Sopenharmony_ci let context: CanvasRenderingContext2D; 177fb726d48Sopenharmony_ci if (anomalyTraceRow.currentContext) { 178fb726d48Sopenharmony_ci context = anomalyTraceRow.currentContext; 179fb726d48Sopenharmony_ci } else { 180fb726d48Sopenharmony_ci context = anomalyTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 181fb726d48Sopenharmony_ci } 182fb726d48Sopenharmony_ci anomalyTraceRow.canvasSave(context); 183fb726d48Sopenharmony_ci (renders.energyAnomaly as EnergyAnomalyRender).renderMainThread( 184fb726d48Sopenharmony_ci { 185fb726d48Sopenharmony_ci context: context, 186fb726d48Sopenharmony_ci useCache: useCache, 187fb726d48Sopenharmony_ci type: 'energyAnomaly', 188fb726d48Sopenharmony_ci appName: SpHiSysEnergyChart.app_name || '', 189fb726d48Sopenharmony_ci canvasWidth: this.trace.canvasPanel?.width || 0, 190fb726d48Sopenharmony_ci }, 191fb726d48Sopenharmony_ci anomalyTraceRow 192fb726d48Sopenharmony_ci ); 193fb726d48Sopenharmony_ci anomalyTraceRow.canvasRestore(context, this.trace); 194fb726d48Sopenharmony_ci }; 195fb726d48Sopenharmony_ci this.energyTraceRow?.addChildTraceRow(anomalyTraceRow); 196fb726d48Sopenharmony_ci let durTime = new Date().getTime() - time; 197fb726d48Sopenharmony_ci info('The time to load the anomaly is: ', durTime); 198fb726d48Sopenharmony_ci }; 199fb726d48Sopenharmony_ci 200fb726d48Sopenharmony_ci private initSystem = (): void => { 201fb726d48Sopenharmony_ci let time = new Date().getTime(); 202fb726d48Sopenharmony_ci let systemTraceRow = this.initSystemChartRow(); 203fb726d48Sopenharmony_ci systemTraceRow.supplierFrame = async (): Promise<EnergySystemStruct[]> => { 204fb726d48Sopenharmony_ci return energySysEventSender(systemTraceRow).then((res: EnergySystemStruct[]) => { 205fb726d48Sopenharmony_ci return res; 206fb726d48Sopenharmony_ci }); 207fb726d48Sopenharmony_ci }; 208fb726d48Sopenharmony_ci systemTraceRow.findHoverStruct = (): void => { 209fb726d48Sopenharmony_ci EnergySystemStruct.hoverEnergySystemStruct = systemTraceRow.getHoverStruct(); 210fb726d48Sopenharmony_ci }; 211fb726d48Sopenharmony_ci systemTraceRow.onThreadHandler = (useCache: boolean): void => { 212fb726d48Sopenharmony_ci let context: CanvasRenderingContext2D; 213fb726d48Sopenharmony_ci if (systemTraceRow.currentContext) { 214fb726d48Sopenharmony_ci context = systemTraceRow.currentContext; 215fb726d48Sopenharmony_ci } else { 216fb726d48Sopenharmony_ci context = systemTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 217fb726d48Sopenharmony_ci } 218fb726d48Sopenharmony_ci systemTraceRow.canvasSave(context); 219fb726d48Sopenharmony_ci (renders.energySystem as EnergySystemRender).renderMainThread( 220fb726d48Sopenharmony_ci { 221fb726d48Sopenharmony_ci context: context, 222fb726d48Sopenharmony_ci useCache: useCache, 223fb726d48Sopenharmony_ci type: 'energySystem', 224fb726d48Sopenharmony_ci }, 225fb726d48Sopenharmony_ci systemTraceRow 226fb726d48Sopenharmony_ci ); 227fb726d48Sopenharmony_ci systemTraceRow.canvasRestore(context, this.trace); 228fb726d48Sopenharmony_ci }; 229fb726d48Sopenharmony_ci this.energyTraceRow?.addChildTraceRow(systemTraceRow); 230fb726d48Sopenharmony_ci let durTime = new Date().getTime() - time; 231fb726d48Sopenharmony_ci info('The time to load the Ability Memory is: ', durTime); 232fb726d48Sopenharmony_ci }; 233fb726d48Sopenharmony_ci 234fb726d48Sopenharmony_ci private initPower = (): void => { 235fb726d48Sopenharmony_ci let time = new Date().getTime(); 236fb726d48Sopenharmony_ci let powerTraceRow = this.initPowerChartRow(); 237fb726d48Sopenharmony_ci powerTraceRow.supplierFrame = async (): Promise<EnergyPowerStruct[]> => { 238fb726d48Sopenharmony_ci return hiSysEnergyPowerSender(powerTraceRow).then((res) => { 239fb726d48Sopenharmony_ci for (let index = 0; index < res.length; index++) { 240fb726d48Sopenharmony_ci let item = res[index]; 241fb726d48Sopenharmony_ci item.eventName = this.powerEventNameMap.get(res[index].id!); 242fb726d48Sopenharmony_ci item.appKey = this.powerAppKeyNameMap.get(res[index].id!); 243fb726d48Sopenharmony_ci item.eventValue = this.powerEventValueMap.get(res[index].id!); 244fb726d48Sopenharmony_ci } 245fb726d48Sopenharmony_ci return this.getPowerData(res); 246fb726d48Sopenharmony_ci }); 247fb726d48Sopenharmony_ci }; 248fb726d48Sopenharmony_ci powerTraceRow.onThreadHandler = (useCache: boolean): void => { 249fb726d48Sopenharmony_ci let context: CanvasRenderingContext2D; 250fb726d48Sopenharmony_ci if (powerTraceRow.currentContext) { 251fb726d48Sopenharmony_ci context = powerTraceRow.currentContext; 252fb726d48Sopenharmony_ci } else { 253fb726d48Sopenharmony_ci context = powerTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 254fb726d48Sopenharmony_ci } 255fb726d48Sopenharmony_ci powerTraceRow.canvasSave(context); 256fb726d48Sopenharmony_ci (renders.energyPower as EnergyPowerRender).renderMainThread( 257fb726d48Sopenharmony_ci { 258fb726d48Sopenharmony_ci context: context, 259fb726d48Sopenharmony_ci useCache: useCache, 260fb726d48Sopenharmony_ci type: 'energyPower', 261fb726d48Sopenharmony_ci appName: SpHiSysEnergyChart.app_name || '', 262fb726d48Sopenharmony_ci }, 263fb726d48Sopenharmony_ci powerTraceRow! 264fb726d48Sopenharmony_ci ); 265fb726d48Sopenharmony_ci powerTraceRow!.canvasRestore(context, this.trace); 266fb726d48Sopenharmony_ci }; 267fb726d48Sopenharmony_ci this.energyTraceRow?.addChildTraceRow(powerTraceRow); 268fb726d48Sopenharmony_ci let durTime = new Date().getTime() - time; 269fb726d48Sopenharmony_ci info('The time to load the energy power is: ', durTime); 270fb726d48Sopenharmony_ci }; 271fb726d48Sopenharmony_ci 272fb726d48Sopenharmony_ci private initState = async (): Promise<void> => { 273fb726d48Sopenharmony_ci let time = new Date().getTime(); 274fb726d48Sopenharmony_ci for (let index = 0; index < this.stateList.length; index++) { 275fb726d48Sopenharmony_ci let stateResult = await queryStateInitValue(this.stateName[index], this.initValueList[index]); 276fb726d48Sopenharmony_ci let maxStateData = await queryMaxStateValue(this.stateName[index]); 277fb726d48Sopenharmony_ci if (!maxStateData[0]) { 278fb726d48Sopenharmony_ci continue; 279fb726d48Sopenharmony_ci } 280fb726d48Sopenharmony_ci let maxStateTotal = this.getMaxStateTotal(maxStateData); 281fb726d48Sopenharmony_ci let stateTraceRow = this.initStatChartRow(index); 282fb726d48Sopenharmony_ci stateTraceRow.supplierFrame = async (): Promise<EnergyStateStruct[]> => { 283fb726d48Sopenharmony_ci const res = await hiSysEnergyStateSender(this.stateName, index, stateTraceRow); 284fb726d48Sopenharmony_ci let stateInitValue = this.initValueList[index] === 'nocolumn' ? [] : stateResult; 285fb726d48Sopenharmony_ci for (let i = 0; i < res.length; i++) { 286fb726d48Sopenharmony_ci let item = res[i]; 287fb726d48Sopenharmony_ci item.type = this.stateName[index]; 288fb726d48Sopenharmony_ci } 289fb726d48Sopenharmony_ci return stateInitValue.concat(res); 290fb726d48Sopenharmony_ci }; 291fb726d48Sopenharmony_ci stateTraceRow.onThreadHandler = (useCache: boolean): void => { 292fb726d48Sopenharmony_ci let context: CanvasRenderingContext2D; 293fb726d48Sopenharmony_ci if (stateTraceRow.currentContext) { 294fb726d48Sopenharmony_ci context = stateTraceRow.currentContext; 295fb726d48Sopenharmony_ci } else { 296fb726d48Sopenharmony_ci context = stateTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 297fb726d48Sopenharmony_ci } 298fb726d48Sopenharmony_ci stateTraceRow.canvasSave(context); 299fb726d48Sopenharmony_ci (renders.energyState as EnergyStateRender).renderMainThread( 300fb726d48Sopenharmony_ci { 301fb726d48Sopenharmony_ci context: context, 302fb726d48Sopenharmony_ci useCache: useCache, 303fb726d48Sopenharmony_ci type: `energyState${index}`, 304fb726d48Sopenharmony_ci maxState: maxStateData[0].maxValue, 305fb726d48Sopenharmony_ci maxStateName: maxStateData[0].type.toLocaleLowerCase().endsWith('br_switch_state') 306fb726d48Sopenharmony_ci ? '-1' 307fb726d48Sopenharmony_ci : maxStateTotal.toString(), 308fb726d48Sopenharmony_ci }, 309fb726d48Sopenharmony_ci stateTraceRow 310fb726d48Sopenharmony_ci ); 311fb726d48Sopenharmony_ci stateTraceRow.canvasRestore(context, this.trace); 312fb726d48Sopenharmony_ci }; 313fb726d48Sopenharmony_ci this.energyTraceRow?.addChildTraceRow(stateTraceRow); 314fb726d48Sopenharmony_ci let durTime = new Date().getTime() - time; 315fb726d48Sopenharmony_ci info('The time to load the Ability Memory is: ', durTime); 316fb726d48Sopenharmony_ci } 317fb726d48Sopenharmony_ci }; 318fb726d48Sopenharmony_ci 319fb726d48Sopenharmony_ci private getMaxStateTotal( 320fb726d48Sopenharmony_ci maxStateData: Array<{ 321fb726d48Sopenharmony_ci type: string; 322fb726d48Sopenharmony_ci maxValue: number; 323fb726d48Sopenharmony_ci }> 324fb726d48Sopenharmony_ci ): string { 325fb726d48Sopenharmony_ci let maxStateTotal = maxStateData[0].maxValue.toString(); 326fb726d48Sopenharmony_ci let statType = maxStateData[0].type.toLocaleLowerCase(); 327fb726d48Sopenharmony_ci if (statType.includes('state') && !statType.endsWith('br_switch_state')) { 328fb726d48Sopenharmony_ci if (maxStateData[0].maxValue === 0) { 329fb726d48Sopenharmony_ci maxStateTotal = 'enable'; 330fb726d48Sopenharmony_ci } else { 331fb726d48Sopenharmony_ci maxStateTotal = 'disable'; 332fb726d48Sopenharmony_ci } 333fb726d48Sopenharmony_ci } else if (statType.includes('sensor')) { 334fb726d48Sopenharmony_ci if (statType.includes('enable')) { 335fb726d48Sopenharmony_ci maxStateTotal = 'enable'; 336fb726d48Sopenharmony_ci } else { 337fb726d48Sopenharmony_ci maxStateTotal = 'disable'; 338fb726d48Sopenharmony_ci } 339fb726d48Sopenharmony_ci } 340fb726d48Sopenharmony_ci return maxStateTotal; 341fb726d48Sopenharmony_ci } 342fb726d48Sopenharmony_ci 343fb726d48Sopenharmony_ci private initStatChartRow(index: number): TraceRow<EnergyStateStruct> { 344fb726d48Sopenharmony_ci let stateTraceRow = TraceRow.skeleton<EnergyStateStruct>(); 345fb726d48Sopenharmony_ci stateTraceRow.rowParentId = 'energy'; 346fb726d48Sopenharmony_ci stateTraceRow.rowHidden = true; 347fb726d48Sopenharmony_ci stateTraceRow.rowId = `energy-state-${this.stateList[index]}`; 348fb726d48Sopenharmony_ci stateTraceRow.rowType = TraceRow.ROW_TYPE_STATE_ENERGY; 349fb726d48Sopenharmony_ci stateTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 350fb726d48Sopenharmony_ci stateTraceRow.selectChangeHandler = this.trace.selectChangeHandler; 351fb726d48Sopenharmony_ci stateTraceRow.style.height = '40px'; 352fb726d48Sopenharmony_ci stateTraceRow.style.width = '100%'; 353fb726d48Sopenharmony_ci stateTraceRow.setAttribute('children', ''); 354fb726d48Sopenharmony_ci stateTraceRow.name = `${this.stateList[index]}`; 355fb726d48Sopenharmony_ci stateTraceRow.focusHandler = (): void => { 356fb726d48Sopenharmony_ci let tip; 357fb726d48Sopenharmony_ci if (EnergyStateStruct.hoverEnergyStateStruct?.type!.toLocaleLowerCase().includes('state')) { 358fb726d48Sopenharmony_ci tip = `<span>Switch Status: ${ 359fb726d48Sopenharmony_ci EnergyStateStruct.hoverEnergyStateStruct?.value === 1 ? 'disable' : 'enable' 360fb726d48Sopenharmony_ci }</span>`; 361fb726d48Sopenharmony_ci if (EnergyStateStruct.hoverEnergyStateStruct?.type!.toLocaleLowerCase().endsWith('br_switch_state')) { 362fb726d48Sopenharmony_ci tip = `<span>${SpHiSysEnergyChart.getBlueToothState(EnergyStateStruct.hoverEnergyStateStruct?.value)}</span>`; 363fb726d48Sopenharmony_ci } 364fb726d48Sopenharmony_ci } else { 365fb726d48Sopenharmony_ci tip = `<span>value: ${EnergyStateStruct.hoverEnergyStateStruct?.value?.toFixed(2) || 0}</span>`; 366fb726d48Sopenharmony_ci } 367fb726d48Sopenharmony_ci this.trace?.displayTip(stateTraceRow, EnergyStateStruct.hoverEnergyStateStruct, tip); 368fb726d48Sopenharmony_ci }; 369fb726d48Sopenharmony_ci return stateTraceRow; 370fb726d48Sopenharmony_ci } 371fb726d48Sopenharmony_ci 372fb726d48Sopenharmony_ci private async initEnergyChartRow(): Promise<void> { 373fb726d48Sopenharmony_ci SpHiSysEnergyChart.app_name = ''; 374fb726d48Sopenharmony_ci let appNameFromTable = await queryEnergyAppName(); 375fb726d48Sopenharmony_ci let configAppName = await queryConfigEnergyAppName(); 376fb726d48Sopenharmony_ci if (configAppName.length > 0 && appNameFromTable.length > 0) { 377fb726d48Sopenharmony_ci let name = configAppName[0].process_name; 378fb726d48Sopenharmony_ci if (name !== null) { 379fb726d48Sopenharmony_ci let filterList = appNameFromTable.filter((appNameFromTableElement) => { 380fb726d48Sopenharmony_ci return appNameFromTableElement.string_value?.trim() === name; 381fb726d48Sopenharmony_ci }); 382fb726d48Sopenharmony_ci if (filterList.length > 0) { 383fb726d48Sopenharmony_ci SpHiSysEnergyChart.app_name = name; 384fb726d48Sopenharmony_ci } 385fb726d48Sopenharmony_ci } 386fb726d48Sopenharmony_ci } 387fb726d48Sopenharmony_ci appNameFromTable.sort((a, b) => { 388fb726d48Sopenharmony_ci return a.string_value!.localeCompare(b.string_value!); 389fb726d48Sopenharmony_ci }); 390fb726d48Sopenharmony_ci if (appNameFromTable.length > 0 && SpHiSysEnergyChart.app_name === '') { 391fb726d48Sopenharmony_ci SpHiSysEnergyChart.app_name = appNameFromTable[0].string_value; 392fb726d48Sopenharmony_ci } 393fb726d48Sopenharmony_ci this.energyTraceRow = TraceRow.skeleton<BaseStruct>(); 394fb726d48Sopenharmony_ci this.energyTraceRow.addRowSettingPop(); 395fb726d48Sopenharmony_ci this.energyTraceRow.rowSetting = 'enable'; 396fb726d48Sopenharmony_ci this.energyTraceRow.rowSettingPopoverDirection = 'bottomLeft'; 397fb726d48Sopenharmony_ci let nameList: Array<TreeItemData> = []; 398fb726d48Sopenharmony_ci for (let index = 0; index < appNameFromTable.length; index++) { 399fb726d48Sopenharmony_ci let appName = appNameFromTable[index].string_value; 400fb726d48Sopenharmony_ci nameList.push({ 401fb726d48Sopenharmony_ci key: `${appName}`, 402fb726d48Sopenharmony_ci title: `${appName}`, 403fb726d48Sopenharmony_ci checked: index === 0, 404fb726d48Sopenharmony_ci }); 405fb726d48Sopenharmony_ci } 406fb726d48Sopenharmony_ci this.energyTraceRow.rowSettingList = nameList; 407fb726d48Sopenharmony_ci this.energyTraceRow.onRowSettingChangeHandler = (value): void => { 408fb726d48Sopenharmony_ci SpHiSysEnergyChart.app_name = value[0]; 409fb726d48Sopenharmony_ci this.trace.refreshCanvas(false); 410fb726d48Sopenharmony_ci }; 411fb726d48Sopenharmony_ci this.energyTraceRow.rowId = 'energy'; 412fb726d48Sopenharmony_ci this.energyTraceRow.rowType = TraceRow.ROW_TYPE_ENERGY; 413fb726d48Sopenharmony_ci this.energyTraceRow.rowParentId = ''; 414fb726d48Sopenharmony_ci this.energyTraceRow.folder = true; 415fb726d48Sopenharmony_ci this.energyTraceRow.addTemplateTypes('EnergyEvent'); 416fb726d48Sopenharmony_ci this.energyTraceRow.name = 'Energy'; 417fb726d48Sopenharmony_ci this.energyTraceRow.style.height = '40px'; 418fb726d48Sopenharmony_ci } 419fb726d48Sopenharmony_ci 420fb726d48Sopenharmony_ci private initAnomalyChartRow(): TraceRow<EnergyAnomalyStruct> { 421fb726d48Sopenharmony_ci let anomalyTraceRow = TraceRow.skeleton<EnergyAnomalyStruct>(); 422fb726d48Sopenharmony_ci anomalyTraceRow.rowParentId = 'energy'; 423fb726d48Sopenharmony_ci anomalyTraceRow.rowHidden = true; 424fb726d48Sopenharmony_ci anomalyTraceRow.rowId = 'energy-anomaly'; 425fb726d48Sopenharmony_ci anomalyTraceRow.rowType = TraceRow.ROW_TYPE_ANOMALY_ENERGY; 426fb726d48Sopenharmony_ci anomalyTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 427fb726d48Sopenharmony_ci anomalyTraceRow.selectChangeHandler = this.trace.selectChangeHandler; 428fb726d48Sopenharmony_ci anomalyTraceRow.setAttribute('height', '55px'); 429fb726d48Sopenharmony_ci let element = anomalyTraceRow.shadowRoot?.querySelector('.root') as HTMLDivElement; 430fb726d48Sopenharmony_ci element!.style.height = '55px'; 431fb726d48Sopenharmony_ci anomalyTraceRow.style.width = '100%'; 432fb726d48Sopenharmony_ci anomalyTraceRow.setAttribute('children', ''); 433fb726d48Sopenharmony_ci anomalyTraceRow.name = 'Anomaly Event'; 434fb726d48Sopenharmony_ci anomalyTraceRow.focusHandler = (): void => { 435fb726d48Sopenharmony_ci this.trace?.displayTip( 436fb726d48Sopenharmony_ci anomalyTraceRow, 437fb726d48Sopenharmony_ci EnergyAnomalyStruct.hoverEnergyAnomalyStruct, 438fb726d48Sopenharmony_ci `<span>AnomalyName:${EnergyAnomalyStruct.hoverEnergyAnomalyStruct?.eventName || ''}</span>` 439fb726d48Sopenharmony_ci ); 440fb726d48Sopenharmony_ci }; 441fb726d48Sopenharmony_ci return anomalyTraceRow; 442fb726d48Sopenharmony_ci } 443fb726d48Sopenharmony_ci 444fb726d48Sopenharmony_ci private initSystemChartRow(): TraceRow<EnergySystemStruct> { 445fb726d48Sopenharmony_ci let systemTraceRow = TraceRow.skeleton<EnergySystemStruct>(); 446fb726d48Sopenharmony_ci systemTraceRow.rowParentId = 'energy'; 447fb726d48Sopenharmony_ci systemTraceRow.rowHidden = true; 448fb726d48Sopenharmony_ci systemTraceRow.rowId = 'energy-system'; 449fb726d48Sopenharmony_ci systemTraceRow.rowType = TraceRow.ROW_TYPE_SYSTEM_ENERGY; 450fb726d48Sopenharmony_ci systemTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 451fb726d48Sopenharmony_ci systemTraceRow.selectChangeHandler = this.trace.selectChangeHandler; 452fb726d48Sopenharmony_ci systemTraceRow.setAttribute('height', '80px'); 453fb726d48Sopenharmony_ci let element = systemTraceRow.shadowRoot?.querySelector('.root') as HTMLDivElement; 454fb726d48Sopenharmony_ci element!.style.height = '90px'; 455fb726d48Sopenharmony_ci systemTraceRow.style.width = '100%'; 456fb726d48Sopenharmony_ci systemTraceRow.setAttribute('children', ''); 457fb726d48Sopenharmony_ci systemTraceRow.name = 'System Event'; 458fb726d48Sopenharmony_ci systemTraceRow.focusHandler = (): void => { 459fb726d48Sopenharmony_ci this.trace?.displayTip(systemTraceRow, EnergySystemStruct.hoverEnergySystemStruct, this.getSystemFocusHtml()); 460fb726d48Sopenharmony_ci }; 461fb726d48Sopenharmony_ci return systemTraceRow; 462fb726d48Sopenharmony_ci } 463fb726d48Sopenharmony_ci 464fb726d48Sopenharmony_ci private getSystemFocusHtml(): string { 465fb726d48Sopenharmony_ci return ` 466fb726d48Sopenharmony_ci<div style="width: 250px"> 467fb726d48Sopenharmony_ci <div style=" display: flex"> 468fb726d48Sopenharmony_ci <div style="width: 75%;text-align: left">WORKSCHEDULER: </div> 469fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergySystemStruct.hoverEnergySystemStruct?.workScheduler! || 0}</div> 470fb726d48Sopenharmony_ci </div> 471fb726d48Sopenharmony_ci <div style="display: flex"> 472fb726d48Sopenharmony_ci <div style="width: 75%;text-align: left">POWER_RUNNINGLOCK: </div> 473fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergySystemStruct.hoverEnergySystemStruct?.power! || 0}</div> 474fb726d48Sopenharmony_ci </div> 475fb726d48Sopenharmony_ci <div style="display: flex"> 476fb726d48Sopenharmony_ci <div style="width: 75%;text-align: left">LOCATION: </div> 477fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergySystemStruct.hoverEnergySystemStruct?.location! || 0}</div> 478fb726d48Sopenharmony_ci </div> 479fb726d48Sopenharmony_ci</div>`; 480fb726d48Sopenharmony_ci } 481fb726d48Sopenharmony_ci 482fb726d48Sopenharmony_ci private getPowerFocusHtml(): string { 483fb726d48Sopenharmony_ci return ` 484fb726d48Sopenharmony_ci<div style="width: 120px"> 485fb726d48Sopenharmony_ci <div style="display: flex"> 486fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">CPU: </div> 487fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.cpu! || 0}</div> 488fb726d48Sopenharmony_ci </div> 489fb726d48Sopenharmony_ci <div style="display: flex"> 490fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">location: </div> 491fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.location! || 0}</div> 492fb726d48Sopenharmony_ci </div> 493fb726d48Sopenharmony_ci <div style="display: flex"> 494fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">GPU: </div> 495fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.gpu! || 0}</div> 496fb726d48Sopenharmony_ci </div> 497fb726d48Sopenharmony_ci <div style="display: flex"> 498fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">display: </div> 499fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.display! || 0}</div> 500fb726d48Sopenharmony_ci </div> 501fb726d48Sopenharmony_ci <div style="display: flex"> 502fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">camera: </div> 503fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.camera! || 0}</div> 504fb726d48Sopenharmony_ci </div> 505fb726d48Sopenharmony_ci <div style="display: flex"> 506fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">bluetooth: </div> 507fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.bluetooth! || 0}</div> 508fb726d48Sopenharmony_ci </div> 509fb726d48Sopenharmony_ci <div style="display: flex"> 510fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">flashlight: </div> 511fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.flashlight! || 0}</div> 512fb726d48Sopenharmony_ci </div> 513fb726d48Sopenharmony_ci <div style="display: flex"> 514fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">audio: </div> 515fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.audio! || 0}</div> 516fb726d48Sopenharmony_ci </div> 517fb726d48Sopenharmony_ci <div style="display: flex"> 518fb726d48Sopenharmony_ci <div style="width: 80%;text-align: left">wifiScan: </div> 519fb726d48Sopenharmony_ci <div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct?.wifiscan! || 0}</div> 520fb726d48Sopenharmony_ci </div> 521fb726d48Sopenharmony_ci</div>`; 522fb726d48Sopenharmony_ci } 523fb726d48Sopenharmony_ci 524fb726d48Sopenharmony_ci private initPowerChartRow(): TraceRow<EnergyPowerStruct> { 525fb726d48Sopenharmony_ci let powerTraceRow = TraceRow.skeleton<EnergyPowerStruct>(); 526fb726d48Sopenharmony_ci powerTraceRow.rowParentId = 'energy'; 527fb726d48Sopenharmony_ci powerTraceRow.rowHidden = true; 528fb726d48Sopenharmony_ci powerTraceRow.rowId = 'energy-power'; 529fb726d48Sopenharmony_ci powerTraceRow.rowType = TraceRow.ROW_TYPE_POWER_ENERGY; 530fb726d48Sopenharmony_ci powerTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 531fb726d48Sopenharmony_ci powerTraceRow.selectChangeHandler = this.trace.selectChangeHandler; 532fb726d48Sopenharmony_ci powerTraceRow.setAttribute('height', '200px'); 533fb726d48Sopenharmony_ci let element = powerTraceRow.shadowRoot?.querySelector('.root') as HTMLDivElement; 534fb726d48Sopenharmony_ci element!.style.height = '200px'; 535fb726d48Sopenharmony_ci powerTraceRow.style.width = '100%'; 536fb726d48Sopenharmony_ci powerTraceRow.setAttribute('children', ''); 537fb726d48Sopenharmony_ci powerTraceRow.name = 'Power'; 538fb726d48Sopenharmony_ci powerTraceRow.focusHandler = (): void => { 539fb726d48Sopenharmony_ci this.trace?.displayTip(powerTraceRow, EnergyPowerStruct.hoverEnergyPowerStruct, this.getPowerFocusHtml()); 540fb726d48Sopenharmony_ci }; 541fb726d48Sopenharmony_ci return powerTraceRow; 542fb726d48Sopenharmony_ci } 543fb726d48Sopenharmony_ci 544fb726d48Sopenharmony_ci private getPowerData(items: unknown): EnergyPowerStruct[] { 545fb726d48Sopenharmony_ci let powerDataMap: unknown = {}; 546fb726d48Sopenharmony_ci let appNameList: string[] = []; //@ts-ignore 547fb726d48Sopenharmony_ci items.forEach( 548fb726d48Sopenharmony_ci (item: { id: number; startNS: number; eventName: string; appKey: string; eventValue: string }): void => { 549fb726d48Sopenharmony_ci //@ts-ignore 550fb726d48Sopenharmony_ci let dataItem = powerDataMap[item.startNS]; 551fb726d48Sopenharmony_ci if (dataItem === undefined) { 552fb726d48Sopenharmony_ci if (item.appKey === 'APPNAME') { 553fb726d48Sopenharmony_ci let appMap: unknown = {}; 554fb726d48Sopenharmony_ci let appNames = item.eventValue.split(','); 555fb726d48Sopenharmony_ci appNameList = appNames; 556fb726d48Sopenharmony_ci if (appNames.length > 0) { 557fb726d48Sopenharmony_ci for (let appNamesKey of appNames) { 558fb726d48Sopenharmony_ci //@ts-ignore 559fb726d48Sopenharmony_ci appMap[appNamesKey] = new EnergyPowerStruct(); //@ts-ignore 560fb726d48Sopenharmony_ci appMap[appNamesKey].name = appNamesKey; //@ts-ignore 561fb726d48Sopenharmony_ci appMap[appNamesKey].ts = item.startNS; 562fb726d48Sopenharmony_ci } //@ts-ignore 563fb726d48Sopenharmony_ci powerDataMap[item.startNS] = appMap; 564fb726d48Sopenharmony_ci } 565fb726d48Sopenharmony_ci } 566fb726d48Sopenharmony_ci } else { 567fb726d48Sopenharmony_ci if (item.appKey !== 'APPNAME') { 568fb726d48Sopenharmony_ci this.powerDataMap(item.eventName, item.eventValue, appNameList, dataItem); 569fb726d48Sopenharmony_ci } else { 570fb726d48Sopenharmony_ci //@ts-ignore 571fb726d48Sopenharmony_ci let dataMap = powerDataMap[item.startNS]; 572fb726d48Sopenharmony_ci let appNames = item.eventValue.split(','); 573fb726d48Sopenharmony_ci appNameList = appNames; 574fb726d48Sopenharmony_ci if (appNames.length > 0) { 575fb726d48Sopenharmony_ci for (let appNamesKey of appNames) { 576fb726d48Sopenharmony_ci dataMap[appNamesKey] = new EnergyPowerStruct(); 577fb726d48Sopenharmony_ci dataMap[appNamesKey].name = appNamesKey; 578fb726d48Sopenharmony_ci dataMap[appNamesKey].ts = item.startNS; 579fb726d48Sopenharmony_ci } 580fb726d48Sopenharmony_ci } 581fb726d48Sopenharmony_ci } 582fb726d48Sopenharmony_ci } 583fb726d48Sopenharmony_ci } 584fb726d48Sopenharmony_ci ); 585fb726d48Sopenharmony_ci //@ts-ignore 586fb726d48Sopenharmony_ci return Object.values(powerDataMap); 587fb726d48Sopenharmony_ci } 588fb726d48Sopenharmony_ci 589fb726d48Sopenharmony_ci private powerDataMap(name: string, eventValue: string, appNameList: string[], dataItem: unknown): void { 590fb726d48Sopenharmony_ci let values = eventValue.split(','); 591fb726d48Sopenharmony_ci for (let i = 0; i < values.length; i++) { 592fb726d48Sopenharmony_ci let appName = appNameList[i]; //@ts-ignore 593fb726d48Sopenharmony_ci let obj = dataItem[appName]; 594fb726d48Sopenharmony_ci if (obj !== undefined) { 595fb726d48Sopenharmony_ci let eventName = name.split('_'); 596fb726d48Sopenharmony_ci let s = eventName[eventName.length - 1].toLocaleLowerCase(); 597fb726d48Sopenharmony_ci if (obj[s] === undefined) { 598fb726d48Sopenharmony_ci obj[s] = parseInt(values[i]); 599fb726d48Sopenharmony_ci } else { 600fb726d48Sopenharmony_ci obj[s] += parseInt(values[i]); 601fb726d48Sopenharmony_ci } 602fb726d48Sopenharmony_ci } 603fb726d48Sopenharmony_ci } 604fb726d48Sopenharmony_ci } 605fb726d48Sopenharmony_ci 606fb726d48Sopenharmony_ci public static getBlueToothState(num: number | undefined): string { 607fb726d48Sopenharmony_ci switch (num) { 608fb726d48Sopenharmony_ci case 0: 609fb726d48Sopenharmony_ci return 'STATE_TURNING_ON'; 610fb726d48Sopenharmony_ci case 1: 611fb726d48Sopenharmony_ci return 'STATE_TURN_ON'; 612fb726d48Sopenharmony_ci case 2: 613fb726d48Sopenharmony_ci return 'STATE_TURNING_OFF'; 614fb726d48Sopenharmony_ci case NUM_3: 615fb726d48Sopenharmony_ci return 'STATE_TURN_OFF'; 616fb726d48Sopenharmony_ci default: 617fb726d48Sopenharmony_ci return 'UNKNOWN_STATE'; 618fb726d48Sopenharmony_ci } 619fb726d48Sopenharmony_ci } 620fb726d48Sopenharmony_ci} 621