diff options
-rw-r--r-- | chip/stm32/usb_power.c | 99 | ||||
-rw-r--r-- | chip/stm32/usb_power.h | 56 | ||||
-rw-r--r-- | extra/usb_power/board.README | 7 | ||||
-rw-r--r-- | extra/usb_power/board/marlin/marlin_pvc.scenario | 1 | ||||
-rw-r--r-- | extra/usb_power/marlin_v.scenario | 1 | ||||
-rwxr-xr-x | extra/usb_power/powerlog.py | 130 |
6 files changed, 230 insertions, 64 deletions
diff --git a/chip/stm32/usb_power.c b/chip/stm32/usb_power.c index ad2b6d55d6..bf9e824f84 100644 --- a/chip/stm32/usb_power.c +++ b/chip/stm32/usb_power.c @@ -16,8 +16,6 @@ #define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) - - static int usb_power_init_inas(struct usb_power_config const *config); static int usb_power_read(struct usb_power_config const *config); static int usb_power_write_line(struct usb_power_config const *config); @@ -102,9 +100,6 @@ static int usb_power_write_line(struct usb_power_config const *config) return bytes; } - CPRINTS("usb_power_write_line: no data rs: %d, rc: %d", - USB_POWER_RECORD_SIZE(state->ina_count), - USB_POWER_MAX_CACHED(state->ina_count)); return 0; } @@ -133,12 +128,12 @@ static int usb_power_state_stop(struct usb_power_config const *config) return USB_POWER_ERROR_NOT_CAPTURING; } - state->state = USB_POWER_STATE_SETUP; + state->state = USB_POWER_STATE_OFF; state->reports_head = 0; state->reports_tail = 0; state->reports_xmit_active = 0; state->stride_bytes = 0; - CPRINTS("[STOP] STATE: CAPTURING -> SETUP"); + CPRINTS("[STOP] STATE: CAPTURING -> OFF"); return USB_POWER_SUCCESS; } @@ -149,14 +144,16 @@ static int usb_power_state_start(struct usb_power_config const *config, { struct usb_power_state *state = config->state; int integration_us = cmd->start.integration_us; + int ret; if (state->state != USB_POWER_STATE_SETUP) { CPRINTS("[START] Error not setup."); return USB_POWER_ERROR_NOT_SETUP; } - if (count != 6) { - CPRINTS("[START] Error count %d is not 6", (int)count); + if (count != sizeof(struct usb_power_command_start)) { + CPRINTS("[START] Error count %d is not %d", (int)count, + sizeof(struct usb_power_command_start)); return USB_POWER_ERROR_READ_SIZE; } @@ -170,7 +167,10 @@ static int usb_power_state_start(struct usb_power_config const *config, state->max_cached = USB_POWER_MAX_CACHED(state->ina_count); state->integration_us = integration_us; - usb_power_init_inas(config); + ret = usb_power_init_inas(config); + + if (ret) + return USB_POWER_ERROR_INVAL; state->state = USB_POWER_STATE_CAPTURING; CPRINTS("[START] STATE: SETUP -> CAPTURING %dus", integration_us); @@ -198,7 +198,7 @@ static int usb_power_state_settime(struct usb_power_config const *config, else config->state->wall_offset = 0; - return EC_SUCCESS; + return USB_POWER_SUCCESS; } @@ -207,6 +207,7 @@ static int usb_power_state_addina(struct usb_power_config const *config, { struct usb_power_state *state = config->state; struct usb_power_ina_cfg *ina; + int i; /* Only valid from OFF or SETUP */ if ((state->state != USB_POWER_STATE_OFF) && @@ -232,12 +233,48 @@ static int usb_power_state_addina(struct usb_power_config const *config, state->ina_count = 0; } + if ((cmd->addina.type < USBP_INA231_POWER) || + (cmd->addina.type > USBP_INA231_SHUNTV)) { + CPRINTS("[ADDINA] Error INA type 0x%x invalid", + (int)(cmd->addina.type)); + return USB_POWER_ERROR_INVAL; + } + + if (cmd->addina.rs == 0) { + CPRINTS("[ADDINA] Error INA resistance cannot be zero!"); + return USB_POWER_ERROR_INVAL; + } + /* Select INA to configure */ ina = state->ina_cfg + state->ina_count; ina->port = cmd->addina.port; ina->addr = (cmd->addina.addr) << 1; /* 7 to 8 bit addr. */ ina->rs = cmd->addina.rs; + ina->type = cmd->addina.type; + + /* + * INAs can be shared, in that they will have various values + * (and therefore registers) read from them each cycle, including + * power, voltage, current. If only a single value is read, + * we an use i2c_readagain for faster transactions as we don't + * have to respecify the address. + */ + ina->shared = 0; +#ifdef USB_POWER_VERBOSE + ina->shared = 1; +#endif + + /* Check if shared with previously configured INAs. */ + for (i = 0; i < state->ina_count; i++) { + struct usb_power_ina_cfg *tmp = state->ina_cfg + i; + + if ((tmp->port == ina->port) && + (tmp->addr == ina->addr)) { + ina->shared = 1; + tmp->shared = 1; + } + } state->ina_count += 1; return USB_POWER_SUCCESS; @@ -305,7 +342,6 @@ static int usb_power_read(struct usb_power_config const *config) if (ret) return EC_SUCCESS; - CPRINTS("[CAP] busy"); result = USB_POWER_ERROR_BUSY; } else { CPRINTS("[STOP] Error not capturing."); @@ -353,7 +389,22 @@ static int usb_power_read(struct usb_power_config const *config) #define INA231_MODE_BUS 0x6 #define INA231_MODE_BOTH 0x7 +int reg_type_mapping(enum usb_power_ina_type ina_type) +{ + switch (ina_type) { + case USBP_INA231_POWER: + return INA231_REG_PWR; + case USBP_INA231_BUSV: + return INA231_REG_BUSV; + case USBP_INA231_CURRENT: + return INA231_REG_CURR; + case USBP_INA231_SHUNTV: + return INA231_REG_RSHV; + default: + return INA231_REG_CONF; + } +} uint16_t ina2xx_readagain(uint8_t port, uint8_t addr) { @@ -407,6 +458,7 @@ int ina2xx_write(uint8_t port, uint8_t addr, uint8_t reg, uint16_t val) */ /* INA231 integration and averaging time presets, indexed by register value */ +#define NELEMS(x) (sizeof(x) / sizeof((x)[0])) static const int average_settings[] = { 1, 4, 16, 64, 128, 256, 512, 1024}; static const int conversion_time_us[] = { @@ -426,14 +478,14 @@ static int usb_power_init_inas(struct usb_power_config const *config) } /* Find an INA preset integration time less than specified */ - while (shunt_time < 7) { + while (shunt_time < (NELEMS(conversion_time_us) - 1)) { if (conversion_time_us[shunt_time + 1] > target_us) break; shunt_time++; } /* Find an averaging setting from the INA presets that fits. */ - while (avg < 7) { + while (avg < (NELEMS(average_settings) - 1)) { if ((conversion_time_us[shunt_time] * average_settings[avg + 1]) > target_us) @@ -464,6 +516,7 @@ static int usb_power_init_inas(struct usb_power_config const *config) * CurrentLSB = uA per div = 80mV / (Rsh * 2^15) * CurrentLSB 100x uA = 100x 80000000nV / (Rsh mOhm * 0x8000) */ + /* TODO: allow voltage readings if no sense resistor. */ if (ina->rs == 0) return -1; @@ -524,7 +577,10 @@ static int usb_power_init_inas(struct usb_power_config const *config) * will be cached and all ina2xx_readagain() calls will read * from the same address. */ - ina2xx_read(ina->port, ina->addr, INA231_REG_PWR); + ina2xx_read(ina->port, ina->addr, reg_type_mapping(ina->type)); +#ifdef USB_POWER_VERBOSE + CPRINTS("[CAP] %d (%d,0x%02x): type:%d", (int)(ina->type)); +#endif } return EC_SUCCESS; @@ -570,7 +626,7 @@ static int usb_power_get_samples(struct usb_power_config const *config) r->timestamp = time; for (i = 0; i < state->ina_count; i++) { - int power; + int regval; struct usb_power_ina_cfg *ina = inas + i; /* Read INA231. @@ -578,11 +634,16 @@ static int usb_power_get_samples(struct usb_power_config const *config) * Readagain cached this address so we'll save an I2C * transaction. */ - power = ina2xx_readagain(ina->port, ina->addr); - r->power[i] = power; + if (ina->shared) + regval = ina2xx_read(ina->port, ina->addr, + reg_type_mapping(ina->type)); + else + regval = ina2xx_readagain(ina->port, ina->addr); + r->power[i] = regval; #ifdef USB_POWER_VERBOSE { int current; + int power; int voltage; int bvoltage; @@ -590,7 +651,6 @@ static int usb_power_get_samples(struct usb_power_config const *config) bvoltage = ina2xx_read(ina->port, ina->addr, INA231_REG_BUSV); current = ina2xx_read(ina->port, ina->addr, INA231_REG_CURR); power = ina2xx_read(ina->port, ina->addr, INA231_REG_PWR); - } { int uV = ((int)voltage * 25) / 10; int mV = ((int)bvoltage * 125) / 100; @@ -604,6 +664,7 @@ static int usb_power_get_samples(struct usb_power_config const *config) "%duW v:%04x, b:%04x, p:%04x", uV, mV, uA, CuA, uW, voltage, bvoltage, power); } + } #endif } diff --git a/chip/stm32/usb_power.h b/chip/stm32/usb_power.h index 976f849404..ff76603e63 100644 --- a/chip/stm32/usb_power.h +++ b/chip/stm32/usb_power.h @@ -15,56 +15,60 @@ /* * Command: + * + * Commands are a 16 bit value, with optional command dependent data. * +--------------+-----------------------------------+ * | command : 2B | | * +--------------+-----------------------------------+ * - * command: 2 bytes + * Responses are an 8 bit status value, with optional data. + * +----------+-----------------------------------+ + * | res : 1B | | + * +----------+-----------------------------------+ * * reset: 0x0000 - * * +--------+ * | 0x0000 | * +--------+ * * stop: 0x0001 - * * +--------+ * | 0x0001 | * +--------+ * * addina: 0x0002 - * - * +--------+--------------------------+-------------+--------------+-----------+-------------+--------+ - * | 0x0002 | 1B: 4b: extender 4b: bus | 1B:INA type | 1B: INA addr | 1B: extra | 4B: voltage | 4B: Rs | - * +--------+--------------------------+-------------+--------------+-----------+-------------+--------+ + * +--------+--------------------------+-------------+--------------+-----------+--------+ + * | 0x0002 | 1B: 4b: extender 4b: bus | 1B:INA type | 1B: INA addr | 1B: extra | 4B: Rs | + * +--------+--------------------------+-------------+--------------+-----------+--------+ * * start: 0x0003 - * * +--------+----------------------+ * | 0x0003 | 4B: integration time | * +--------+----------------------+ * - * next: 0x0004 + * start response: + * +-------------+-----------------------------+ + * | status : 1B | Actual integration time: 4B | + * +-------------+-----------------------------+ * + * next: 0x0004 * +--------+ * | 0x0004 | * +--------+ * - * settime: 0x0005 + * next response: + * +-------------+----------+----------------+----------------------------+ + * | status : 1B | size: 1B | timestamp : 8B | payload : may span packets | + * +-------------+----------+----------------+----------------------------+ * + * settime: 0x0005 * +--------+---------------------+ * | 0x0005 | 8B: Wall clock time | * +--------+---------------------+ * * + * Status: 1 byte status * - * Response: - * +-------------+----------+----------------+------------------+ - * | status : 1B | size: 1B | timestamp : 8B | payload : <= 58B | Pad to multiple of 4 byte. - * +-------------+----------+----------------+------------------+ - * - * status: 1 byte status * 0x00: Success * 0x01: I2C Error * 0x02: Overflow @@ -75,16 +79,16 @@ * 0x06: Busy, outgoing queue is empty. * 0x07: Size, command length is incorrect for command type.. * 0x08: More INAs specified than board limit. + * 0x09: Invalid input, eg. invalid INA type. * 0x80: Unknown error * * size: 1 byte incoming INA reads count * * timestamp: 4 byte timestamp associated with these samples * - * read payload: up to 58 bytes of data, 29x INA reads of current - * */ +/* 8b status field. */ enum usb_power_error { USB_POWER_SUCCESS = 0x00, USB_POWER_ERROR_I2C = 0x01, @@ -95,9 +99,11 @@ enum usb_power_error { USB_POWER_ERROR_BUSY = 0x06, USB_POWER_ERROR_READ_SIZE = 0x07, USB_POWER_ERROR_FULL = 0x08, + USB_POWER_ERROR_INVAL = 0x09, USB_POWER_ERROR_UNKNOWN = 0x80, }; +/* 16b command field. */ enum usb_power_command { USB_POWER_CMD_RESET = 0x0000, USB_POWER_CMD_STOP = 0x0001, @@ -107,6 +113,15 @@ enum usb_power_command { USB_POWER_CMD_SETTIME = 0x0005, }; +/* Addina "INA Type" field. */ +enum usb_power_ina_type { + USBP_INA231_POWER = 0x01, + USBP_INA231_BUSV = 0x02, + USBP_INA231_CURRENT = 0x03, + USBP_INA231_SHUNTV = 0x04, +}; + +/* Internal state machine values */ enum usb_power_states { USB_POWER_STATE_OFF = 0, USB_POWER_STATE_SETUP, @@ -132,6 +147,11 @@ struct usb_power_ina_cfg { int rs; /* uA per div as reported from INA */ int scale; + + /* Is this power, shunt voltage, bus voltage, or current? */ + int type; + /* Is this INA returning the one value only and can use readagain? */ + int shared; }; diff --git a/extra/usb_power/board.README b/extra/usb_power/board.README index b898e16540..41c30c8e38 100644 --- a/extra/usb_power/board.README +++ b/extra/usb_power/board.README @@ -45,10 +45,16 @@ Scenario files: Scenario files contain the set of rails to monitor in this session. The file format is simply a list of rail names from the board file. +Optionally, you can specify the type of measurement, from the set of +"POWER", "BUSV", "CURRENT", "SHUNTV". If not specified, the default is +power. + example.scenario: [ "railname", "another_railname", +["railname", "BUSV"], +["railname", "CURRENT"], ... ] @@ -82,6 +88,7 @@ VBAT uW: microwatt reading from this rail, generated on the INA voltage. ... uW: Further microwatt entry columns for each rail specified in your scenario file. +... xX: Measurement in uW, mW, mV, uA, uV as per config. Calculate stats and store data and stats: diff --git a/extra/usb_power/board/marlin/marlin_pvc.scenario b/extra/usb_power/board/marlin/marlin_pvc.scenario new file mode 100644 index 0000000000..426cd1479c --- /dev/null +++ b/extra/usb_power/board/marlin/marlin_pvc.scenario @@ -0,0 +1 @@ +["VBAT", ["VBAT", "BUSV"], ["VBAT", "CURRENT"], ["VBAT", "SHUNTV"]] diff --git a/extra/usb_power/marlin_v.scenario b/extra/usb_power/marlin_v.scenario new file mode 100644 index 0000000000..99c132cb27 --- /dev/null +++ b/extra/usb_power/marlin_v.scenario @@ -0,0 +1 @@ +[["VBAT", "BUSV"], ["VDD_1V8_PANEL", "BUSV"], ["V_EMMC_2V95", "BUSV"], ["V_SR_2V85", "BUSV"], ["V_USBSS_SW_1V8", "BUSV"], ["V_AUDIO_2V15", "BUSV"]] diff --git a/extra/usb_power/powerlog.py b/extra/usb_power/powerlog.py index 81d050bb91..6128ca2027 100755 --- a/extra/usb_power/powerlog.py +++ b/extra/usb_power/powerlog.py @@ -46,7 +46,19 @@ class Spower(object): _write_ep: pyUSB write endpoint for this interface """ - INA231 = 1 + # INA interface type. + INA_POWER = 1 + INA_BUSV = 2 + INA_CURRENT = 3 + INA_SHUNTV = 4 + + # usb power commands + CMD_RESET = 0x0000 + CMD_STOP = 0x0001 + CMD_ADDINA = 0x0002 + CMD_START = 0x0003 + CMD_NEXT = 0x0004 + CMD_SETTIME = 0x0005 # Map between header channel number (0-47) # and INA I2C bus/addr on sweetberry. @@ -180,7 +192,8 @@ class Spower(object): """ Clear INA description struct.""" self._inas = [] - def append_ina_struct(self, name, rs, port, addr, data=None): + def append_ina_struct(self, name, rs, port, addr, + data=None, ina_type=INA_POWER): """Add an INA descriptor into the list of active INAs. Args: @@ -189,18 +202,22 @@ class Spower(object): port: I2C channel this INA is connected to. addr: I2C addr of this INA. data: Misc data for special handling, board specific. + ina_type: INA function to use, power, voltage, etc. """ ina = {} ina['name'] = name ina['rs'] = rs ina['port'] = port ina['addr'] = addr + ina['type'] = ina_type # Calculate INA231 Calibration register # (see INA231 spec p.15) # CurrentLSB = uA per div = 80mV / (Rsh * 2^15) # CurrentLSB uA = 80000000nV / (Rsh mOhm * 0x8000) ina['uAscale'] = 80000000. / (rs * 0x8000); ina['uWscale'] = 25. * ina['uAscale']; + ina['mVscale'] = 1.25 + ina['uVscale'] = 2.5 ina['data'] = data self._inas.append(ina) @@ -265,7 +282,7 @@ class Spower(object): def send_reset(self): """Reset the power interface on the stm32""" - cmd = struct.pack("<H", 0x0000) + cmd = struct.pack("<H", self.CMD_RESET) ret = self.wr_command(cmd, rtimeout=50, wtimeout=50) debuglog("Command RESET: %s" % "success" if ret == 0 else "failure") @@ -292,7 +309,7 @@ class Spower(object): def stop(self): """Stop any active data acquisition.""" - cmd = struct.pack("<H", 0x0001) + cmd = struct.pack("<H", self.CMD_STOP) ret = self.wr_command(cmd) debuglog("Command STOP: %s" % "success" if ret == 0 else "failure") @@ -306,22 +323,23 @@ class Spower(object): Returns: actual sampling interval in ms. """ - cmd = struct.pack("<HI", 0x0003, integration_us) + cmd = struct.pack("<HI", self.CMD_START, integration_us) read = self.wr_command(cmd, read_count=5) actual_us = 0 if len(read) == 5: ret, actual_us = struct.unpack("<BI", read) - debuglog("Command START: %s %dus" % ("success" if ret == 0 else "failure", actual_us)) + debuglog("Command START: %s %dus" % ( + "success" if ret == 0 else "failure", actual_us)) else: debuglog("Command START: FAIL") return actual_us - def add_ina_name(self, name): + def add_ina_name(self, name_tuple): """Add INA from board config. Args: - name: readable name of power rail in board config. + name_tuple: name and type of power rail in board config. Returns: True if INA added, False if the INA is not on this board. @@ -329,6 +347,8 @@ class Spower(object): Raises: Exception on unexpected failure. """ + name, ina_type = name_tuple + for datum in self._brdcfg: if datum["name"] == name: channel = int(datum["channel"]) @@ -337,7 +357,7 @@ class Spower(object): if board == self._board: port, addr = self.CHMAP[channel] - self.add_ina(port, self.INA231, addr, 0, rs, data=datum) + self.add_ina(port, ina_type, addr, 0, rs, data=datum) return True else: return False @@ -350,7 +370,7 @@ class Spower(object): timestamp_us: host timestmap in us. """ # 0x0005 , 8 byte timestamp - cmd = struct.pack("<HQ", 0x0005, timestamp_us) + cmd = struct.pack("<HQ", self.CMD_SETTIME, timestamp_us) ret = self.wr_command(cmd) debuglog("Command SETTIME: %s" % "success" if ret == 0 else "failure") @@ -360,20 +380,22 @@ class Spower(object): Args: bus: which i2c bus the INA is on. Same ordering as Si2c. - ina_type: which model INA. 0x1 -> INA231 + ina_type: Ina interface: INA_POWER/BUSV/etc. addr: 7 bit i2c addr of this INA extra: extra data for nonstandard configs. resistance: int, shunt resistance in mOhm """ # 0x0002, 1B: bus, 1B:INA type, 1B: INA addr, 1B: extra, 4B: Rs - cmd = struct.pack("<HBBBBI", 0x0002, bus, ina_type, addr, extra, resistance) + cmd = struct.pack("<HBBBBI", self.CMD_ADDINA, + bus, ina_type, addr, extra, resistance) ret = self.wr_command(cmd) if ret == 0: if data: name = data['name'] else: name = "ina%d_%02x" % (bus, addr) - self.append_ina_struct(name, resistance, bus, addr, data=data) + self.append_ina_struct(name, resistance, bus, addr, + data=data, ina_type=ina_type) debuglog("Command ADD_INA: %s" % "success" if ret == 0 else "failure") def report_header_size(self): @@ -396,12 +418,12 @@ class Spower(object): """Read a line of data from the setup INAs Returns: - list of dicts of the values read, otherwise None. - [{ts:100, vbat:450}, {ts:200, vbat:440}] + list of dicts of the values read by ina/type tuple, otherwise None. + [{ts:100, (vbat, power):450}, {ts:200, (vbat, power):440}] """ try: expected_bytes = self.report_size(len(self._inas)) - cmd = struct.pack("<H", 0x0004) + cmd = struct.pack("<H", self.CMD_NEXT) bytesread = self.wr_command(cmd, read_count=expected_bytes) except usb.core.USBError as e: print("READ LINE FAILED %s" % e) @@ -455,11 +477,23 @@ class Spower(object): for i in range(0, size): idx = self.report_header_size() + 2*i - raw_w = struct.unpack("<H", data[idx:idx+2])[0] - uw = raw_w * self._inas[i]['uWscale'] name = self._inas[i]['name'] - debuglog("READ %d %s: %fs: %fuW" % (i, name, ftimestamp, uw)) - record[self._inas[i]['name']] = uw + name_tuple = (self._inas[i]['name'], self._inas[i]['type']) + + raw_val = struct.unpack("<h", data[idx:idx+2])[0] + + if self._inas[i]['type'] == Spower.INA_POWER: + val = raw_val * self._inas[i]['uWscale'] + elif self._inas[i]['type'] == Spower.INA_BUSV: + val = raw_val * self._inas[i]['mVscale'] + elif self._inas[i]['type'] == Spower.INA_CURRENT: + val = raw_val * self._inas[i]['uAscale'] + elif self._inas[i]['type'] == Spower.INA_SHUNTV: + val = raw_val * self._inas[i]['uVscale'] + + debuglog("READ %d %s: %fs: 0x%04x %f" % (i, + name, ftimestamp, raw_val, val)) + record[name_tuple] = val return record @@ -532,7 +566,7 @@ class powerlog(object): with open(cfgfile) as data_file: names = json.load(data_file) - self._names = names + self._names = self.process_scenario(names) for key in self._pwr: self._pwr[key].load_board(brdfile) @@ -562,6 +596,37 @@ class powerlog(object): else: self._pwr[key].set_time(0) + def process_scenario(self, name_list): + """Return list of tuples indicating name and type. + + Args: + json originated list of names, or [name, type] + Returns: + list of tuples of (name, type) defaulting to type "POWER" + Raises: exception, invalid INA type. + """ + names = [] + for entry in name_list: + if isinstance(entry, list): + name = entry[0] + if entry[1] == "POWER": + type = Spower.INA_POWER + elif entry[1] == "BUSV": + type = Spower.INA_BUSV + elif entry[1] == "CURRENT": + type = Spower.INA_CURRENT + elif entry[1] == "SHUNTV": + type = Spower.INA_SHUNTV + else: + raise Exception("Invalid INA type", "Type of %s [%s] not recognized," + " try one of POWER, BUSV, CURRENT" % (entry[0], entry[1])) + else: + name = entry + type = Spower.INA_POWER + + names.append((name, type)) + return names + def start(self, integration_us_request, seconds, sync_speed=.8): """Starts sampling. @@ -585,8 +650,18 @@ class powerlog(object): # CSV header if self._print_raw_data: title = "ts:%dus" % integration_us - for name in self._names: - unit = "mW" if self._use_mW else "uW" + for name_tuple in self._names: + name, ina_type = name_tuple + + if ina_type == Spower.INA_POWER: + unit = "mW" if self._use_mW else "uW" + elif ina_type == Spower.INA_BUSV: + unit = "mV" + elif ina_type == Spower.INA_CURRENT: + unit = "uA" + elif ina_type == Spower.INA_SHUNTV: + unit = "uV" + title += ", %s %s" % (name, unit) title += ", status" logoutput(title) @@ -625,10 +700,11 @@ class powerlog(object): csv = "%f" % aggregate_record["ts"] for name in self._names: if name in aggregate_record: - multiplier = 0.001 if self._use_mW else 1 - power = aggregate_record[name] * multiplier - csv += ", %.2f" % power - self._data.AddValue(name, power) + multiplier = 0.001 if (self._use_mW and + name[1]==Spower.INA_POWER) else 1 + value = aggregate_record[name] * multiplier + csv += ", %.2f" % value + self._data.AddValue(name, value) else: csv += ", " csv += ", %d" % aggregate_record["status"] |