blob: f498a5bb0b5bcd10b74891650737e57a8cc60b3c [file] [log] [blame]
Yu-Hsuan Hsudb96ced2020-03-03 17:35:01 +08001#!/usr/bin/env python3
En-Shuo Hsua6814512020-01-16 16:47:39 +08002# -*- coding: utf-8 -*-
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +08003# Copyright 2015 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +08006"""A simple utility to connect to Chameleond in an interactive shell."""
7
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +08008import atexit
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +08009import argparse
10import code
En-Shuo Hsua6814512020-01-16 16:47:39 +080011import logging # pylint: disable=cros-logging-import
Cheng-Yi Chiangab747d82016-11-22 15:39:12 +080012import os
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080013import readline
14import rlcompleter
Cheng-Yi Chiangab747d82016-11-22 15:39:12 +080015import subprocess
Cheng-Yi Chiang852e13e2017-04-17 19:02:22 +080016import time
Yu-Hsuan Hsudb96ced2020-03-03 17:35:01 +080017import xmlrpc.client
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080018
Moja Hsu7ef568c2016-12-27 15:58:58 +080019from audio.audio_value_detector import AudioValueDetector
20
En-Shuo Hsua6814512020-01-16 16:47:39 +080021TUNNEL_NAME = 'to_chameleon_tunnel'
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +080022
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080023
24def ShowMessages(proxy):
25 """Shows the messages for usage.
26
27 Args:
28 proxy: The xmlrpclib.ServerProxy to chameleond.
29 """
30 logging.info('In interactive shell, p is the proxy to chameleond server')
31 supported_ports = proxy.GetSupportedPorts()
32 linein_port = None
33 hdmi_port = None
34 port_messages = []
35 for port in supported_ports:
36 port_type = proxy.GetConnectorType(port)
37 if port_type == 'LineIn':
38 linein_port = port
39 if port_type == 'HDMI':
40 hdmi_port = port
41 port_messages.append('Port %d is %s.' % (port, port_type))
En-Shuo Hsua6814512020-01-16 16:47:39 +080042 message = """
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080043 %s
En-Shuo Hsua6814512020-01-16 16:47:39 +080044 E.g.""" % '\n '.join(port_messages)
Moja Hsu28e1aab2017-03-30 15:24:35 +080045 if linein_port:
En-Shuo Hsua6814512020-01-16 16:47:39 +080046 message += """
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080047 p.StartCapturingAudio(%d) to capture from LineIn.
En-Shuo Hsua6814512020-01-16 16:47:39 +080048 p.StopCapturingAudio(%d) to stop capturing from LineIn.""" % (linein_port,
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +080049 linein_port)
Moja Hsu28e1aab2017-03-30 15:24:35 +080050
51 if hdmi_port:
En-Shuo Hsua6814512020-01-16 16:47:39 +080052 message += """
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080053 p.Plug(%d) to plug HDMI.
En-Shuo Hsua6814512020-01-16 16:47:39 +080054 p.Unplug(%d) to unplug HDMI.""" % (hdmi_port, hdmi_port)
Moja Hsu28e1aab2017-03-30 15:24:35 +080055
56 logging.info(message)
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080057
58
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +080059def DetectAudioValue0(channels=None,
60 margin=0.01,
61 continuous_samples=5,
62 duration=3600,
63 dump_samples=48000):
Moja Hsu7ef568c2016-12-27 15:58:58 +080064 """Detects if Chameleon captures continuous audio data close to 0.
65
66 This function will get the audio streaming data from stream server and will
67 check if the audio data is close to 0 by the margin parameter.
68 -margin < value < margin will be considered to be close to 0.
69 If there are continuous audio samples close to 0 in the streamed data,
70 test_server will log it and save the audio data to a wav file.
71
72 E.g.
73 >>> ConnectCrosToLineIn()
74 >>> p.StartCapturingAudio(6, False)
75 >>> DetectAudioValue0(duration=24*3600, margin=0.001)
76
77 Args:
78 channels: Array of audio channels we want to check.
79 E.g. [0, 1] means we only care about channel 0 and channel 1.
80 margin: Used to decide if the value is closed to 0. Maximum value is 1.
81 continuous_samples: When continuous_samples samples are closed to 0, trigger
82 event.
83 duration: The duration of monitoring in seconds.
84 dump_samples: When event happens, how many audio samples we want to
85 save to file.
86 """
87 if not channels:
88 channels = [0, 1]
89 detecter = AudioValueDetector(options.host) # pylint: disable=undefined-variable
90 detecter.Detect(channels, margin, continuous_samples, duration, dump_samples)
91 return True
92
93
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +080094def StartInteractiveShell(p): # pylint: disable=unused-argument
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +080095 """Starts an interactive shell.
96
97 Args:
98 p: The xmlrpclib.ServerProxy to chameleond.
99 """
Moja Hsu7ef568c2016-12-27 15:58:58 +0800100 vars = globals() # pylint: disable=redefined-builtin
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +0800101 vars.update(locals())
102 readline.set_completer(rlcompleter.Completer(vars).complete)
En-Shuo Hsua6814512020-01-16 16:47:39 +0800103 readline.parse_and_bind('tab: complete')
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +0800104 shell = code.InteractiveConsole(vars)
105 shell.interact()
106
107
108def ParseArgs():
109 """Parses the arguments.
110
Moja Hsu7ef568c2016-12-27 15:58:58 +0800111 Returns:
112 the namespace containing parsed arguments.
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +0800113 """
114 parser = argparse.ArgumentParser(
115 description='Connect to Chameleond and use interactive shell.',
116 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800117 parser.add_argument(
118 '--chameleon_host',
119 type=str,
120 dest='host',
121 required=True,
122 help='host address of Chameleond')
123 parser.add_argument(
124 '--port',
125 type=int,
126 dest='port',
127 default=9992,
128 help='port number of Chameleond')
129 parser.add_argument(
130 '--remote',
131 action='store_true',
132 help='Connect remotely. '
133 'Adding the flag will establish ssh tunnel automatically for you.')
134 parser.add_argument(
135 '--local_port',
136 type=int,
137 default=12346,
138 help='port number of localhost. This will only be used '
139 'if you enable --remote.')
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +0800140 return parser.parse_args()
141
142
Cheng-Yi Chiangab747d82016-11-22 15:39:12 +0800143def GetAndConvertRecordedFile(remote_path):
144 """Gets recorded file and converts it into a wav file.
145
146 A helper function to get recorded file from Chameleon host and do
147 file format conversion from 32 bit, 48000 rate, 8 channel raw file
148 to 2 channel wav file.
149
150 E.g.
151 >>> p.StartCapturingAudio(6)
152 >>> s = p.StopCapturingAudio(6)
153 >>> GetAndConvertRecordedFile(s[0])
154
155 The recorded raw file and converted wav file will be in current
156 directory.
157
158 Args:
159 remote_path: The file to copy from Chameleon host.
Cheng-Yi Chiangab747d82016-11-22 15:39:12 +0800160 """
161 basename = os.path.basename(remote_path)
162 # options is already in the namespace.
163 subprocess.check_call(
Moja Hsu7ef568c2016-12-27 15:58:58 +0800164 ['scp', 'root@%s:%s' % (options.host, remote_path), basename]) # pylint: disable=undefined-variable
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800165 subprocess.check_call([
166 'sox', '-b', '32', '-r', '48000', '-c', '8', '-e', 'signed', basename,
167 '-c', '2', basename + '.wav'
168 ])
Cheng-Yi Chiangab747d82016-11-22 15:39:12 +0800169
170
En-Shuo Hsua6814512020-01-16 16:47:39 +0800171def ConnectCrosToLineIn():
172 """Connects a audio bus path from Cros headphone to Chameleon LineIn."""
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800173 p.AudioBoardConnect(1, 'Cros device headphone') # pylint: disable=undefined-variable
174 p.AudioBoardConnect(1, 'Chameleon FPGA line-in') # pylint: disable=undefined-variable
Cheng-Yi Chiangab747d82016-11-22 15:39:12 +0800175
176
Cheng-Yi Chiang852e13e2017-04-17 19:02:22 +0800177def TestMotors():
178 """Test motors by touching and releasing each button once."""
179 for func in ['Call', 'Hang Up', 'Mute', 'Vol Up', 'Vol Down']:
180 PressOneFunc(func)
181
182
183def PressOneFunc(func, time_sec=0):
184 """Test motors by touching and releasing one button.
185
186 Args:
187 func: The motor function. One of 'Call', 'Hang Up', 'Mute', 'Vol Up',
188 'Vol Down'.
189 time_sec: Hold time in seconds after touch and before release.
190 """
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800191 logging.info('Testing %s button, press and hold for %f seconds', func,
192 time_sec)
En-Shuo Hsua6814512020-01-16 16:47:39 +0800193 p.motor_board.Touch(func) # pylint: disable=undefined-variable
Cheng-Yi Chiang852e13e2017-04-17 19:02:22 +0800194 time.sleep(time_sec)
En-Shuo Hsua6814512020-01-16 16:47:39 +0800195 p.motor_board.Release(func) # pylint: disable=undefined-variable
Cheng-Yi Chiang852e13e2017-04-17 19:02:22 +0800196
197
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800198def BuildTunnel(local_port, port, host):
199
200 def cleanup():
201 cleanup_cmd = 'ssh -S %s -O exit root@%s' % (TUNNEL_NAME, host)
202 subprocess.call(cleanup_cmd, shell=True)
203
204 cmd = ('ssh -M -S %s -fnNT -o "StrictHostKeyChecking no" '
205 '-L %d:localhost:%d root@%s') % (TUNNEL_NAME, local_port, port, host)
206 return None if subprocess.call(cmd, shell=True) else cleanup
207
208
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +0800209def Main():
210 """The Main program."""
211 logging.basicConfig(
212 format='%(asctime)s:%(levelname)s:%(message)s', level=logging.DEBUG)
213
214 options = ParseArgs()
215
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800216 if options.remote:
217 cleanup = BuildTunnel(options.local_port, options.port, options.host)
218 if cleanup is None:
En-Shuo Hsua6814512020-01-16 16:47:39 +0800219 logging.info('Failed to create tunnel')
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800220 return
221 atexit.register(cleanup)
222 address = 'http://localhost:%d' % options.local_port
223 else:
224 address = 'http://%s:%s' % (options.host, options.port)
225
Yu-Hsuan Hsudb96ced2020-03-03 17:35:01 +0800226 proxy = xmlrpc.client.ServerProxy(address)
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800227 logging.info('Connected to %s with MAC address %s', address,
228 proxy.GetMacAddress())
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +0800229 ShowMessages(proxy)
En-Shuo Hsu8fca32b2019-12-09 17:47:45 +0800230 StartInteractiveShell(proxy)
Cheng-Yi Chiang3f9cb972015-11-23 17:43:59 +0800231
232
233if __name__ == '__main__':
234 Main()