3 # Copyright © 2020 Google LLC
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 from serial_buffer
import SerialBuffer
32 def __init__(self
, cpu
, ec
):
33 # Merged FIFO for the two serial buffers, fed by threads.
34 self
.serial_queue
= queue
.Queue()
35 self
.sentinel
= object()
38 self
.ec_ser
= SerialBuffer(ec
, "results/serial-ec.txt", "R SERIAL-EC> ")
39 self
.cpu_ser
= SerialBuffer(cpu
, "results/serial.txt", "R SERIAL-CPU> ")
41 self
.iter_feed_ec
= threading
.Thread(target
=self
.iter_feed_queue
, daemon
=True, args
=(self
.ec_ser
.lines(),))
42 self
.iter_feed_ec
.start()
44 self
.iter_feed_cpu
= threading
.Thread(target
=self
.iter_feed_queue
, daemon
=True, args
=(self
.cpu_ser
.lines(),))
45 self
.iter_feed_cpu
.start()
47 # Feed lines from our serial queues into the merged queue, marking when our
49 def iter_feed_queue(self
, it
):
51 self
.serial_queue
.put(i
)
52 self
.serial_queue
.put(sentinel
)
54 # Return the next line from the queue, counting how many threads have
55 # terminated and joining when done
56 def get_serial_queue_line(self
):
57 line
= self
.serial_queue
.get()
58 if line
== self
.sentinel
:
59 self
.threads_done
= self
.threads_done
+ 1
60 if self
.threads_done
== 2:
61 self
.iter_feed_cpu
.join()
62 self
.iter_feed_ec
.join()
65 # Returns an iterator for getting the next line.
66 def serial_queue_lines(self
):
67 return iter(self
.get_serial_queue_line
, self
.sentinel
)
69 def ec_write(self
, s
):
70 print("W SERIAL-EC> %s" % s
)
71 self
.ec_ser
.serial
.write(s
.encode())
73 def cpu_write(self
, s
):
74 print("W SERIAL-CPU> %s" % s
)
75 self
.cpu_ser
.serial
.write(s
.encode())
78 # Flush any partial commands in the EC's prompt, then ask for a reboot.
80 self
.ec_write("reboot\n")
82 # This is emitted right when the bootloader pauses to check for input.
83 # Emit a ^N character to request network boot, because we don't have a
84 # direct-to-netboot firmware on cheza.
85 for line
in self
.serial_queue_lines():
86 if re
.search("load_archive: loading locale_en.bin", line
):
87 self
.cpu_write("\016")
91 for line
in self
.serial_queue_lines():
92 if re
.search("---. end Kernel panic", line
):
95 # The Cheza boards have issues with failing to bring up power to
96 # the system sometimes, possibly dependent on ambient temperature
98 if re
.search("POWER_GOOD not seen in time", line
):
99 print("Detected intermittent poweron failure, restarting run...")
102 # The Cheza firmware seems to occasionally get stuck looping in
103 # this error state during TFTP booting, possibly based on amount of
104 # network traffic around it, but it'll usually recover after a
106 if re
.search("R8152: Bulk read error 0xffffffbf", line
):
108 if tftp_failures
>= 100:
109 print("Detected intermittent tftp failure, restarting run...")
112 result
= re
.search("bare-metal result: (\S*)", line
)
114 if result
.group(1) == "pass":
119 print("Reached the end of the CPU serial log without finding a result")
123 parser
= argparse
.ArgumentParser()
124 parser
.add_argument('--cpu', type=str, help='CPU Serial device', required
=True)
125 parser
.add_argument('--ec', type=str, help='EC Serial device', required
=True)
126 args
= parser
.parse_args()
128 servo
= CrosServoRun(args
.cpu
, args
.ec
)
135 # power down the CPU on the device
136 servo
.ec_write("power off\n")
140 if __name__
== '__main__':