taotoolkit 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1344 @@
1
+ #!/usr/bin/env python
2
+ # -*- encoding: utf-8 -*-
3
+ """文件与 tuning 处理功能层。"""
4
+
5
+ import argparse
6
+ import os
7
+ import re
8
+ import sys
9
+ import ctypes
10
+ import shutil
11
+ from pathlib import Path
12
+ from typing import Tuple, Union
13
+
14
+ try:
15
+ import uiautomator2 as u2
16
+ except Exception: # pragma: no cover
17
+ u2 = None
18
+
19
+ from .tao_common import (
20
+ debugCtrl,
21
+ ErrCode,
22
+ createFolder,
23
+ eExit,
24
+ fileExceptionNotFound,
25
+ fileExceptionillegal,
26
+ fileExist,
27
+ checkMsg,
28
+ findFilesWithSuffix,
29
+ get_file_index,
30
+ is_number,
31
+ logd,
32
+ loge,
33
+ logh,
34
+ logi,
35
+ logw,
36
+ logCallErr,
37
+ sysVersion,
38
+ rCmd,
39
+ removeAnyContainStr,
40
+ sleep,
41
+ normalize_args,
42
+ register_command,
43
+ )
44
+
45
+
46
+ from .tao_device import DevOp
47
+
48
+
49
+ class asrTuningFile:
50
+ def __init__(self, inFile, outFile=None):
51
+ if not fileExist(inFile):
52
+ raise fileExceptionNotFound(f"文件不存在: {inFile}")
53
+
54
+ self.inFile = inFile
55
+ self.outFile = inFile if outFile is None else outFile
56
+ self.asrHeaderType = 1
57
+ self.asrTuningType = 2
58
+
59
+ self.fileType = 0
60
+ self.tuningFileLines = list()
61
+ self.tuningFileRemoveInfoLines = list()
62
+ self.headerFileLines = list()
63
+
64
+ self.fileType = self.checkASRFile()
65
+ if self.fileType == 0:
66
+ raise fileExceptionillegal(f"{inFile} 不是ASR文件或文件编码不是UTF-8")
67
+
68
+ self.readFile()
69
+
70
+ def checkASRFile(self):
71
+ try:
72
+ with open(self.inFile, "rt", encoding="utf-8", errors="replace") as f:
73
+ content = f.read()
74
+ if "//ASR" in content:
75
+ return self.asrHeaderType
76
+ elif "@@ASR" in content:
77
+ return self.asrTuningType
78
+ return 0
79
+ except UnicodeDecodeError:
80
+ loge(f"{self.inFile} is not UTF-8 encoded, please convert it to UTF-8 first")
81
+ return 0
82
+ except Exception as e:
83
+ loge(f"Error reading file {self.inFile}: {str(e)}")
84
+ return 0
85
+
86
+ def readFile(self):
87
+ with open(self.inFile, "r") as fileObj:
88
+ if self.fileType == self.asrTuningType:
89
+ self.tuningFileLines = fileObj.readlines()
90
+ elif self.fileType == self.asrHeaderType:
91
+ self.headerFileLines = fileObj.readlines()
92
+ else:
93
+ loge(f"{self.inFile} is not ASR Tuning/Header File")
94
+
95
+ def tuning2Header(self):
96
+ dump = False
97
+ if self.fileType == self.asrTuningType:
98
+ linesTmp = self._removeInfo(self.tuningFileLines, dump)
99
+ linesTmp = self._removeIsolatedBrace(linesTmp, dump)
100
+ linesTmp = self._comentAT(linesTmp, dump)
101
+ linesTmp = self._removeLinesBetweenMarkers(linesTmp, "//CDebugFirmwareFilter", "//", dump)
102
+ linesTmp = self._removeLinesBetweenMarkers(linesTmp, "//CFrameInfoFilter", "//", dump)
103
+ linesTmp = self._commentNullFilter(linesTmp, dump)
104
+ self.headerFileLines = self._dblcBracketsProcess(linesTmp, dump, tuning2cFlag=True)
105
+ logd(f"{self.inFile} tuning2Header done")
106
+ return True
107
+ logw(f"{self.inFile} is not ASR Tuning File")
108
+ return False
109
+
110
+ def header2Tuning(self):
111
+ dump = False
112
+ if self.fileType == self.asrHeaderType:
113
+ linesTmp = self._formatHeader(self.headerFileLines, dump)
114
+ linesTmp = self._replaceSymbol_1(linesTmp, dump)
115
+ self.tuningFileLines = self._dblcBracketsProcess(linesTmp, dump, tuning2cFlag=False)
116
+ logd(f"{self.inFile} header2Tuning done")
117
+ return True
118
+ logw(f"{self.inFile} is not ASR Header File")
119
+ return False
120
+
121
+ def _tuningRemoveReadOnly(self):
122
+ linesAfterRemoveInfo = self._removeInfo(self.tuningFileLines)
123
+ linesAfterRemoveMarker1 = self._removeLinesBetweenMarkers(linesAfterRemoveInfo, "@@CDebugFirmwareFilter", "@@")
124
+ linesAfterRemoveMarker2 = self._removeLinesBetweenMarkers(linesAfterRemoveMarker1, "@@CFrameInfoFilter", "@@")
125
+ self.tuningFileRemoveInfoLines = self._removeIsolatedBrace(linesAfterRemoveMarker2)
126
+ logd(f"{self.inFile} remove info done")
127
+
128
+ def lines2File(self, lines: list, fileName: str):
129
+ with open(fileName, "wt+", encoding="utf-8") as file:
130
+ logd(f"write {fileName}")
131
+ file.writelines(lines)
132
+
133
+ def saveTuningFile(self, out=None, withInfo=True):
134
+ if out is not None:
135
+ self.outFile = out
136
+
137
+ if withInfo:
138
+ self.lines2File(self.tuningFileLines, self.outFile)
139
+ else:
140
+ self.lines2File(self.tuningFileRemoveInfoLines, self.outFile)
141
+
142
+ def saveHeaderFile(self, out=None):
143
+ if out is not None:
144
+ self.outFile = out
145
+ self.lines2File(self.headerFileLines, self.outFile)
146
+
147
+ def _formatHeader(self, linelist, dump=False):
148
+ skip = 0
149
+ delete_space = 0
150
+ sde_setting = 0
151
+ caf_setting = 0
152
+ tmpLines = []
153
+ total_line = len(linelist)
154
+
155
+ SDE_KEYWORD = "CSpecialEffect"
156
+ CAF_KEYWORD = "CAFFilter"
157
+ SDE_PATTERNS = [
158
+ ("m_bManualMode_0", 2, 8),
159
+ ("m_bManualMode_1", 2, 8),
160
+ ("m_bManualMode_2", 2, 8),
161
+ ("m_bManualMode_3", 2, 8),
162
+ ("m_bManualMode_4", 2, 8),
163
+ ("m_bManualMode_5", 2, 8),
164
+ ("m_nLuxLUT", 2, 0),
165
+ ]
166
+ CAF_PATTERNS = [("m_pPDShiftPositionLUT_0_0", 1, 4), ("m_bCAFForce", 1, 0)]
167
+
168
+ for i in range(total_line):
169
+ if skip > 1:
170
+ skip -= 1
171
+ continue
172
+
173
+ current_line = linelist[i]
174
+ start_index = current_line.find("//")
175
+
176
+ if start_index >= 0:
177
+ str_line = current_line[start_index + 2 :]
178
+ tmpLines.append("@@" + str_line)
179
+ sde_setting = 1 if SDE_KEYWORD in str_line else 0
180
+ caf_setting = 1 if CAF_KEYWORD in str_line else 0
181
+ elif i >= (total_line - 2):
182
+ tmpLines.append(current_line)
183
+ else:
184
+ skip = 0
185
+ if sde_setting == 1 and i + 2 < total_line:
186
+ next_line = linelist[i + 2]
187
+ for pattern, skip_count, del_space in SDE_PATTERNS:
188
+ if pattern in next_line:
189
+ skip = skip_count
190
+ delete_space = del_space
191
+ break
192
+
193
+ if caf_setting == 1 and skip == 0 and i + 1 < total_line:
194
+ next_line = linelist[i + 1]
195
+ for pattern, skip_count, del_space in CAF_PATTERNS:
196
+ if pattern in next_line:
197
+ skip = skip_count
198
+ delete_space = del_space
199
+ break
200
+
201
+ if skip == 0:
202
+ if delete_space == 0:
203
+ tmpLines.append(current_line)
204
+ else:
205
+ tmpLines.append(current_line[delete_space:])
206
+ if dump:
207
+ self.lines2File(tmpLines, sys._getframe(0).f_code.co_name + ".data")
208
+ return tmpLines
209
+
210
+ def _removeInfo(self, lines, dump=False):
211
+ delLines = self._getDeleteLines(lines)
212
+ linesAfterDelete = self._deleteLineByNumber(lines, delLines)
213
+ linesAfterDelComma = self._delComma(linesAfterDelete)
214
+ if dump:
215
+ self.lines2File(linesAfterDelComma, sys._getframe(0).f_code.co_name + ".data")
216
+ return linesAfterDelComma
217
+
218
+ def _getDeleteLines(self, lines):
219
+ delLines = []
220
+ keyword = "fw_info"
221
+ keyword1 = "hw_info"
222
+ pattern = re.compile(r"Size: (\d+)x(\d+)")
223
+ count = 0
224
+ for i, line in enumerate(lines):
225
+ if "m_nRevisionNumber" not in line:
226
+ if keyword in line or keyword1 in line:
227
+ rowSize = int(pattern.findall(line)[0][0])
228
+ columnSize = int(pattern.findall(line)[0][1])
229
+ if rowSize == 1 and columnSize == 1:
230
+ for j in range(rowSize + 2):
231
+ delLines.append(i + j + 1)
232
+ elif rowSize == 1 and columnSize != 1:
233
+ count = 1
234
+ else:
235
+ count = rowSize + 1
236
+ if count != 0:
237
+ delLines.append(i + 1)
238
+ if "}" in line:
239
+ count -= 1
240
+ return delLines
241
+
242
+ def _deleteLineByNumber(self, lines, delLines):
243
+ delLines_sorted = sorted(delLines, reverse=True)
244
+ for line_number in delLines_sorted:
245
+ if line_number < len(lines):
246
+ del lines[line_number - 1]
247
+ else:
248
+ logw(f"行号 {line_number} 超出了文件行数")
249
+ return lines
250
+
251
+ def _stringToList(self, file_content):
252
+ lines = re.split(r"(\r\n|\n|\r)", file_content)
253
+ result = []
254
+ i = 0
255
+ while i < len(lines):
256
+ if i + 1 < len(lines) and lines[i + 1] in ["\n", "\r", "\r\n"]:
257
+ result.append(lines[i] + lines[i + 1])
258
+ i += 2
259
+ else:
260
+ if lines[i]:
261
+ result.append(lines[i])
262
+ i += 1
263
+ return result
264
+
265
+ def _delComma(self, lines):
266
+ text = "".join(lines)
267
+ pattern = r",(?=\n\})"
268
+ cleaned_text = re.sub(pattern, "", text, flags=re.DOTALL)
269
+ return self._stringToList(cleaned_text)
270
+
271
+ def _isSdeOrCaf(self, str_line, writeLineNum):
272
+ writeLineNum += 1
273
+ find_name = "CSpecialEffect"
274
+ sde_setting = 1 if str_line.find(find_name) >= 0 else 0
275
+ find_name = "CAFFilter"
276
+ caf_setting = 1 if str_line.find(find_name) >= 0 else 0
277
+ return sde_setting, caf_setting
278
+
279
+ def _checkFileLegal(self, lines, judgeStr: str, judgeStr2: str):
280
+ text = "".join(lines)
281
+ return judgeStr in text or judgeStr2 in text
282
+
283
+ def _removeLinesBetweenMarkers(self, lines, start_marker, end_marker, dump=False):
284
+ tmpLines = []
285
+ skip = False
286
+ for line in lines:
287
+ if start_marker in line:
288
+ skip = True
289
+ elif end_marker in line:
290
+ skip = False
291
+ tmpLines.append(line)
292
+ elif not skip:
293
+ tmpLines.append(line)
294
+ if dump:
295
+ self.lines2File(tmpLines, sys._getframe(0).f_code.co_name + ".data")
296
+ return tmpLines
297
+
298
+ def _commentNullFilter(self, lines, dump=False):
299
+ tmpLines = []
300
+ i = 0
301
+ while i < len(lines):
302
+ current_line = lines[i].strip()
303
+ if current_line == "{" and i + 1 < len(lines) and lines[i + 1].strip() == "},":
304
+ tmpLines.append("//" + lines[i])
305
+ tmpLines.append("//" + lines[i + 1])
306
+ i += 2
307
+ else:
308
+ tmpLines.append(lines[i])
309
+ i += 1
310
+ if dump:
311
+ self.lines2File(tmpLines, sys._getframe(0).f_code.co_name + ".data")
312
+ return tmpLines
313
+
314
+ def replace_first_nth_line_after_string(self, lines, search_string, n, new_content):
315
+ for i, line in enumerate(lines):
316
+ if search_string in line:
317
+ target_line = i + n
318
+ if 0 <= target_line < len(lines):
319
+ logd(f"成功在第 {i + 1} 行找到 '{search_string}',并替换第 {target_line + 1} 行的内容")
320
+ lines[target_line] = new_content + "\n" if not new_content.endswith("\n") else new_content
321
+ return lines
322
+
323
+ def _dblcBracketsProcess(self, lines, dump=False, tuning2cFlag=True):
324
+ if not self._checkFileLegal(lines, "@@CDBLCFirmwareFilter", "//CDBLCFirmwareFilter"):
325
+ logd(f"{self.inFile} 不存在 CDBLCFirmwareFilter")
326
+ return lines
327
+
328
+ if tuning2cFlag:
329
+ lines = self.replace_first_nth_line_after_string(lines, "m_pGridR", 2, " {{\n")
330
+ lines = self.replace_first_nth_line_after_string(lines, "m_pGridB", 51, " }}\n")
331
+ else:
332
+ lines = self.replace_first_nth_line_after_string(lines, "m_pGridR", 2, " {\n")
333
+ lines = self.replace_first_nth_line_after_string(lines, "m_pGridB", 51, " }\n")
334
+ logd("_dblcBracketsProcess done")
335
+ if dump:
336
+ self.lines2File(lines, sys._getframe(0).f_code.co_name + ".data")
337
+ return lines
338
+
339
+ def _comentAT(self, lines, dump=False):
340
+ writeLineNum = 0
341
+ postfix_str = ""
342
+ str_space = ""
343
+ sde_setting = 0
344
+ caf_setting = 0
345
+ linesComentAT = []
346
+
347
+ for line in lines:
348
+ start_index = line.find("@@")
349
+ if start_index >= 0:
350
+ line_str = line[start_index + 2 :]
351
+ linesComentAT.append(postfix_str + "//" + line_str)
352
+ sde_setting, caf_setting = self._isSdeOrCaf(line_str, writeLineNum)
353
+ else:
354
+ if sde_setting == 1:
355
+ if line.find("m_bManualMode_0") >= 0:
356
+ linesComentAT.append(postfix_str + " {\n")
357
+ linesComentAT.append(postfix_str + " {\n")
358
+ writeLineNum += 2
359
+ str_space = " "
360
+ elif (
361
+ line.find("m_bManualMode_1") >= 0
362
+ or line.find("m_bManualMode_2") >= 0
363
+ or line.find("m_bManualMode_3") >= 0
364
+ or line.find("m_bManualMode_4") >= 0
365
+ or line.find("m_bManualMode_5") >= 0
366
+ ):
367
+ linesComentAT.append(postfix_str + " },\n")
368
+ linesComentAT.append(postfix_str + " {\n")
369
+ writeLineNum += 2
370
+ elif line.find("m_nLuxLUT") >= 0:
371
+ linesComentAT.append(postfix_str + " },\n")
372
+ linesComentAT.append(postfix_str + " },\n")
373
+ writeLineNum += 2
374
+ str_space = ""
375
+
376
+ if caf_setting == 1:
377
+ if line.find("m_pPDShiftPositionLUT_0_0") >= 0:
378
+ linesComentAT.append(postfix_str + " {\n")
379
+ writeLineNum += 1
380
+ str_space = " "
381
+ elif line.find("m_bCAFForce") >= 0:
382
+ linesComentAT.append(postfix_str + " },\n")
383
+ writeLineNum += 1
384
+ str_space = ""
385
+
386
+ if line == "\n" or line == "\r\n":
387
+ linesComentAT.append(str_space + line)
388
+ else:
389
+ linesComentAT.append((postfix_str + str_space + line).encode("utf-8").decode("latin1"))
390
+ writeLineNum += 1
391
+ if dump:
392
+ self.lines2File(linesComentAT, sys._getframe(0).f_code.co_name + ".data")
393
+ return linesComentAT
394
+
395
+ def _replaceSymbol_1(self, lines, dump=False):
396
+ i = 0
397
+ while i < len(lines):
398
+ current_line = lines[i].strip()
399
+ if current_line == "@@{":
400
+ lines[i] = "{\n"
401
+ elif current_line == "@@},":
402
+ lines[i] = "},\n"
403
+ i += 1
404
+ if dump:
405
+ self.lines2File(lines, sys._getframe(0).f_code.co_name + ".data")
406
+ return lines
407
+
408
+ def _removeIsolatedBrace(self, lines, dump=False):
409
+ open_brace_stack = []
410
+ lines_to_delete = set()
411
+
412
+ for line_num, line in enumerate(lines):
413
+ stripped_line = line.strip()
414
+ if stripped_line == "{":
415
+ open_brace_stack.append(line_num)
416
+ elif stripped_line == "},":
417
+ if open_brace_stack:
418
+ matching_open_brace_line = open_brace_stack.pop()
419
+ lines_between = lines[matching_open_brace_line + 1 : line_num]
420
+ all_lines_blank = all(l.strip() == "" for l in lines_between)
421
+
422
+ if all_lines_blank:
423
+ lines_to_delete.add(matching_open_brace_line)
424
+ lines_to_delete.add(line_num)
425
+ for i in range(matching_open_brace_line + 1, line_num):
426
+ if lines[i].strip() == "":
427
+ lines_to_delete.add(i)
428
+ else:
429
+ if stripped_line != "":
430
+ open_brace_stack.clear()
431
+
432
+ tmpLines = [line for i, line in enumerate(lines) if i not in lines_to_delete]
433
+ if dump:
434
+ self.lines2File(tmpLines, sys._getframe(0).f_code.co_name + ".data")
435
+ return tmpLines
436
+
437
+
438
+ def getFilePureName(filepath: str) -> Tuple[Path, str, str, str]:
439
+ """使用 pathlib 获取文件信息"""
440
+ path = Path(filepath)
441
+ if not path.is_file():
442
+ raise FileNotFoundError(f"{filepath} 不是一个有效的文件")
443
+
444
+ folder, nameWithSuffix, nameWithoutSuffix, suffix = path.parent, path.name, path.stem, path.suffix
445
+
446
+ return folder, nameWithSuffix, nameWithoutSuffix, suffix
447
+
448
+
449
+ def checkFileNameIsTuning(file):
450
+ if os.path.isfile(file):
451
+ tuningFileFlagList = ["_isp", "_ipe", "_vfe", "_vbe", "_cpp"]
452
+ for i in tuningFileFlagList:
453
+ if i in file:
454
+ return True
455
+ logw(f"{file} not contain any of the following strings : {tuningFileFlagList}")
456
+ return False
457
+
458
+
459
+ def getTuningFileEndStr(replaceStr, file, isTuning2c=True):
460
+ tuningFileFlagList = ["_isp", "_ipe", "_vfe", "_vbe", "_cpp"]
461
+ splitFlag = ""
462
+ if os.path.isfile(file):
463
+ for i in tuningFileFlagList:
464
+ if i in file:
465
+ splitFlag = i
466
+ break
467
+ if splitFlag == "":
468
+ loge(f"{file} not contain any of the following strings : {tuningFileFlagList}")
469
+ return None
470
+ path = os.path.split(file)[0]
471
+ nameWithSuffix = os.path.split(file)[1]
472
+ if isTuning2c:
473
+ targetFileName = nameWithSuffix.split(splitFlag)[-1].split(".")[0] + ".h"
474
+ else:
475
+ targetFileName = nameWithSuffix.split(splitFlag)[-1].split(".")[0] + ".data"
476
+ return os.path.join(path, replaceStr + splitFlag + targetFileName)
477
+ loge(f"{file} isn't a file")
478
+ return None
479
+
480
+
481
+ def _fileProcessTuning2c(inFile, outFile=None):
482
+ if os.path.isfile(inFile):
483
+ if outFile is None:
484
+ folder, _, nameWithoutSuffix, _ = getFilePureName(inFile)
485
+ if nameWithoutSuffix is None:
486
+ return ErrCode.FILE_ILLEGAL
487
+ else:
488
+ outFile = os.path.join(folder, nameWithoutSuffix + ".h")
489
+ try:
490
+ asrTuning = asrTuningFile(inFile)
491
+ if not asrTuning.tuning2Header():
492
+ return ErrCode.FILE_ILLEGAL
493
+ asrTuning.saveHeaderFile(outFile)
494
+ logi(f"process {inFile} to {outFile} done")
495
+ return 0
496
+ except fileExceptionNotFound:
497
+ return ErrCode.FILE_NOT_FOUND
498
+ except fileExceptionillegal:
499
+ return ErrCode.FILE_ILLEGAL
500
+ loge(f"{inFile} isn't a file")
501
+ return ErrCode.FILE_ILLEGAL
502
+
503
+
504
+ def _fileProcessC2Tuning(inFile, outFile=None):
505
+ if os.path.isfile(inFile):
506
+ if outFile is None:
507
+ path, _, nameWithoutSuffix, _ = getFilePureName(inFile)
508
+ outFile = os.path.join(path, nameWithoutSuffix + ".data")
509
+ try:
510
+ asrTuning = asrTuningFile(inFile)
511
+ if not asrTuning.header2Tuning():
512
+ return ErrCode.FILE_ILLEGAL
513
+ asrTuning.saveTuningFile(outFile)
514
+ logi(f"process {inFile} to {outFile} done")
515
+ return 0
516
+ except fileExceptionNotFound:
517
+ return ErrCode.FILE_NOT_FOUND
518
+ except fileExceptionillegal:
519
+ return ErrCode.FILE_ILLEGAL
520
+ loge(f"{inFile} isn't a file")
521
+ return ErrCode.FILE_ILLEGAL
522
+
523
+
524
+ def _fileProcessTuningRemoveInfo(inFile, outFile=None):
525
+ logi(f"remove fw_info from {inFile}")
526
+ if outFile is None:
527
+ outFile = inFile
528
+ try:
529
+ asrTuning = asrTuningFile(inFile, outFile)
530
+ asrTuning._tuningRemoveReadOnly()
531
+ asrTuning.saveTuningFile(outFile, False)
532
+ return 0
533
+ except fileExceptionNotFound:
534
+ return ErrCode.FILE_NOT_FOUND
535
+ except fileExceptionillegal:
536
+ return ErrCode.FILE_ILLEGAL
537
+
538
+
539
+ class asrCamOp(DevOp):
540
+ def __init__(self, checkCam=False, useUi=False, **kwargs):
541
+ logd(f"needroot = {kwargs.get('needRoot', False)}, serial = {kwargs.get('serial', '')}")
542
+ super().__init__(**kwargs)
543
+ if sysVersion == "Linux":
544
+ self.tuning_assistant = "tuning_assistant64.out"
545
+ elif sysVersion == "Windows":
546
+ self.tuning_assistant = "tuning_assistant64.exe"
547
+ self.soc = self.getASRDevice()
548
+ self.lcdOnAndUnlock()
549
+ self.tcpForward()
550
+ if checkCam:
551
+ self.checkCameraOpened()
552
+ self.facing = "rear_primary"
553
+ if useUi:
554
+ try:
555
+ if u2 is None:
556
+ raise RuntimeError("uiautomator2 not installed")
557
+ if self.serial == None:
558
+ exit("no device detected")
559
+ else:
560
+ self.uiDev = u2.connect(self.serial)
561
+ self.lang = self.get_system_language()
562
+ except Exception as e:
563
+ logw(f"Failed to connect UI device: {e}")
564
+ self.resourceId = "com.asrmicro.camera:id/mode_list_item_text"
565
+ self.className = "android.widget.TextView"
566
+
567
+ def get_system_language(self):
568
+ locale = self.uiDev.shell("getprop persist.sys.locale").output.strip()
569
+ if locale.startswith("zh"):
570
+ return "zh"
571
+ if locale.startswith("en"):
572
+ return "en"
573
+ lang = self.uiDev.shell("getprop persist.sys.language").output.strip()
574
+ return lang
575
+
576
+ def uiUsage(self):
577
+ self.uiDev(resourceId=self.resourceId).click()
578
+ self.uiDev(resourceId=self.resourceId, text="Video").click()
579
+ self.uiDev(textContains="Video").click()
580
+ self.uiDev(resourceId=self.resourceId, description="目标元素").click()
581
+ self.uiDev(resourceId=self.resourceId, className="android.widget.TextView").click()
582
+ self.uiDev(resourceId=self.resourceId, instance=2).click()
583
+ self.uiDev(xpath="(//*[@resource-id=self.resourceId])[2]").click()
584
+ self.uiDev(scrollable=True).scroll.to(text="目标元素")
585
+
586
+ def uiClick(self, textList, slp=2, timeOut=2):
587
+ clicked = False
588
+ if self.lang == "zh":
589
+ textList = textList[::-1]
590
+ for t in textList:
591
+ if self.uiDev(text=t).exists(timeout=1):
592
+ self.uiDev(resourceId=self.resourceId, text=t).click(timeOut)
593
+ sleep(slp)
594
+ clicked = True
595
+ break
596
+ if not clicked:
597
+ loge(f"错误:未找到包含 {textList} 的元素")
598
+
599
+ def tuningGetModuleGroup(self):
600
+ rCmd(f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 gm", 1, showCmd=True, showRet=False, logLevel="debug")
601
+
602
+ def tcpForward(self):
603
+ rCmd(
604
+ f'adb -s {self.serial} shell "settings put system screen_off_timeout 7200000"',
605
+ 1,
606
+ showCmd=True,
607
+ logLevel="debug",
608
+ )
609
+ rCmd(
610
+ f"adb -s {self.serial} forward tcp:12218 localabstract:camera_tuning_server",
611
+ 1,
612
+ showCmd=True,
613
+ logLevel="debug",
614
+ )
615
+ self.tuningGetModuleGroup()
616
+
617
+ def tcpRemove(self):
618
+ rCmd(f"adb -s {self.serial} kill-server", 1)
619
+
620
+ def resetNet(self):
621
+ rCmd("netsh interface portproxy delete v4tov4 listenport=12218", showCmd=True)
622
+
623
+ def netCon(self, on=True):
624
+ if on:
625
+ logi("ip connect on")
626
+ if sysVersion == "Linux":
627
+ rCmd(
628
+ "echo AAbbcc123 |sudo -S sysctl -w net.ipv4.conf.enp3s0.route_localnet=1",
629
+ showCmd=True,
630
+ timeOut=30,
631
+ shell=True,
632
+ splitCmd=False,
633
+ )
634
+ rCmd(
635
+ "echo AAbbcc123 |sudo -S iptables -t nat -F PREROUTING ",
636
+ showRet=True,
637
+ showCmd=True,
638
+ shell=True,
639
+ splitCmd=False,
640
+ )
641
+ rCmd(
642
+ "echo AAbbcc123 |sudo -S iptables -t nat -A PREROUTING -p tcp --dport 12218 -j DNAT --to 127.0.0.1:10000 ",
643
+ showRet=True,
644
+ showCmd=True,
645
+ shell=True,
646
+ splitCmd=False,
647
+ )
648
+ rCmd(
649
+ f"adb -s {self.serial} forward tcp:10000 localabstract:camera_tuning_server",
650
+ showRet=False,
651
+ showCmd=True,
652
+ logLevel="info",
653
+ )
654
+ out = rCmd("ifconfig")[0]
655
+ ip = out.split("\n")[1].strip().split(" ")[1]
656
+ logi(f"{ip} : 12218")
657
+ elif sysVersion == "Windows":
658
+ loge("windows unsupport")
659
+ return
660
+ else:
661
+ loge(f"unsupport cmd in {sysVersion}")
662
+ return
663
+ else:
664
+ logi("ip connect off")
665
+ if sysVersion == "Linux":
666
+ rCmd(
667
+ "sudo iptables -t nat -F PREROUTING ",
668
+ showRet=True,
669
+ showCmd=True,
670
+ timeOut=30,
671
+ shell=True,
672
+ splitCmd=False,
673
+ )
674
+ rCmd(f"adb -s {self.serial} forward --remove tcp:10000", showCmd=True, logLevel="info")
675
+ elif sysVersion == "Windows":
676
+ self.resetNet()
677
+ rCmd(f"adb -s {self.serial} forward --remove tcp:10000")
678
+ rCmd("netsh interface portproxy reset", showRet=False)
679
+ else:
680
+ loge(f"unsupport cmd in {sysVersion}")
681
+
682
+ def openCam(self, id=0):
683
+ if id == 0:
684
+ rCmd("adb shell am start -a android.media.action.STILL_IMAGE_CAMERA", 1)
685
+ else:
686
+ rCmd("adb shell am start -a android.media.action.STILL_IMAGE_CAMERA", 2)
687
+ sleep(1)
688
+ self.adbTap((600, 1400))
689
+ sleep(2)
690
+ self.tuningGetModuleGroup()
691
+
692
+ def readIsp(self, CFliter: str, param: str, row=0, col=0, is_float=False, showCmd=False, module=0, group=0):
693
+ if sysVersion == "Linux":
694
+ eExit("tuning_assistant not support linux")
695
+ cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 r m{module}_g{group} {CFliter} {param} {row} {col}"
696
+ try:
697
+ out = rCmd(cmd, sleep_s=0.5, showCmd=showCmd, logLevel="info")[0].strip()
698
+ if row > 0 or col > 0:
699
+ cmdResult = re.split("[ \n,.]+", out)[2]
700
+ else:
701
+ cmdResult = re.split("[ .]+", out)[2]
702
+
703
+ if is_number(cmdResult):
704
+ if is_float:
705
+ value_f = int(cmdResult)
706
+ tmp = ctypes.c_int(value_f)
707
+ result = ctypes.cast(ctypes.pointer(tmp), ctypes.POINTER(ctypes.c_float)).contents.value
708
+ return float(result)
709
+ return float(cmdResult)
710
+ logCallErr(f"{cmd}, please check the command.")
711
+ return 0.0
712
+ # self.tcpRemove()
713
+ # raise Exception("cmd fail")
714
+ except Exception as e:
715
+ logCallErr(str(e))
716
+ return 0.0
717
+
718
+ def writeIsp(self, CFliter: str, param: str, row: int, col: int, value: Union[int, float], showCmd=False):
719
+ if sysVersion == "Linux":
720
+ eExit("tuning_assistant not support linux")
721
+ if isinstance(value, float):
722
+ cf = ctypes.c_float(value)
723
+ value = ctypes.cast(ctypes.pointer(cf), ctypes.POINTER(ctypes.c_int)).contents.value
724
+ cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 w m0_g0 {CFliter} {param} {row} {col} {value}"
725
+ out, _error = rCmd(cmd, sleep_s=0.5, showCmd=showCmd, logLevel="info")
726
+ checkMsg(out, "error")
727
+ logd(f"{out} {_error}")
728
+
729
+ def writeI2c(
730
+ self, devId: int, devAddr: int, regAddr: int, regBit: int, valueBit: int, regValue: int, showCmd=False
731
+ ):
732
+ cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 w i2c {hex(devId)} {hex(devAddr)} {regBit} {hex(regAddr)} {valueBit} {hex(regValue)}"
733
+ _ = rCmd(cmd, 0.5, showCmd)
734
+
735
+ def startVideoPreview(self, facing=0):
736
+ self.keyHome()
737
+ cmd = f"adb -s {self.serial} shell am start -a android.media.action.VIDEO_CAMERA --ei android.intent.extras.CAMERA_FACING {facing}"
738
+ rCmd(cmd, 1)
739
+
740
+ def startPreview(self, facing=0):
741
+ self.keyHome()
742
+ cmd = f"adb -s {self.serial} shell am start -a android.media.action.STILL_IMAGE_CAMERA --ei android.intent.extras.CAMERA_FACING {facing}"
743
+ rCmd(cmd, 1)
744
+
745
+ def isVideoMode(self):
746
+ info, _ = rCmd(f"adb -s {self.serial} shell dumpsys media.camera", 0.5)
747
+ return "VIDEO_RECORD" in info
748
+
749
+ def getCameraFacing(self):
750
+ ret = True
751
+ if self.soc == "dove":
752
+ info, _ = rCmd(f"adb -s {self.serial} shell dumpsys media.camera")
753
+ rc = re.compile(r"Camera ID: (\d+),")
754
+ cameraFacing = rc.findall(info)[0]
755
+ if cameraFacing == "1":
756
+ self.facing = "front"
757
+ elif cameraFacing == "0":
758
+ self.facing = "rear_primary"
759
+ elif cameraFacing == "2":
760
+ self.facing = "rear_secondary"
761
+ elif "failed" in info:
762
+ loge("getCameraFacing failed, device need remount")
763
+ ret = False
764
+ return ret
765
+ elif self.soc in ["lark", "larkl", "larkpro"]:
766
+ cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 20000 gm"
767
+ info = rCmd(cmd, 0.5, True, logLevel="debug")[0].splitlines()[1]
768
+ logd(info)
769
+ if "failed" in info:
770
+ loge("getCameraFacing failed")
771
+ ret = False
772
+ return ret
773
+ if "ISP_Rear_" in info or "ISP_Front_" in info or "ISP_Aux_" in info:
774
+ self.facing = info.split(",")[3].split("ISP_")[1]
775
+ else:
776
+ self.facing = info.split(",")[3].split("ISP_Preview_")[1]
777
+ return ret
778
+
779
+ def pushVrf(self, path, id="rear_primary", renameVrf=False, ignoreTag=None, matchCase=True):
780
+ # id: rear_primary, front, rear_secondary
781
+ out = ""
782
+ if not os.path.exists(path):
783
+ loge(f"{path} not exist")
784
+ return
785
+ rCmd(f"adb -s {self.serial} shell rm vendor/etc/camera/*.vrf", showCmd=True, logLevel="info")
786
+ if self.soc == "dove":
787
+ vrfEndName = "_sensor.vrf"
788
+ out, _ = rCmd(f"adb -s {self.serial} push {path} vendor/etc/camera/{id}{vrfEndName}", showCmd=True, logLevel="info")
789
+ elif self.soc in ["lark", "larkl", "larkpro"]:
790
+ if os.path.isfile(path):
791
+ vrfEndName = "_sensor_0.vrf"
792
+ out, _ = rCmd(f"adb -s {self.serial} push {path} vendor/etc/camera/{id}{vrfEndName}", showCmd=True, logLevel="info")
793
+ elif os.path.isdir(path):
794
+ index = 0
795
+ vrfFiles = findFilesWithSuffix(path, ".vrf")
796
+ if ignoreTag is not None:
797
+ for tag in ignoreTag:
798
+ vrfFiles = removeAnyContainStr(tag, vrfFiles, matchCase)
799
+ vrfFiles.sort(key=lambda x: x.split("_")[0])
800
+ for vrf in vrfFiles:
801
+ target = f"{id}_sensor_{index}.vrf"
802
+ if renameVrf:
803
+ out, _ = rCmd(f"adb -s {self.serial} push {os.path.join(path, vrf)} vendor/etc/camera/{target}", showCmd=True, logLevel="info")
804
+ else:
805
+ out, _ = rCmd(f"adb -s {self.serial} push {os.path.join(path, vrf)} vendor/etc/camera/{vrf}", showCmd=True, logLevel="info")
806
+ index += 1
807
+ if "Read-only" in out:
808
+ eExit("device is Read-only, may need remount")
809
+ rCmd("adb shell am start -a android.media.action.STILL_IMAGE_CAMERA")
810
+ sleep(2)
811
+ self.tuningGetModuleGroup()
812
+
813
+ def pushTuningFile(self, fullName):
814
+ if not os.path.exists(fullName):
815
+ loge(f"{fullName} not exist")
816
+ return
817
+ if "asr_" in fullName:
818
+ targetFile = os.path.split(fullName)[1].split("asr_")[1]
819
+ else:
820
+ targetFile = os.path.split(fullName)[1]
821
+ self.pushFile(fullName, f"vendor/etc/camera/tuning_files/{targetFile}")
822
+
823
+ def saveTuningFile(self, outPath, file, paramlist, delInfo):
824
+ module = "m" + paramlist[0] + "_g" + paramlist[2]
825
+ outFile = os.path.join(outPath, file.lower())
826
+ cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 20000 s {module} {outFile}"
827
+ out, _ = rCmd(cmd, 0.5, False)
828
+ if "failed" in out:
829
+ loge(f"{cmd} error")
830
+ return
831
+ if delInfo:
832
+ _fileProcessTuningRemoveInfo(outFile, outFile)
833
+ logi(f"save {module} {outFile} successful")
834
+
835
+ def saveDoveTuning(self, outPath, paramlist, mode, delInfo=True):
836
+ createFolder(outPath)
837
+ for i in range(len(paramlist)):
838
+ if mode == "video":
839
+ if paramlist[i][1] == "isp":
840
+ file = self.facing + "_isp_setting_video.data"
841
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
842
+ if "preview" in paramlist[i][3] and paramlist[i][1] == "cpp":
843
+ file = self.facing + "_cpp_video_setting.data"
844
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
845
+ elif mode == "preview":
846
+ if paramlist[i][1] == "isp":
847
+ file = self.facing + "_isp_setting.data"
848
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
849
+ continue
850
+ file = ""
851
+ if "preview" in paramlist[i][3] and paramlist[i][1] == "cpp":
852
+ file = self.facing + "_cpp_preview_setting.data"
853
+ if "snapshot" in paramlist[i][3] and paramlist[i][1] == "cpp":
854
+ file = self.facing + "_cpp_snapshot_setting.data"
855
+ if "nightshot" in paramlist[i][3] and paramlist[i][1] == "cpp":
856
+ file = self.facing + "_cpp_nightshot_setting.data"
857
+ if file:
858
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
859
+
860
+ def saveDoveLiteTuning(self, outPath, paramlist, mode, delInfo=True):
861
+ createFolder(outPath)
862
+ for i in range(len(paramlist)):
863
+ file = ""
864
+ if mode == "video":
865
+ if paramlist[i][1] == "vfe":
866
+ file = self.facing + "_vfe_setting.data"
867
+ elif paramlist[i][1] == "vbe":
868
+ file = self.facing + "_vbe_setting.data"
869
+ elif paramlist[i][1] == "cpp" and "preview" in paramlist[i][3]:
870
+ file = self.facing + "_cpp_video.data"
871
+ if file:
872
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
873
+ elif mode == "preview":
874
+ if paramlist[i][1] == "vfe":
875
+ file = self.facing + "_vfe_setting.data"
876
+ elif paramlist[i][1] == "vbe":
877
+ file = self.facing + "_vbe_setting.data"
878
+ elif paramlist[i][1] == "cpp" and "preview" in paramlist[i][3]:
879
+ file = self.facing + "_cpp_preview.data"
880
+ elif paramlist[i][1] == "cpp" and "preview" in paramlist[i][3]:
881
+ file = self.facing + "_cpp_snapshot.data"
882
+ if file:
883
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
884
+
885
+ def saveLarkTuning(self, outPath, paramlist, mode, delInfo=True):
886
+ createFolder(outPath)
887
+ for i in range(len(paramlist)):
888
+ file = ""
889
+ if mode == "video":
890
+ if paramlist[i][1] == "isp":
891
+ file = self.facing + "_isp_video.data"
892
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
893
+ if "ipe_video" in paramlist[i][3].lower() and paramlist[i][1] == "ipe":
894
+ file = self.facing + "_ipe_video.data"
895
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
896
+ if "IPE_Preview" in paramlist[i][3] and paramlist[i][1] == "ipe":
897
+ file = self.facing + "_ipe_video.data"
898
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
899
+ elif mode == "preview":
900
+ if paramlist[i][1] == "isp":
901
+ file = self.facing + "_isp_preview.data"
902
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
903
+ continue
904
+ if paramlist[i][1] == "ipe":
905
+ if "Preview" in paramlist[i][3]:
906
+ file = self.facing + "_ipe_preview.data"
907
+ elif "Capture" in paramlist[i][3]:
908
+ file = self.facing + "_ipe_snapshot.data"
909
+ elif "Portrait" in paramlist[i][3]:
910
+ file = self.facing + "_ipe_portrait.data"
911
+ elif "Night" in paramlist[i][3]:
912
+ file = self.facing + "_ipe_night.data"
913
+ else:
914
+ logw(f"need support {paramlist[i][3]}")
915
+ return
916
+ if file:
917
+ self.saveTuningFile(outPath, file, paramlist[i], delInfo)
918
+
919
+ def saveTuning(self, mode, delInfo=True, outPath="tuning_data"):
920
+ cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 20000 gm"
921
+ info = rCmd(cmd, 0.5, True, logLevel="debug")[0].splitlines()
922
+ for i in info:
923
+ logd(f"{i}")
924
+ paramlist = []
925
+ for i in info:
926
+ if "isp" in i or "ipe" in i or "cpp" in i or "vfe" in i or "vbe" in i:
927
+ paramlist.append(i.replace(" ", "").split(","))
928
+ logd(f"paramlist {paramlist}")
929
+ if self.soc == "dove":
930
+ self.saveDoveTuning(outPath, paramlist, mode, delInfo)
931
+ elif self.soc in ["lark", "larkl", "larkpro"]:
932
+ self.saveLarkTuning(outPath, paramlist, mode, delInfo)
933
+ elif self.soc == "dovelite":
934
+ self.saveDoveLiteTuning(outPath, paramlist, mode, delInfo)
935
+ else:
936
+ eExit(f"unsupport platform {self.soc}")
937
+
938
+ def setRawDump(self, on):
939
+ cmd = f"adb -s {self.serial} shell setprop persist.vendor.camera.enable.capturedump {on}"
940
+ rCmd(cmd, 0.5, checkErr=True)
941
+
942
+ def dumpVrf(self, outPath: str, vrfName: str):
943
+ cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 dr m0_g0 {outPath} 1"
944
+ out, _ = rCmd(cmd, 2)
945
+ keyword1 = "ID="
946
+ keyword2 = "\n"
947
+ match = re.search(f"{keyword1}(.*?){keyword2}", out)
948
+ if match:
949
+ dumpName = "dump_" + str(match.group(1)) + ".vrf"
950
+ fullpath = os.path.join(outPath, dumpName)
951
+ newfile = os.path.join(outPath, str(vrfName))
952
+ from .tao_common import renameFile
953
+
954
+ renameFile(newfile, fullpath)
955
+ else:
956
+ eExit("抓取vrf失败")
957
+
958
+ def capVRF(self, name="null"):
959
+ outPath = self.curPath
960
+ if name == "null":
961
+ logi(f"capture vrf without name to {outPath}")
962
+ else:
963
+ logi(f"capture {name}.vrf to {outPath}")
964
+ if self.androidVersion == "13":
965
+ vrfPath = r"/data/vendor_de/camera/"
966
+ elif self.androidVersion == "14":
967
+ vrfPath = r"/data/vendor/camera/"
968
+ else:
969
+ vrfPath = r"/data/vendor/camera/"
970
+ oldFileList = self.getSuffixList(vrfPath, "jpg", "jpeg", "vrf")
971
+ logd(oldFileList)
972
+ cmd = f"adb -s {self.serial} shell input keyevent 27"
973
+ rCmd(cmd, 0.5, True, logLevel="info")
974
+ sleep(3)
975
+
976
+ foundedVRF = False
977
+ foundedJPG = False
978
+ pulledNameList = []
979
+ max_attempts = 5
980
+ jpgIndex = None
981
+ for _ in range(max_attempts):
982
+ fileList = self.getSuffixList(vrfPath, "jpg", "jpeg", "vrf")
983
+ diffNameList = list(set(fileList) - set(oldFileList))
984
+ logd(diffNameList)
985
+ if diffNameList:
986
+ for file in diffNameList:
987
+ if file.lower().endswith(".jpg") or file.lower().endswith(".jpeg"):
988
+ foundedJPG = True
989
+ if name == "null":
990
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file}"
991
+ else:
992
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file} {name}.jpg"
993
+ if file not in pulledNameList:
994
+ rCmd(cmd, 0.5, True, logLevel="info")
995
+ pulledNameList.append(file)
996
+ try:
997
+ jpgIndex = get_file_index("frameid_", "_", file)
998
+ except Exception:
999
+ jpgIndex = None
1000
+ if file.lower().endswith(".vrf"):
1001
+ if file.startswith("short") or file.startswith("normal") or file.startswith("long"):
1002
+ foundedVRF = True
1003
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file}"
1004
+ if file not in pulledNameList:
1005
+ rCmd(cmd, 0.5, True, logLevel="info")
1006
+ pulledNameList.append(file)
1007
+ elif foundedJPG and jpgIndex is not None and str(jpgIndex) in file and not foundedVRF:
1008
+ foundedVRF = True
1009
+ if name == "null":
1010
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file}"
1011
+ else:
1012
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file} {name}.vrf"
1013
+ if file not in pulledNameList:
1014
+ rCmd(cmd, 0.5, True, checkErr=True, logLevel="info")
1015
+ pulledNameList.append(file)
1016
+ if foundedVRF and foundedJPG:
1017
+ break
1018
+ else:
1019
+ sleep(2.0)
1020
+ if not foundedVRF:
1021
+ loge(f"capture {os.path.join(outPath, name)}.vrf failed, new vrf not found in {vrfPath} ")
1022
+
1023
+ def capVRFLark(self, name="null"):
1024
+ outPath = self.curPath
1025
+ if name == "null":
1026
+ logi(f"capture vrf without name to {outPath}")
1027
+ else:
1028
+ logi(f"capture {name}.vrf to {outPath}")
1029
+ if self.androidVersion == "13":
1030
+ vrfPath = r"/data/vendor_de/camera/"
1031
+ elif self.androidVersion == "14":
1032
+ vrfPath = r"/data/vendor/camera/"
1033
+ else:
1034
+ vrfPath = r"/data/vendor/camera/"
1035
+ oldFileList = self.getSuffixList(vrfPath, "jpg", "jpeg", "vrf")
1036
+ logd(oldFileList)
1037
+ cmd = f"adb -s {self.serial} shell input keyevent 27"
1038
+ rCmd(cmd, 0.5, True, logLevel="info")
1039
+ sleep(3)
1040
+
1041
+ foundedVRF = False
1042
+ foundedJPG = False
1043
+ pulledNameList = []
1044
+ max_attempts = 1
1045
+ totalVRFNum = 0
1046
+ for _ in range(max_attempts):
1047
+ fileList = self.getSuffixList(vrfPath, "jpg", "jpeg", "vrf")
1048
+ diffNameList = list(set(fileList) - set(oldFileList))
1049
+ logd(diffNameList)
1050
+ if diffNameList:
1051
+ for file in diffNameList:
1052
+ if file.lower().endswith(".jpg") or file.lower().endswith(".jpeg"):
1053
+ foundedJPG = True
1054
+ if name == "null":
1055
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file}"
1056
+ else:
1057
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file} {name}.jpg"
1058
+ if file not in pulledNameList:
1059
+ rCmd(cmd, 0.5, True, logLevel="info")
1060
+ pulledNameList.append(file)
1061
+ jpgIndex = get_file_index("frameid_", "_", file)
1062
+ if file.lower().endswith(".vrf"):
1063
+ foundedVRF = True
1064
+ if file not in pulledNameList:
1065
+ totalVRFNum += 1
1066
+ cmd = f"adb -s {self.serial} pull {vrfPath}{file}"
1067
+ rCmd(cmd, 0.5, True, checkErr=True, logLevel="info")
1068
+ pulledNameList.append(file)
1069
+ logi(f"{file} {name}.vrf")
1070
+ if name != "null":
1071
+ shutil.move(file, f"{name}.vrf")
1072
+ if foundedVRF and foundedJPG:
1073
+ break
1074
+ else:
1075
+ sleep(2.0)
1076
+ if not foundedVRF:
1077
+ loge(f"capture {os.path.join(outPath, name)}.vrf failed, new vrf not found in {vrfPath} ")
1078
+
1079
+
1080
+ def CLI_tuningRemoveInfo(argsList):
1081
+ parser = argparse.ArgumentParser(prog="tuningRemoveInfo", description="移除tuning参数fw_info")
1082
+ parser.add_argument("-p", "--path", required=True, help="tuning文件名或路径")
1083
+ args = parser.parse_args(argsList)
1084
+ inFile = args.path
1085
+ if os.path.isfile(inFile):
1086
+ _fileProcessTuningRemoveInfo(inFile)
1087
+ elif os.path.isdir(inFile):
1088
+ for f in os.listdir(inFile):
1089
+ if f.endswith(".data"):
1090
+ raw_name = os.path.join(inFile, f)
1091
+ _fileProcessTuningRemoveInfo(raw_name)
1092
+ else:
1093
+ loge(f"{inFile} is not a valid file or directory")
1094
+
1095
+
1096
+ # def CLI_pushVrf(args):
1097
+ # argsDict = {}
1098
+ # if args:
1099
+ # argsDict = parseArgs(" ".join(args))
1100
+ # idx = argsDict.get("i", "0")
1101
+ # rename = int(argsDict.get("r", 0))
1102
+ # dev = asrCamOp()
1103
+ # if os.path.exists(args[1]):
1104
+ # dev.pushVrf(args[1], idx, rename)
1105
+ # else:
1106
+ # loge(f"cmd error, psvrf name.vrf/path [i=0,1,2]cameraId [r=0,1]renameVrf")
1107
+
1108
+
1109
+ def CLI_pushVrf(argsList):
1110
+ parser = argparse.ArgumentParser(prog="pushvrf", description="push vrf到设备")
1111
+ parser.add_argument("-p", "--path", required=True, help="vrf文件名或路径")
1112
+ parser.add_argument(
1113
+ "-i",
1114
+ "--index",
1115
+ default="rear_primary",
1116
+ choices=["rear_primary", "front", "rear_secondary"],
1117
+ help="push摄像头位置",
1118
+ )
1119
+ parser.add_argument("--no-rename", action="store_false", dest="rename", help="不将文件按filecam重命名")
1120
+ parser.set_defaults(rename=True)
1121
+ parser.add_argument(
1122
+ "-t", "--tag", required=False, nargs="+", help="如果vrf包含tag(支持多tag), push时忽略包含tag列表中的文件"
1123
+ )
1124
+ parser.add_argument("--matchcase", action="store_true", dest="matchcase", help="是否区分tag大小写")
1125
+ parser.set_defaults(matchcase=False)
1126
+ args = parser.parse_args(argsList)
1127
+
1128
+ logi(
1129
+ f"psvrf {args.path} indxe={args.index}, rename={args.rename}, ignoreTag={args.tag}, matchcase={args.matchcase}"
1130
+ )
1131
+
1132
+ dev = asrCamOp()
1133
+ if os.path.exists(args.path):
1134
+ dev.pushVrf(args.path, args.index, args.rename, args.tag, args.matchcase)
1135
+ else:
1136
+ loge(f"cmd error, psvrf name.vrf/path [i=0,1,2]cameraId [r=0,1]renameVrf")
1137
+
1138
+
1139
+ def CLI_capVrf(argsList):
1140
+ parser = argparse.ArgumentParser(prog="capvrf", description="抓取vrf")
1141
+ parser.add_argument("-f", "--file", type=str, required=False, help="抓取vrf 文件名")
1142
+ args = parser.parse_args(argsList)
1143
+ asrCam = asrCamOp(True)
1144
+ asrCam.setRawDump(1)
1145
+ if args.file == None:
1146
+ if asrCam.soc in ["lark", "larkl", "larkpro"]:
1147
+ asrCam.capVRFLark()
1148
+ else:
1149
+ asrCam.capVRF()
1150
+ else:
1151
+ name = args.file
1152
+ if asrCam.soc in ["lark", "larkl", "larkpro"]:
1153
+ asrCam.capVRFLark(name)
1154
+ else:
1155
+ asrCam.capVRF(name)
1156
+ asrCam.setRawDump(0)
1157
+
1158
+
1159
+ def CLI_saveTuning(argsList):
1160
+ if sysVersion == "Linux":
1161
+ loge("Linux not support save tuning!")
1162
+ return
1163
+ parser = argparse.ArgumentParser(prog="savetuning", description="保存tuning参数")
1164
+ parser.add_argument("-a", "--all", type=str, default="1", choices=["0", "1"], help="是否保存包含RO的参数")
1165
+ parser.add_argument("-p", "--path", type=str, default="tuning_data", help="保存文件夹名")
1166
+ args = parser.parse_args(argsList)
1167
+
1168
+ path = args.path
1169
+ previewIcon = ["Photo", "拍照"]
1170
+ videoIcon = ["Video", "视频"]
1171
+ asrCam = asrCamOp(True, True)
1172
+ if asrCam.isVideoMode():
1173
+ logi("current is video mode, switch to preview!")
1174
+ asrCam.uiClick(previewIcon)
1175
+ if not asrCam.getCameraFacing():
1176
+ eExit("get camera ID failed")
1177
+ if asrCam.soc in ["lark", "larkl", "larkpro"]:
1178
+ try:
1179
+ otpEn = asrCam.readIsp("CDigitalGainFirmwareFilter", "m_bWhiteBalanceOTPEnable")
1180
+ except Exception as exc:
1181
+ loge(str(exc))
1182
+ otpEn = 0
1183
+ else:
1184
+ otpEn = 0
1185
+ logh(f"otpEn {otpEn}")
1186
+ if args.all == "1" or otpEn == 1:
1187
+ logi(f"save tuning with debug information {asrCam.serial}")
1188
+ asrCam.saveTuning("preview", False, path)
1189
+ asrCam.uiClick(videoIcon)
1190
+ asrCam.saveTuning("video", False, path)
1191
+ asrCam.uiClick(previewIcon)
1192
+ else:
1193
+ logi(f"save tuning without debug information {asrCam.serial}")
1194
+ asrCam.saveTuning("preview", True, path)
1195
+ asrCam.uiClick(videoIcon)
1196
+ asrCam.saveTuning("video", True, path)
1197
+ asrCam.uiClick(previewIcon)
1198
+
1199
+
1200
+ def CLI_pushTuning(argsList):
1201
+ parser = argparse.ArgumentParser(prog="pushtuning", description="push tuning参数")
1202
+ parser.add_argument("-p", "--path", required=True, help="push tuning文件名或路径")
1203
+ args = parser.parse_args(argsList)
1204
+ inFile = args.path
1205
+ asrCam = asrCamOp()
1206
+ if os.path.isfile(inFile):
1207
+ asrCam.pushTuningFile(inFile)
1208
+ elif os.path.isdir(inFile):
1209
+ for f in os.listdir(inFile):
1210
+ if f.endswith(".data"):
1211
+ raw_name = os.path.join(inFile, f)
1212
+ asrCam.pushTuningFile(raw_name)
1213
+ else:
1214
+ loge(f"{inFile} is not a valid file or directory")
1215
+
1216
+
1217
+ def CLI_tuning2c(argsList):
1218
+ parser = argparse.ArgumentParser(prog="tuning2c", description="tuning参数转 .h文件")
1219
+ parser.add_argument("-p", "--path", required=True, help="tuning文件名或路径")
1220
+ parser.add_argument("-s", "--prefix", required=False, help="转为头文件替换的前缀")
1221
+ args = parser.parse_args(argsList)
1222
+
1223
+ sensorName = args.prefix
1224
+ inFile = args.path
1225
+ if os.path.isfile(inFile):
1226
+ if sensorName == "":
1227
+ _fileProcessTuning2c(inFile)
1228
+ else:
1229
+ if checkFileNameIsTuning(inFile):
1230
+ outFile = getTuningFileEndStr(sensorName, inFile)
1231
+ _fileProcessTuning2c(inFile, outFile)
1232
+ elif os.path.isdir(inFile):
1233
+ for f in os.listdir(inFile):
1234
+ if f.endswith(".data"):
1235
+ raw_name = os.path.join(inFile, f)
1236
+ if sensorName == "":
1237
+ _fileProcessTuning2c(raw_name)
1238
+ else:
1239
+ if checkFileNameIsTuning(raw_name):
1240
+ outFile = getTuningFileEndStr(sensorName, raw_name)
1241
+ _fileProcessTuning2c(raw_name, outFile)
1242
+ else:
1243
+ loge(f"{inFile} is not a valid file or directory")
1244
+
1245
+
1246
+ def CLI_c2tuning(argsList):
1247
+ parser = argparse.ArgumentParser(prog="c2tuning", description="将 .h文件转为 tuning文件")
1248
+ parser.add_argument("-p", "--path", required=True, help="tuning文件名或路径")
1249
+ parser.add_argument("-s", "--prefix", required=False, help="转为头文件替换的前缀")
1250
+ args = parser.parse_args(argsList)
1251
+
1252
+ sensorName = args.prefix
1253
+ inFile = args.path
1254
+ splitFlag = "asr_"
1255
+ if os.path.isfile(inFile):
1256
+ if sensorName == None:
1257
+ _fileProcessC2Tuning(inFile)
1258
+ else:
1259
+ if splitFlag not in inFile:
1260
+ loge(f"{inFile} not contain {splitFlag} flag")
1261
+ return
1262
+ if checkFileNameIsTuning(inFile):
1263
+ outFile = getTuningFileEndStr(sensorName, inFile, False)
1264
+ _fileProcessC2Tuning(inFile, outFile)
1265
+ elif os.path.isdir(inFile):
1266
+ for f in os.listdir(inFile):
1267
+ if f.endswith(".h"):
1268
+ raw_name = os.path.join(inFile, f)
1269
+ if sensorName == None:
1270
+ _fileProcessC2Tuning(raw_name)
1271
+ else:
1272
+ if splitFlag not in raw_name:
1273
+ loge(f"{raw_name} not contain {splitFlag} flag, skip")
1274
+ continue
1275
+ if checkFileNameIsTuning(raw_name):
1276
+ outFile = getTuningFileEndStr(sensorName, raw_name, False)
1277
+ _fileProcessC2Tuning(raw_name, outFile)
1278
+ else:
1279
+ loge(f"{inFile} is not a valid file or directory")
1280
+
1281
+
1282
+ def CLI_netCon(args):
1283
+ dev = asrCamOp(True)
1284
+ if len(args) == 0:
1285
+ dev.netCon(True)
1286
+ else:
1287
+ dev.netCon(False)
1288
+
1289
+
1290
+ def CLI_osd(_args):
1291
+ dev = DevOp()
1292
+ osdAppPath = os.path.join(sys.path[0], "osd_usage", "osdApp.apk")
1293
+ dev.adbCmd(f"install {osdAppPath}", False)
1294
+ dev.adbCmd("setenforce 0")
1295
+ dev.adbCmd("setprop persist.vendor.camera.osd.dump 1")
1296
+ dev.adbCmd("touch /data/local/tmp/isp.txt")
1297
+
1298
+
1299
+ _COMMAND_REGISTRY = {}
1300
+
1301
+
1302
+ def printHelp():
1303
+ print("[tuning]")
1304
+ print("psvrf -h :push vrf to vendor/etc/camera for filecam")
1305
+ print("capvrf -h :capture vrf in current path")
1306
+ print("savetuning -h :save current tuning data")
1307
+ print("pushtuning -h :push tuning data to vendor/etc/camera/tuning_files")
1308
+ print("tuning2c -h :convert tuning data to c header")
1309
+ print("c2tuning -h :convert c header to tuning data")
1310
+ print("tuningr -h :remove readonly info")
1311
+ print("ipc {off} :connect camera with ip address")
1312
+ print("osd :install osd app")
1313
+
1314
+
1315
+ CLI_pushVrf = register_command("psvrf", registry=_COMMAND_REGISTRY)(CLI_pushVrf)
1316
+ CLI_capVrf = register_command("capvrf", registry=_COMMAND_REGISTRY)(CLI_capVrf)
1317
+ CLI_saveTuning = register_command("savetuning", registry=_COMMAND_REGISTRY)(CLI_saveTuning)
1318
+ CLI_pushTuning = register_command("pushtuning", registry=_COMMAND_REGISTRY)(CLI_pushTuning)
1319
+ CLI_tuning2c = register_command("tuning2c", registry=_COMMAND_REGISTRY)(CLI_tuning2c)
1320
+ CLI_c2tuning = register_command("c2tuning", registry=_COMMAND_REGISTRY)(CLI_c2tuning)
1321
+ CLI_tuningRemoveInfo = register_command("tuningr", registry=_COMMAND_REGISTRY)(CLI_tuningRemoveInfo)
1322
+ CLI_netCon = register_command("ipc", registry=_COMMAND_REGISTRY)(CLI_netCon)
1323
+ CLI_osd = register_command("osd", registry=_COMMAND_REGISTRY)(CLI_osd)
1324
+
1325
+
1326
+ def tuningMain(args):
1327
+ debugCtrl(1) if "debug" in args else debugCtrl(0)
1328
+ args.remove("debug") if "debug" in args else args
1329
+ args = normalize_args(args)
1330
+ if len(args) < 1 or args[0] in {"help", "-h", "--help"}:
1331
+ printHelp()
1332
+ return
1333
+ cmd = args[0]
1334
+ handler = _COMMAND_REGISTRY.get(cmd)
1335
+ if handler is None:
1336
+ loge(f"unsupport command {cmd}")
1337
+ return
1338
+ handler(args[1:])
1339
+
1340
+
1341
+ if __name__ == "__main__":
1342
+ debugCtrl(1) if "debug" in sys.argv else debugCtrl(0)
1343
+ sys.argv.remove("debug") if "debug" in sys.argv else sys.argv
1344
+ tuningMain(sys.argv)