| // Copyright 2021 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file implements functions to interact with the DUT's embedded controller (EC) |
| // via the host command `ectool`. |
| |
| package firmware |
| |
| import ( |
| "context" |
| "regexp" |
| |
| "chromiumos/tast/dut" |
| "chromiumos/tast/errors" |
| "chromiumos/tast/ssh" |
| ) |
| |
| // ECToolName specifies which of the many Chromium EC based MCUs ectool will |
| // be communicated with. |
| // Some options are cros_ec, cros_fp, cros_pd, cros_scp, and cros_ish. |
| type ECToolName string |
| |
| const ( |
| // ECToolNameMain selects the main EC using cros_ec. |
| ECToolNameMain ECToolName = "cros_ec" |
| // ECToolNameFingerprint selects the FPMCU using cros_fp. |
| ECToolNameFingerprint ECToolName = "cros_fp" |
| ) |
| |
| // ECTool allows for interaction with the host command `ectool`. |
| type ECTool struct { |
| dut *dut.DUT |
| name ECToolName |
| } |
| |
| // NewECTool creates an ECTool. |
| func NewECTool(d *dut.DUT, name ECToolName) *ECTool { |
| return &ECTool{dut: d, name: name} |
| } |
| |
| // Regexps to capture values outputted by ectool version. |
| var ( |
| reFirmwareCopy = regexp.MustCompile(`Firmware copy:\s*(RO|RW)`) |
| reROVersion = regexp.MustCompile(`RO version:\s*(\S+)\s`) |
| reRWVersion = regexp.MustCompile(`RW version:\s*(\S+)\s`) |
| ) |
| |
| // Command return the prebuilt ssh Command with options and args applied. |
| func (ec *ECTool) Command(args ...string) *ssh.Cmd { |
| args = append([]string{"--name=" + string(ec.name)}, args...) |
| return ec.dut.Conn().Command("ectool", args...) |
| } |
| |
| // Version returns the EC version of the active firmware. |
| func (ec *ECTool) Version(ctx context.Context) (string, error) { |
| output, err := ec.Command("version").Output(ctx, ssh.DumpLogOnError) |
| if err != nil { |
| return "", errors.Wrap(err, "running 'ectool version' on DUT") |
| } |
| |
| // Parse output to determine whether RO or RW is the active firmware. |
| match := reFirmwareCopy.FindSubmatch(output) |
| if len(match) == 0 { |
| return "", errors.Errorf("did not find firmware copy in 'ectool version' output: %s", output) |
| } |
| var reActiveFWVersion *regexp.Regexp |
| switch string(match[1]) { |
| case "RO": |
| reActiveFWVersion = reROVersion |
| case "RW": |
| reActiveFWVersion = reRWVersion |
| default: |
| return "", errors.Errorf("unexpected match from reFirmwareCopy: got %s; want RO or RW", match[1]) |
| } |
| |
| // Parse either RO version line or RW version line, depending on which is active, to find the active firmware version. |
| match = reActiveFWVersion.FindSubmatch(output) |
| if len(match) == 0 { |
| return "", errors.Errorf("failed to match regexp %s in ectool version output: %s", reActiveFWVersion, output) |
| } |
| return string(match[1]), nil |
| } |