Skip to content

Commit 9aa2aab

Browse files
daichengheyiweisong
andcommitted
Develop (#80)
* delete device_info version * add 8100Bx upgrade worker * upgrade sdk_Bx * add option to select config file * cli app add para_path option * fix 5.8.16 BA upgrade issue * add test case to test ans-devices * Update rtk_provider_base.py Co-authored-by: yiweisong <[email protected]>
1 parent 8d2a9cd commit 9aa2aab

File tree

13 files changed

+1085
-9
lines changed

13 files changed

+1085
-9
lines changed

src/aceinna/bootstrap/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class CommandLine:
3535
def __init__(self, **kwargs):
3636
self._build_options(**kwargs)
3737
APP_CONTEXT.mode = APP_TYPE.CLI
38-
38+
APP_CONTEXT.para_path = kwargs['para_path']
3939
# self.communication = 'uart'
4040
# self.device_provider = None
4141
# self.communicator = None

src/aceinna/bootstrap/default.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ class Default:
2828
def __init__(self, **kwargs):
2929
self._build_options(**kwargs)
3030
APP_CONTEXT.mode = APP_TYPE.DEFAULT
31-
31+
APP_CONTEXT.para_path = kwargs['para_path']
32+
3233
def listen(self):
3334
'''
3435
Prepare components, initialize the application

src/aceinna/devices/base/rtk_provider_base.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,12 @@ def load_properties(self):
204204
return
205205

206206
# Load the openimu.json based on its app
207-
app_file_path = os.path.join(
208-
self.setting_folder_path, product_name, app_name, self.config_file_name)
209-
207+
if APP_CONTEXT.para_path == None:
208+
app_file_path = os.path.join(
209+
self.setting_folder_path, product_name, app_name, self.config_file_name)
210+
else:
211+
app_file_path = os.path.join(
212+
self.setting_folder_path, product_name, app_name, APP_CONTEXT.para_path)
210213
if not self.is_app_matched:
211214
print_yellow(
212215
'Failed to extract app version information from unit.' +

src/aceinna/devices/upgrade_workers/sdk_8100Bx_worker.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,9 @@ def send_sync(self):
755755

756756
sync = [0xfd, 0xc6, 0x49, 0x28]
757757
self._uart.write(sync)
758+
self._uart.write(sync)
759+
self._uart.write(sync)
760+
self._uart.write(sync)
758761
time.sleep(0.2)
759762

760763
return self.read_until([0x3A, 0x54, 0x2C, 0xA6], 100)
@@ -996,9 +999,6 @@ def work(self):
996999
fs_len = len(self._file_content)
9971000
bin_info_list = self.get_bin_info_list(fs_len, self._file_content)
9981001

999-
# if not self.connect_serail_port():
1000-
# return self._raise_error('Connect serial Port failed')
1001-
10021002
if not self.send_sync():
10031003
return self._raise_error('Sync failed')
10041004

src/aceinna/framework/context.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,12 @@ def mode(self):
6969
def mode(self, value):
7070
self._mode = value
7171

72+
@property
73+
def para_path(self):
74+
return self._para_path
75+
76+
@para_path.setter
77+
def para_path(self, value):
78+
self._para_path = value
7279

7380
APP_CONTEXT = AppContext()

src/aceinna/framework/decorator.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def _build_args():
4343
help="Contains internal data log (OpenIMU only)", default=False)
4444
parser.add_argument("-s", "--set-user-para", dest='set_user_para', action='store_true',
4545
help="Set user parameters (OpenRTK only)", default=False)
46+
parser.add_argument("--para-path", dest="para_path", type=str,
47+
metavar='')
4648
parser.add_argument("--cli", dest='use_cli', action='store_true',
4749
help="start as cli mode", default=False)
4850

src/aceinna/models/args.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ class WebserverArgs(KeyValuesArgumentBase):
4040
'console_log': False,
4141
'set_user_para': False,
4242
'ntrip_client': False,
43-
'force_bootloader': False
43+
'force_bootloader': False,
44+
'para_path': None
4445
}
4546

4647

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
class StringStream:
2+
"""A simple class to hold text so that when passed
3+
between functions, the object is passed by reference
4+
and memory does not need to be repeatedly allocated for the string.
5+
6+
This class was written here to avoid adding a dependency
7+
to the project.
8+
"""
9+
10+
def __init__(self, raw_text, debug=False):
11+
self.raw_text = raw_text
12+
self.index = 0
13+
self.len = len(raw_text)
14+
15+
def read(self, count):
16+
"""Read count characters starting at self.index,
17+
and return those characters as a string
18+
"""
19+
new_index = self.index + count
20+
if new_index > self.len:
21+
buf = self.raw_text[self.index :] # return to the end, don't fail
22+
else:
23+
buf = self.raw_text[self.index : new_index]
24+
self.index = new_index
25+
26+
return buf
27+
28+
def seek(self, offset):
29+
"""Advance the index of this StringStream by offset characters"""
30+
self.index = self.index + offset
31+
32+
def advance_past_chars(self, chars):
33+
"""Advance the index past specific chars
34+
Args chars (list): list of characters to advance past
35+
36+
Return substring that was advanced past
37+
"""
38+
start_index = self.index
39+
while True:
40+
current_char = self.raw_text[self.index]
41+
self.index += 1
42+
if current_char in chars:
43+
break
44+
45+
elif self.index == self.len:
46+
break
47+
48+
return self.raw_text[start_index : self.index - 1]
49+
50+
def advance_past_string_with_gdb_escapes(self, chars_to_remove_gdb_escape=None):
51+
"""characters that gdb escapes that should not be
52+
escaped by this parser
53+
"""
54+
55+
if chars_to_remove_gdb_escape is None:
56+
chars_to_remove_gdb_escape = ['"']
57+
58+
buf = ""
59+
while True:
60+
c = self.raw_text[self.index]
61+
self.index += 1
62+
63+
if c == "\\":
64+
# We are on a backslash and there is another character after the backslash
65+
# to parse. Handle this case specially since gdb escaped it for us
66+
67+
# Get the next char that is being escaped
68+
c2 = self.raw_text[self.index]
69+
self.index += 1
70+
# only store the escaped character in the buffer; don't store the backslash
71+
# (don't leave it escaped)
72+
buf += c2
73+
74+
elif c == '"':
75+
# Quote is closed. Exit (and don't include the end quote).
76+
break
77+
78+
else:
79+
# capture this character, and keep capturing
80+
buf += c
81+
return buf
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import os
2+
3+
DEFAULT_PROCESS_TIMEOUT_SEC = 1
4+
DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC = 0.2
5+
USING_WINDOWS = os.name == "nt"
6+
7+
8+
class ProcessTimeoutError(ValueError):
9+
"""Raised when no response is recieved from python driver after the timeout has been triggered"""
10+
11+
pass
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
"""This module defines the `ProcessController` class
2+
which runs app as a subprocess and can write to it and read from it to get
3+
structured output.
4+
"""
5+
6+
import logging
7+
import subprocess
8+
from distutils.spawn import find_executable
9+
from typing import Union, List, Optional
10+
from io_manager import IoManager
11+
from constants import (
12+
DEFAULT_PROCESS_TIMEOUT_SEC,
13+
DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC,
14+
)
15+
import time
16+
import process_parser
17+
import sys
18+
19+
DEFAULT_PROCESS_LAUNCH_COMMAND = ["./ans-devices.exe", "--cli"]
20+
logger = logging.getLogger(__name__)
21+
22+
23+
class ProcessController:
24+
def __init__(
25+
self,
26+
command,
27+
time_to_check_for_additional_output_sec=DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC,
28+
):
29+
"""
30+
Run a subprocess. Send commands and receive structured output.
31+
Create new object, along with subprocess
32+
33+
Args:
34+
command: Command to run in shell to spawn new subprocess
35+
time_to_check_for_additional_output_sec: When parsing responses, wait this amout of time before exiting (exits before timeout is reached to save time). If <= 0, full timeout time is used.
36+
Returns:
37+
New ProcessController object
38+
"""
39+
40+
if command is None:
41+
command = DEFAULT_PROCESS_LAUNCH_COMMAND
42+
43+
# if not any([("--interpreter=mi" in c) for c in command]):
44+
# logger.warning(
45+
# "warning. "
46+
# )
47+
self.abs_app_path = None # abs path to executable
48+
self.command = command # type: List[str]
49+
self.time_to_check_for_additional_output_sec = (
50+
time_to_check_for_additional_output_sec
51+
)
52+
self.app_process = None
53+
self._allow_overwrite_timeout_times = (
54+
self.time_to_check_for_additional_output_sec > 0
55+
)
56+
app_path = command.split(' ')[0]
57+
58+
if not app_path:
59+
raise ValueError("a valid path to app must be specified")
60+
61+
else:
62+
abs_app_path = find_executable(app_path)
63+
if abs_app_path is None:
64+
raise ValueError(
65+
'executable could not be resolved from "%s"' % app_path
66+
)
67+
68+
else:
69+
self.abs_app_path = abs_app_path
70+
self.spawn_new_subprocess()
71+
72+
def spawn_new_subprocess(self):
73+
"""Spawn a new subprocess with the arguments supplied to the object
74+
during initialization. If subprocess already exists, terminate it before
75+
spanwing a new one.
76+
Return int: process id
77+
"""
78+
if self.app_process:
79+
logger.debug(
80+
"Killing current subprocess (pid %d)" % self.app_process.pid
81+
)
82+
self.exit()
83+
84+
logger.debug(f'Launching app: {" ".join(self.command)}')
85+
# print('xxxxxxxxxxxxxxxxxxxxx', self.command)
86+
# Use pipes to the standard streams
87+
self.app_process = subprocess.Popen(
88+
self.command,
89+
shell=False,
90+
stdout=subprocess.PIPE,
91+
stdin=subprocess.PIPE,
92+
stderr=subprocess.PIPE,
93+
bufsize=0,
94+
)
95+
96+
self.io_manager = IoManager(
97+
self.app_process.stdin,
98+
self.app_process.stdout,
99+
self.app_process.stderr,
100+
self.time_to_check_for_additional_output_sec,
101+
)
102+
return self.app_process.pid
103+
104+
def get_process_response(
105+
self, timeout_sec: float = DEFAULT_PROCESS_TIMEOUT_SEC, raise_error_on_timeout=True
106+
):
107+
"""Get process response. See IoManager.get_process_response() for details"""
108+
return self.io_manager.get_process_response(timeout_sec, raise_error_on_timeout)
109+
110+
def write(
111+
self,
112+
mi_cmd_to_write: Union[str, List[str]],
113+
timeout_sec=DEFAULT_PROCESS_TIMEOUT_SEC,
114+
raise_error_on_timeout: bool = True,
115+
read_response: bool = True,
116+
):
117+
print('cmd: ', mi_cmd_to_write)
118+
"""Write command to process. See IoManager.write() for details"""
119+
return self.io_manager.write(
120+
mi_cmd_to_write, timeout_sec, raise_error_on_timeout, read_response
121+
)
122+
123+
def exit(self) -> None:
124+
"""Terminate process"""
125+
if self.app_process:
126+
self.app_process.terminate()
127+
self.app_process.communicate()
128+
self.app_process = None
129+
return None
130+
131+
if __name__ == '__main__':
132+
if len(sys.argv) < 2:
133+
print('input upgrade file')
134+
exit(-1)
135+
upgrade_file = sys.argv[1]
136+
fs_log = open('./log.txt', 'w')
137+
driver_cmd = './ans-devices.exe --cli'
138+
app_handle = ProcessController(driver_cmd)
139+
suc_count = 0
140+
fail_count = 0
141+
data = ''
142+
process_ret = ''
143+
while True:
144+
while True:
145+
try:
146+
response = app_handle.get_process_response()
147+
try:
148+
process_ret += process_parser.get_gdb_response_str(response)
149+
except Exception as e:
150+
print(e)
151+
if 'Connected' in process_ret:
152+
print('python drivder connected...')
153+
fs_log.write(process_ret)
154+
process_ret = ''
155+
break
156+
except Exception as e:
157+
time.sleep(1)
158+
print('wait to connect')
159+
time.sleep(2)
160+
while True:
161+
response = app_handle.write('upgrade {0}'.format(upgrade_file), 1, read_response = False)
162+
time_used = 0
163+
while True:
164+
165+
try:
166+
response = app_handle.get_process_response()
167+
try:
168+
process_ret += process_parser.get_gdb_response_str(response)
169+
except Exception as e:
170+
print(e)
171+
if 'RTK_INS App' in process_ret:
172+
print('upgrade suc...')
173+
suc_count+= 1
174+
break
175+
elif 'failed' in process_ret:
176+
print('upgrade fail...')
177+
fail_count+= 1
178+
break
179+
except Exception as e:
180+
time.sleep(1)
181+
time_used+= 2
182+
print("\rtime used: %ds" %(time_used), end="")
183+
if time_used > 600:
184+
print('time out')
185+
time_used = 0
186+
fail_count+= 1
187+
break
188+
189+
print('suc_count = {0}, fail_count = {1}'.format(suc_count, fail_count))
190+
fs_log.write(process_ret)
191+
time.sleep(5)
192+
process_ret = ''

0 commit comments

Comments
 (0)