mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
pd: add commands to test flashing using PD communication
Add console commands to send the Vendor-Defined Messages used to flash a USB-PD target. Also add a simple test script to flash Zinger through its CC line. To run the script, the board must have CONFIG_USB_PD_CUSTOM_VDM defined. By default fruitpie has this config option enabled. BRANCH=none BUG=chrome-os-partner:28330 TEST=With a fruitpie connected to a zinger run ./util/flash_pd.py ./build/zinger/ec.RW.flat and see Zinger booting on RW. Change-Id: I06f8f545e28b93b2e646e668d81b594eb7976a2d Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/203375 Reviewed-by: Todd Broch <tbroch@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
550669cbfb
commit
8ed54fbf07
@@ -18,6 +18,7 @@
|
||||
/* Optional features */
|
||||
#define CONFIG_STM_HWTIMER32
|
||||
#define CONFIG_USB_POWER_DELIVERY
|
||||
#define CONFIG_USB_PD_CUSTOM_VDM
|
||||
#define CONFIG_USB_PD_DUAL_ROLE
|
||||
#define CONFIG_USB_PD_INTERNAL_COMP
|
||||
#define CONFIG_USBC_SS_MUX
|
||||
|
||||
@@ -127,3 +127,33 @@ int pd_power_negotiation_allowed(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ----------------- Vendor Defined Messages ------------------ */
|
||||
int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
|
||||
{
|
||||
int cmd = PD_VDO_CMD(payload[0]);
|
||||
int i;
|
||||
ccprintf("VDM/%d [%d] %08x\n", cnt, cmd, payload[0]);
|
||||
|
||||
/* make sure we have some payload */
|
||||
if (cnt == 0)
|
||||
return 0;
|
||||
|
||||
switch (cmd) {
|
||||
case VDO_CMD_VERSION:
|
||||
/* guarantee last byte of payload is null character */
|
||||
*(payload + cnt - 1) = 0;
|
||||
ccprintf("version: %s\n", (char *)(payload+1));
|
||||
break;
|
||||
case VDO_CMD_RW_HASH:
|
||||
ccprintf("RW Hash: ");
|
||||
payload++; /* skip cmd */
|
||||
for (i = 0; i < cnt - 1; i++)
|
||||
ccprintf("%08x ", *payload++);
|
||||
ccprintf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define CONFIG_BOARD_PRE_INIT
|
||||
#define CONFIG_STM_HWTIMER32
|
||||
#define CONFIG_USB_POWER_DELIVERY
|
||||
#define CONFIG_USB_PD_CUSTOM_VDM
|
||||
#define CONFIG_USB_PD_DUAL_ROLE
|
||||
#define CONFIG_USB_PD_INTERNAL_COMP
|
||||
#define CONFIG_USBC_SS_MUX
|
||||
|
||||
@@ -183,6 +183,37 @@ static void dual_role_force_sink(void)
|
||||
}
|
||||
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, dual_role_force_sink, HOOK_PRIO_DEFAULT);
|
||||
|
||||
/* ----------------- Vendor Defined Messages ------------------ */
|
||||
int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
|
||||
{
|
||||
int cmd = PD_VDO_CMD(payload[0]);
|
||||
int i;
|
||||
ccprintf("VDM/%d [%d] %08x\n", cnt, cmd, payload[0]);
|
||||
|
||||
/* make sure we have some payload */
|
||||
if (cnt == 0)
|
||||
return 0;
|
||||
|
||||
switch (cmd) {
|
||||
case VDO_CMD_VERSION:
|
||||
/* guarantee last byte of payload is null character */
|
||||
*(payload + cnt - 1) = 0;
|
||||
ccprintf("version: %s\n", (char *)(payload+1));
|
||||
break;
|
||||
case VDO_CMD_RW_HASH:
|
||||
ccprintf("RW Hash: ");
|
||||
payload++; /* skip cmd */
|
||||
for (i = 0; i < cnt - 1; i++)
|
||||
ccprintf("%08x ", *payload++);
|
||||
ccprintf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Console commands */
|
||||
static int command_ec_int(int argc, char **argv)
|
||||
{
|
||||
pd_send_ec_int();
|
||||
@@ -194,6 +225,8 @@ DECLARE_CONSOLE_COMMAND(ecint, command_ec_int,
|
||||
"Toggle EC interrupt line",
|
||||
NULL);
|
||||
|
||||
/****************************************************************************/
|
||||
/* Host commands */
|
||||
static int ec_status_host_cmd(struct host_cmd_handler_args *args)
|
||||
{
|
||||
const struct ec_params_pd_status *p = args->params;
|
||||
|
||||
@@ -203,6 +203,7 @@ enum pd_states {
|
||||
PD_STATE_SNK_REQUESTED,
|
||||
PD_STATE_SNK_TRANSITION,
|
||||
PD_STATE_SNK_READY,
|
||||
PD_STATE_VDM_COMM,
|
||||
#endif /* CONFIG_USB_PD_DUAL_ROLE */
|
||||
|
||||
PD_STATE_SRC_DISCONNECTED,
|
||||
@@ -432,6 +433,10 @@ static int send_request(int port, uint32_t rdo)
|
||||
|
||||
return bit_len;
|
||||
}
|
||||
|
||||
/* next Vendor Defined Message to send */
|
||||
static int vdo_count[PD_PORT_COUNT];
|
||||
static uint32_t vdo_data[PD_PORT_COUNT][7];
|
||||
#endif /* CONFIG_USB_PD_DUAL_ROLE */
|
||||
|
||||
static int send_bist_cmd(int port)
|
||||
@@ -504,8 +509,13 @@ static void handle_vdm_request(int port, int cnt, uint32_t *payload)
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
int rlen;
|
||||
uint32_t *rdata;
|
||||
#endif
|
||||
|
||||
if (vid == USB_VID_GOOGLE) {
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
||||
vdo_count[port] = 0; /* Done */
|
||||
#endif
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
rlen = pd_custom_vdm(port, cnt, payload, &rdata);
|
||||
if (rlen > 0) {
|
||||
uint16_t header = PD_HEADER(PD_DATA_VENDOR_DEF,
|
||||
@@ -513,9 +523,9 @@ static void handle_vdm_request(int port, int cnt, uint32_t *payload)
|
||||
rlen);
|
||||
send_validate_message(port, header, rlen, rdata);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CPRINTF("Unhandled VDM VID %04x CMD %04x\n",
|
||||
vid, payload[0] & 0xFFFF);
|
||||
}
|
||||
@@ -836,7 +846,8 @@ static void execute_hard_reset(int port)
|
||||
{
|
||||
pd[port].msg_id = 0;
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
||||
pd[port].task_state = pd[port].role == PD_ROLE_SINK ?
|
||||
if (pd[port].task_state != PD_STATE_VDM_COMM)
|
||||
pd[port].task_state = pd[port].role == PD_ROLE_SINK ?
|
||||
PD_STATE_SNK_DISCONNECTED : PD_STATE_SRC_DISCONNECTED;
|
||||
#else
|
||||
pd[port].task_state = PD_STATE_SRC_DISCONNECTED;
|
||||
@@ -1112,6 +1123,23 @@ void pd_task(void)
|
||||
}
|
||||
timeout = 100*MSEC;
|
||||
break;
|
||||
case PD_STATE_VDM_COMM:
|
||||
if (vdo_count[port] > 7) { /* TIMEOUT */
|
||||
vdo_count[port] = -EC_ERROR_TIMEOUT;
|
||||
} else if (vdo_count[port] > 0) {
|
||||
int len;
|
||||
uint16_t header = PD_HEADER(PD_DATA_VENDOR_DEF,
|
||||
pd[port].role, pd[port].msg_id,
|
||||
vdo_count[port]);
|
||||
len = send_validate_message(port, header,
|
||||
vdo_count[port],
|
||||
vdo_data[port]);
|
||||
vdo_count[port] = 8; /* Transmitting */
|
||||
if (len < 0)
|
||||
vdo_count[port] = -EC_ERROR_BUSY;
|
||||
}
|
||||
timeout = 500*MSEC;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_DUAL_ROLE */
|
||||
case PD_STATE_HARD_RESET:
|
||||
send_hard_reset(port);
|
||||
@@ -1147,10 +1175,12 @@ void pd_task(void)
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
||||
if (pd[port].role == PD_ROLE_SINK &&
|
||||
!pd_snk_is_vbus_provided(port)) {
|
||||
/* Sink: detect disconnect by monitoring VBUS */
|
||||
pd[port].task_state = PD_STATE_SNK_DISCONNECTED;
|
||||
/* set timeout small to reconnect fast */
|
||||
timeout = 5*MSEC;
|
||||
if (pd[port].task_state != PD_STATE_VDM_COMM) {
|
||||
/* Sink: detect disconnect by monitoring VBUS */
|
||||
pd[port].task_state = PD_STATE_SNK_DISCONNECTED;
|
||||
/* set timeout small to reconnect fast */
|
||||
timeout = 5*MSEC;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DUAL_ROLE */
|
||||
}
|
||||
@@ -1169,6 +1199,87 @@ void pd_set_suspend(int port, int enable)
|
||||
task_wake(PORT_TO_TASK_ID(port));
|
||||
}
|
||||
|
||||
static int hex8tou32(char *str, uint32_t *val)
|
||||
{
|
||||
char *ptr = str;
|
||||
uint32_t tmp = 0;
|
||||
|
||||
while (*ptr) {
|
||||
char c = *ptr++;
|
||||
if (c >= '0' && c <= '9')
|
||||
tmp = (tmp << 4) + (c - '0');
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
tmp = (tmp << 4) + (c - 'A' + 10);
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
tmp = (tmp << 4) + (c - 'a' + 10);
|
||||
else
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
if (ptr != str + 8)
|
||||
return EC_ERROR_INVAL;
|
||||
*val = tmp;
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int remote_flashing(int argc, char **argv)
|
||||
{
|
||||
int port;
|
||||
char *e;
|
||||
static int flash_offset[PD_PORT_COUNT];
|
||||
|
||||
if (argc < 4)
|
||||
return EC_ERROR_PARAM_COUNT;
|
||||
|
||||
port = strtoi(argv[1], &e, 10);
|
||||
if (*e || port >= PD_PORT_COUNT)
|
||||
return EC_ERROR_PARAM2;
|
||||
|
||||
if (!strcasecmp(argv[3], "erase")) {
|
||||
vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_FLASH_ERASE);
|
||||
vdo_count[port] = 1;
|
||||
flash_offset[port] = 0;
|
||||
ccprintf("ERASE ...");
|
||||
} else if (!strcasecmp(argv[3], "reboot")) {
|
||||
vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_REBOOT);
|
||||
vdo_count[port] = 1;
|
||||
ccprintf("REBOOT ...");
|
||||
} else if (!strcasecmp(argv[3], "hash")) {
|
||||
int i;
|
||||
for (i = 4; i < argc; i++)
|
||||
if (hex8tou32(argv[i], vdo_data[port] + i - 3))
|
||||
return EC_ERROR_INVAL;
|
||||
vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_FLASH_HASH);
|
||||
vdo_count[port] = argc - 3;
|
||||
ccprintf("HASH ...");
|
||||
} else if (!strcasecmp(argv[3], "rw_hash")) {
|
||||
vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_RW_HASH);
|
||||
vdo_count[port] = 1;
|
||||
ccprintf("RW HASH...");
|
||||
} else if (!strcasecmp(argv[3], "version")) {
|
||||
vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_VERSION);
|
||||
vdo_count[port] = 1;
|
||||
ccprintf("VERSION...");
|
||||
} else {
|
||||
int i;
|
||||
for (i = 3; i < argc; i++)
|
||||
if (hex8tou32(argv[i], vdo_data[port] + i - 2))
|
||||
return EC_ERROR_INVAL;
|
||||
vdo_data[port][0] = VDO(USB_VID_GOOGLE, VDO_CMD_FLASH_WRITE);
|
||||
vdo_count[port] = argc - 2;
|
||||
ccprintf("WRITE %d @%04x ...", (argc - 3) * 4,
|
||||
flash_offset[port]);
|
||||
flash_offset[port] += (argc - 3) * 4;
|
||||
}
|
||||
pd[port].task_state = PD_STATE_VDM_COMM;
|
||||
task_wake(PORT_TO_TASK_ID(port));
|
||||
|
||||
/* Wait until VDO is done */
|
||||
while (vdo_count[port] > 0)
|
||||
task_wait_event(100*MSEC);
|
||||
ccprintf("DONE\n");
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
void pd_request_source_voltage(int port, int mv)
|
||||
{
|
||||
pd_set_max_voltage(mv);
|
||||
@@ -1264,11 +1375,13 @@ static int command_pd(int argc, char **argv)
|
||||
else
|
||||
return EC_ERROR_PARAM3;
|
||||
}
|
||||
} else if (!strncasecmp(argv[2], "flash", 4)) {
|
||||
return remote_flashing(argc, argv);
|
||||
} else if (!strncasecmp(argv[2], "state", 5)) {
|
||||
const char * const state_names[] = {
|
||||
"DISABLED", "SUSPENDED",
|
||||
"SNK_DISCONNECTED", "SNK_DISCOVERY", "SNK_REQUESTED",
|
||||
"SNK_TRANSITION", "SNK_READY",
|
||||
"SNK_TRANSITION", "SNK_READY", "VDM_COMM",
|
||||
"SRC_DISCONNECTED", "SRC_DISCOVERY", "SRC_NEGOCIATE",
|
||||
"SRC_ACCEPTED", "SRC_TRANSITION", "SRC_READY",
|
||||
"HARD_RESET", "BIST",
|
||||
|
||||
313
util/flash_pd.py
Executable file
313
util/flash_pd.py
Executable file
@@ -0,0 +1,313 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2014 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.
|
||||
"""Flash PD PSU RW firmware over the USBPD comm channel using console."""
|
||||
|
||||
import array
|
||||
import errno
|
||||
import hashlib
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
|
||||
import serial
|
||||
# TODO(tbroch): Discuss adding hdctools as an EC package RDEPENDS
|
||||
from servo import client
|
||||
from servo import multiservo
|
||||
|
||||
VERSION = '0.0.1'
|
||||
|
||||
# RW area is half of the 32-kB flash minus the hash storage area
|
||||
MAX_FW_SIZE = 16 * 1024 - 32
|
||||
# Hash of RW when erased (set to all F's)
|
||||
ERASED_RW_HASH = 'd582e94d 0d12a61c 1199927e 5610c036 2e2870a9'
|
||||
|
||||
|
||||
class FlashPDError(Exception):
|
||||
"""Exception class for flash_pd utility."""
|
||||
|
||||
|
||||
class FlashPD(client.ServoClient):
|
||||
"""class to flash PD MCU.
|
||||
|
||||
Note,
|
||||
Some designs(samus) have multiple embedded MCUs. In that case the convention
|
||||
is to name the pty associated with usbpd as 'usbpd_uart_pty'. In the case
|
||||
where there is only one MCU (fruitpie) we prefer 'usbpd_uart_pty' but will
|
||||
also associate 'ecu_uart_pty' with having capability to flash the UBS-PD
|
||||
capable PSU(zinger).
|
||||
|
||||
Attributes:
|
||||
_options : Values instance from optparse.
|
||||
|
||||
Public Methods:
|
||||
expect : Examine console output for an expected response.
|
||||
flash_command : Write a PD flash command and interrogate its result.
|
||||
get_version : Retrieve current version of PD FW.
|
||||
"""
|
||||
|
||||
def __init__(self, options):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
options : Values instance from optparse.
|
||||
|
||||
Raises:
|
||||
FlashPDError: If unable to determine the console pty
|
||||
"""
|
||||
super(FlashPD, self).__init__(host=options.server, port=options.port)
|
||||
self._options = options
|
||||
self._serial = None
|
||||
|
||||
try:
|
||||
pty = self.get('usbpd_uart_pty')
|
||||
except socket.error as e:
|
||||
raise FlashPDError('Can\'t connect to servod :: %s' % e)
|
||||
except client.ServoClientError:
|
||||
pty = self.get('ec_uart_pty')
|
||||
if not pty:
|
||||
raise FlashPDError('Unable to determine EC uart from servod')
|
||||
|
||||
logging.debug('Opening serial connection to %s', pty)
|
||||
try:
|
||||
self._serial = serial.Serial(pty, timeout=1)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EAGAIN:
|
||||
# try twice if already open EAGAIN failure causes disconnect.
|
||||
self._serial = serial.Serial(pty, timeout=1)
|
||||
else:
|
||||
raise FlashPDError('%s' % e)
|
||||
|
||||
# quiet other channels that might pollute console.
|
||||
self._serial.write('chan 1\n')
|
||||
self._serial.flushOutput()
|
||||
self._serial.flushInput()
|
||||
|
||||
def __del__(self):
|
||||
"""Deconstructor."""
|
||||
if self._serial:
|
||||
for l in self._serial:
|
||||
logging.debug('flash: %s', l)
|
||||
self._serial.write('chan 0xffffffff\n')
|
||||
self._serial.write('chan restore\n')
|
||||
self._serial.close()
|
||||
|
||||
def expect(self, val, timeout=5):
|
||||
"""Scan serial output for particular string.
|
||||
|
||||
Args:
|
||||
val : string to look for
|
||||
timeout : integer seconds to look before timing out.
|
||||
|
||||
Returns:
|
||||
tuple : boolean if 'val' found in console output.
|
||||
string of line that had 'val' in it.
|
||||
"""
|
||||
done = False
|
||||
deadline = time.time() + timeout
|
||||
while not done and (time.time() < deadline):
|
||||
l = None
|
||||
for l in self._serial:
|
||||
done = val in l
|
||||
logging.debug('Is %s in: %s', val, l)
|
||||
if done or time.time() > deadline:
|
||||
break
|
||||
if not done:
|
||||
logging.error('\"%s\" missing', val)
|
||||
return (done, l)
|
||||
|
||||
def flash_command(self, cmd, expect='DONE'):
|
||||
"""Send PD Flash command and interrogate output.
|
||||
|
||||
Args:
|
||||
cmd : string of 'pd port flash' command to execute
|
||||
expect : string of expected response after 'cmd'
|
||||
|
||||
Returns:
|
||||
found : boolean, whether response matches expected.
|
||||
"""
|
||||
self._serial.write('pd %d flash %s\n' % (self._options.multiport, cmd))
|
||||
(found, line) = self.expect(expect)
|
||||
return (found, line)
|
||||
|
||||
def get_version(self):
|
||||
"""Retreive PSU firmware version.
|
||||
|
||||
Looks like: 'version: zinger_v1.1.1917-bfd'
|
||||
|
||||
Returns:
|
||||
version : string of version
|
||||
Raises:
|
||||
FlashPDError : if can't determine version
|
||||
"""
|
||||
(found, line) = self.flash_command('version', expect='version:')
|
||||
logging.debug('is version in: %s', line)
|
||||
m = False
|
||||
if found:
|
||||
m = re.match(r'.*version:\s+(\w+_v\d+\.\d+\.\d+-\S+).*', line)
|
||||
if not m:
|
||||
raise FlashPDError('Unable to determine PD FW version')
|
||||
return m.group(1)
|
||||
|
||||
|
||||
def flash_pd(options):
|
||||
"""Flash power delivery firmware."""
|
||||
|
||||
ec = FlashPD(options)
|
||||
|
||||
with open(options.firmware) as fd:
|
||||
fw = fd.read()
|
||||
fw_size = len(fw)
|
||||
# Compute SHA-1 hash for the full (padded) RW firmware
|
||||
padded_fw = fw + '\xff' * (MAX_FW_SIZE - fw_size)
|
||||
sha = hashlib.sha1(padded_fw).digest()
|
||||
sha_str = ' '.join(['%08x' % (w) for w in array.array('I', sha)])
|
||||
|
||||
# pad the firmware to a multiple of 6 U32
|
||||
if fw_size % 24:
|
||||
fw += '\xff'*(24 - fw_size % 24)
|
||||
words = array.array('I', fw)
|
||||
|
||||
logging.info('Current PD FW version is %s', ec.get_version())
|
||||
if options.versiononly:
|
||||
return
|
||||
|
||||
logging.info('Flashing %d bytes', fw_size)
|
||||
|
||||
# reset flashed hash to reboot in RO
|
||||
ec.flash_command('hash' + ' 00000000' * 5)
|
||||
# reboot in RO
|
||||
ec.flash_command('reboot')
|
||||
# delay to give time to reboot
|
||||
time.sleep(0.5)
|
||||
# erase all RW partition
|
||||
ec.flash_command('erase')
|
||||
|
||||
# verify that erase was successful by reading hash of RW
|
||||
(done, _) = ec.flash_command('rw_hash', expect=ERASED_RW_HASH)
|
||||
if done:
|
||||
done = ec.expect('DONE')
|
||||
|
||||
if not done:
|
||||
raise FlashPDError('Erase failed')
|
||||
|
||||
logging.info('Successfully erased flash.')
|
||||
|
||||
if options.eraseonly:
|
||||
ec.flash_command('reboot')
|
||||
logging.info('After erase, FW version is %s', ec.get_version())
|
||||
return
|
||||
|
||||
# write firmware content
|
||||
for i in xrange(len(words) / 6):
|
||||
chunk = words[i * 6: (i + 1) * 6]
|
||||
cmd = ' '.join(['%08x' % (w) for w in chunk])
|
||||
ec.flash_command(cmd)
|
||||
|
||||
# write new firmware hash
|
||||
ec.flash_command('hash ' + sha_str)
|
||||
# reboot in RW
|
||||
ec.flash_command('reboot')
|
||||
# delay for reboot
|
||||
time.sleep(0.2)
|
||||
|
||||
logging.info('Flashing DONE.')
|
||||
logging.info('SHA-1: %s', sha_str)
|
||||
logging.info('New PD FW version is %s', ec.get_version())
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""Parse commandline arguments.
|
||||
|
||||
Note, reads sys.argv directly
|
||||
|
||||
Returns:
|
||||
options : dict of from optparse.parse_args().
|
||||
|
||||
Raises:
|
||||
FlashPDError : If problems with arguments
|
||||
"""
|
||||
description = (
|
||||
'%prog [<switch args>] <firmware.bin>'
|
||||
'\n'
|
||||
'%prog is a utility for flashing the USB-PD charger RW firmware over '
|
||||
'the USB-PD communication channel using PD MCU console commands.'
|
||||
)
|
||||
examples = (
|
||||
'\nExamples:\n'
|
||||
' %prog build/zinger/ec.RW.flat\n'
|
||||
)
|
||||
parser = optparse.OptionParser(version='%prog ' + VERSION)
|
||||
parser.description = description
|
||||
parser.add_option('-d', '--debug', action='store_true', default=False,
|
||||
help='enable debug messages.')
|
||||
parser.add_option('-s', '--server', help='host where servod is running',
|
||||
default=client.DEFAULT_HOST)
|
||||
parser.add_option('-p', '--port', default=client.DEFAULT_PORT, type=int,
|
||||
help='port servod is listening on.')
|
||||
parser.add_option('-m', '--multiport', default=0, type=int,
|
||||
help='If design has multiple type-C ports, this identifies '
|
||||
'which one has USB PD PSU.')
|
||||
parser.add_option('', '--timeout', default=5, type=int,
|
||||
help='Timeout seconds to wait for console output.')
|
||||
parser.add_option('', '--eraseonly', action='store_true', default=False,
|
||||
help='Only erase RW portion and exit.')
|
||||
parser.add_option('-V', '--versiononly', action='store_true', default=False,
|
||||
help='Only read version and exit.')
|
||||
multiservo.add_multiservo_parser_options(parser)
|
||||
|
||||
parser.set_usage(parser.get_usage() + examples)
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
# TODO(tbroch) Add this once we refactor module to ease use in scripts.
|
||||
if options.name:
|
||||
raise NotImplementedError('Multiservo support TBD')
|
||||
|
||||
# Add after to enumerate options.firmware but outside 'help' generation
|
||||
parser.add_option('-f', '', action='store', type='string', dest='firmware')
|
||||
|
||||
if len(args) != 1:
|
||||
raise FlashPDError('Must supply power delivery firmware to write.')
|
||||
|
||||
options.firmware = args[0]
|
||||
if not os.path.exists(options.firmware):
|
||||
raise FlashPDError('Unable to find file %s' % options.firmware)
|
||||
|
||||
fw_size = os.path.getsize(options.firmware)
|
||||
if fw_size > MAX_FW_SIZE:
|
||||
raise FlashPDError('Firmware too large %d/%d' % (fw_size, MAX_FW_SIZE))
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def main_function():
|
||||
options = parse_args()
|
||||
|
||||
loglevel = logging.INFO
|
||||
log_format = '%(asctime)s - %(name)s - %(levelname)s'
|
||||
if options.debug:
|
||||
loglevel = logging.DEBUG
|
||||
log_format += ' - %(filename)s:%(lineno)d:%(funcName)s'
|
||||
log_format += ' - %(message)s'
|
||||
logging.basicConfig(level=loglevel, format=log_format)
|
||||
|
||||
flash_pd(options)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function wrapper to catch exceptions properly."""
|
||||
try:
|
||||
main_function()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
except FlashPDError as e:
|
||||
print 'Error: ', e.message
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user