From ccff3365038c037741d274c6713f72f129766980 Mon Sep 17 00:00:00 2001 From: Nick Sanders Date: Tue, 22 Nov 2016 16:20:47 -0800 Subject: sweetberry: add power logging tool powerlog.py can access sweetberry and log power data. Also included are marlin and kevin example board configs. BUG=chromium:608039 TEST=log power data BRANCH=None Change-Id: I0f868d95d17d86522dca045a227a824563f93cd0 Signed-off-by: Nick Sanders Reviewed-on: https://chromium-review.googlesource.com/413293 Reviewed-by: Aseda Aboagye --- extra/usb_power/board.README | 71 +++ extra/usb_power/board/kevin/kevin.board | 18 + extra/usb_power/board/kevin/kevin_all.scenario | 18 + extra/usb_power/board/marlin/marlin.board | 74 +++ extra/usb_power/board/marlin/marlin_all_A.scenario | 42 ++ extra/usb_power/board/marlin/marlin_all_B.scenario | 28 ++ .../usb_power/board/marlin/marlin_common.scenario | 1 + extra/usb_power/board/marlin/marlin_short.scenario | 1 + extra/usb_power/board/marlin/marlin_vbat.scenario | 1 + extra/usb_power/powerlog.py | 549 +++++++++++++++++++++ 10 files changed, 803 insertions(+) create mode 100644 extra/usb_power/board.README create mode 100644 extra/usb_power/board/kevin/kevin.board create mode 100644 extra/usb_power/board/kevin/kevin_all.scenario create mode 100644 extra/usb_power/board/marlin/marlin.board create mode 100644 extra/usb_power/board/marlin/marlin_all_A.scenario create mode 100644 extra/usb_power/board/marlin/marlin_all_B.scenario create mode 100644 extra/usb_power/board/marlin/marlin_common.scenario create mode 100644 extra/usb_power/board/marlin/marlin_short.scenario create mode 100644 extra/usb_power/board/marlin/marlin_vbat.scenario create mode 100755 extra/usb_power/powerlog.py (limited to 'extra/usb_power') diff --git a/extra/usb_power/board.README b/extra/usb_power/board.README new file mode 100644 index 0000000000..e253660496 --- /dev/null +++ b/extra/usb_power/board.README @@ -0,0 +1,71 @@ +Sweetberry USB power monitoring + +This tool allows high speed monitoring of power rails via a special USB +endpoint. Currently this is implemented for the sweetberry baord. + +To use on a board, you'll need two config files, one describing the board, +a ".board" file, and one describing the particular rails you want to +monitor in this session, a ".scenario" file. + + +Board files: + +Board files contain a list of rails, supporting 48 channels each on up to two +sweetberries. For each rail you must specify a name, sense resistor value, +and channel number. You can optionally list expected voltage and net name. +The format is as follows, in json: + +example.board: +[ +{ "name": "railname", + "rs": , + "sweetberry": <"A" for main sweetberry, "B" for a secondary sweetberry>, + "channel": <0-47 according to board schematic>, + "v": , + "net": +}, +{...} +] + +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. + +example.scenario: +[ +"railname", +"another_railname", +... +] + + +Output: +powerlog.py will output a csv formatted log to stdout, at timing intervals +specified on the command line. Currently values below "-t 10000" do not work +reliably but further updates should allow faster updating. + +An example run of: +./powerlog.py -b board/marlin/marlin.board -c board/marlin/marlin_short.scenario -t 100000 + +Will result in: +ts:32976us, VBAT uW, VDD_MEM uW, VDD_CORE uW, VDD_GFX uW, VDD_1V8_PANEL uW +0.033004, 12207.03, 4882.81, 9155.27, 2441.41, 0.00 +0.066008, 12207.03, 3662.11, 9155.27, 2441.41, 0.00 +0.099012, 12207.03, 3662.11, 9155.27, 2441.41, 0.00 +... + + +The output format is as follows: +ts:32976us: Timestamps either zero based or synced to system clock, + in seconds. The column header indicates the selected + sampling interval. Since the INA231 has specific + hardware defines sampling options, this will be the + closest supported option lower than the requested "-t" + value on the command line. +VBAT uW: microwatt reading from this rail, generated on the INA + by integrating the voltage/amperage on the sense resistor + over the sampling time, and multiplying by the sampled bus + voltage. +... uW: Further microwatt entry columns for each rail specified in + your scenario file. diff --git a/extra/usb_power/board/kevin/kevin.board b/extra/usb_power/board/kevin/kevin.board new file mode 100644 index 0000000000..8ab59573c6 --- /dev/null +++ b/extra/usb_power/board/kevin/kevin.board @@ -0,0 +1,18 @@ +[ +{"name": "pp5000", "rs": 0.01, "sweetberry": "A", "channel": 0}, +{"name": "ppvar_gpu", "rs": 0.01, "sweetberry": "A", "channel": 1}, +{"name": "pp3300_wifi_bt", "rs": 0.01, "sweetberry": "A", "channel": 2}, +{"name": "pp1500_ap_io", "rs": 0.01, "sweetberry": "A", "channel": 3}, +{"name": "pp3300_alw", "rs": 0.01, "sweetberry": "A", "channel": 4}, +{"name": "ppvar_litcpu", "rs": 0.01, "sweetberry": "A", "channel": 5}, +{"name": "pp1800_s0", "rs": 0.01, "sweetberry": "A", "channel": 6}, +{"name": "pp3300_haven", "rs": 0.1, "sweetberry": "A", "channel": 7}, +{"name": "ppvar_bigcpu", "rs": 0.01, "sweetberry": "A", "channel": 8}, +{"name": "pp900_ap", "rs": 0.01, "sweetberry": "A", "channel": 9}, +{"name": "pp1800_ec", "rs": 0.1, "sweetberry": "A", "channel": 10}, +{"name": "pp1800_sensor", "rs": 0.01, "sweetberry": "A", "channel": 11}, +{"name": "pp1800_alw", "rs": 0.01, "sweetberry": "A", "channel": 12}, +{"name": "pp1200_lpddr", "rs": 0.01, "sweetberry": "A", "channel": 13}, +{"name": "pp3300_ec", "rs": 0.1, "sweetberry": "A", "channel": 14}, +{"name": "pp3300_s0", "rs": 0.01, "sweetberry": "A", "channel": 15} +] diff --git a/extra/usb_power/board/kevin/kevin_all.scenario b/extra/usb_power/board/kevin/kevin_all.scenario new file mode 100644 index 0000000000..dbc3953364 --- /dev/null +++ b/extra/usb_power/board/kevin/kevin_all.scenario @@ -0,0 +1,18 @@ +[ +"pp5000", +"ppvar_gpu", +"pp3300_wifi_bt", +"pp1500_ap_io", +"pp3300_alw", +"ppvar_litcpu", +"pp1800_s0", +"pp3300_haven", +"ppvar_bigcpu", +"pp900_ap", +"pp1800_ec", +"pp1800_sensor", +"pp1800_alw", +"pp1200_lpddr", +"pp3300_ec", +"pp3300_s0" +] diff --git a/extra/usb_power/board/marlin/marlin.board b/extra/usb_power/board/marlin/marlin.board new file mode 100644 index 0000000000..dc4cdad258 --- /dev/null +++ b/extra/usb_power/board/marlin/marlin.board @@ -0,0 +1,74 @@ +[ +{"name": "VBAT", "rs": 0.01, "sweetberry": "A", "net": "", "channel": 0}, +{"name": "VBAT_", "rs": 0.01, "sweetberry": "B", "net": "", "channel": 0}, +{"name": "VDD_MEM", "rs": 0.05, "sweetberry": "A", "net": "V_MEM_0V875", "channel": 1}, +{"name": "VDD_EBI_PHY", "rs": 0.1, "sweetberry": "A", "net": "V_EBI_0V875", "channel": 2}, +{"name": "VDD_PCIE_1P8", "rs": 0.5, "sweetberry": "A", "net": "V_USB_1V8", "channel": 3}, +{"name": "VDD_PCIE_CORE", "rs": 0.1, "sweetberry": "A", "net": "V_PCIE_0V925", "channel": 4}, +{"name": "VDD_MIPI_CSI", "rs": 0.1, "sweetberry": "A", "net": "V_CSI_DSI_1V25", "channel": 5}, +{"name": "VDD_A1", "rs": 0.1, "sweetberry": "A", "net": "V_MSMA1_1V225", "channel": 6}, +{"name": "VDD_A2", "rs": 1.0, "sweetberry": "A", "net": "V_MSMA2_1V8", "channel": 7}, +{"name": "VDD_P2", "rs": 0.02, "sweetberry": "A", "net": "V_IO_1V8", "channel": 8}, +{"name": "VDD_P3", "rs": 0.5, "sweetberry": "B", "net": "V_IO_1V8", "channel": 1}, +{"name": "VDD_P5", "rs": 0.5, "sweetberry": "A", "net": "V_RUIM1", "channel": 9}, +{"name": "VDD_P6", "rs": 0.02, "sweetberry": "A", "net": "V_IO_1V8", "channel": 46}, +{"name": "VDD_P10", "rs": 0.1, "sweetberry": "A", "net": "V_UFS_1V2", "channel": 10}, +{"name": "VDD_P12", "rs": 0.1, "sweetberry": "A", "net": "V_SRIO_1V8", "channel": 11}, +{"name": "VDD_USB_HS_3P1", "rs": 0.5, "sweetberry": "A", "net": "V_USB_3V075", "channel": 12}, +{"name": "VDD_CORE", "rs": 0.02, "sweetberry": "A", "net": "V_VDDCORE_0V8", "channel": 13}, +{"name": "VDD_GFX", "rs": 0.05, "sweetberry": "A", "net": "V_GFX_0V98", "channel": 14}, +{"name": "VDD_MODEM", "rs": 0.05, "sweetberry": "A", "net": "V_MODEM_1V0", "channel": 15}, +{"name": "VDD_APC", "rs": 0.01, "sweetberry": "A", "net": "V_APC_0V8", "channel": 16}, +{"name": "VDD_P1", "rs": 0.1, "sweetberry": "A", "net": "V_DDRCORE_1V1", "channel": 17}, +{"name": "VDD_DDR_CORE_1P8", "rs": 0.1, "sweetberry": "B", "net": "V_IO_1V8", "channel": 3}, +{"name": "VDD_SSC_CORE", "rs": 0.05, "sweetberry": "A", "net": "V_SSCCORE_0V8", "channel": 18}, +{"name": "VDD_SSC_MEM", "rs": 0.02, "sweetberry": "A", "net": "V_SSCMEM_0V875", "channel": 19}, +{"name": "V_EMMC_2V95", "rs": 0.1, "sweetberry": "A", "net": "V_EMMC_2V95", "channel": 20}, +{"name": "VCCQ2", "rs": 0.1, "sweetberry": "B", "net": "V_IO_1V8", "channel": 4}, +{"name": "VDD/VDDIO", "rs": 1.0, "sweetberry": "B", "net": "V_SRIO_1V8", "channel": 5}, +{"name": "V_LED_3V3", "rs": 0.1, "sweetberry": "A", "net": "V_LED_3V3", "channel": 21}, +{"name": "VDD/VIO", "rs": 1.0, "sweetberry": "B", "net": "V_SRIO_1V8", "channel": 6}, +{"name": "V_SRIO_1V8", "rs": 1.0, "sweetberry": "B", "net": "V_SRIO_1V8", "channel": 7}, +{"name": "V_SRIO_1V8_", "rs": 1.0, "sweetberry": "B", "net": "V_SRIO_1V8", "channel": 8}, +{"name": "VBAT/VDD/VDDA", "rs": 0.1, "sweetberry": "B", "net": "V_SRIO_1V8", "channel": 9}, +{"name": "V_SRIO_1V8__", "rs": 1.0, "sweetberry": "B", "net": "V_SRIO_1V8", "channel": 10}, +{"name": "V_SR_2V85", "rs": 0.1, "sweetberry": "A", "net": "V_SR_2V85", "channel": 22}, +{"name": "", "rs": 0.1, "sweetberry": "B", "net": "", "channel": 11}, +{"name": "V_USBSS_SW_1V8", "rs": 0.1, "sweetberry": "A", "net": "V_USBSS_SW_1V8", "channel": 23}, +{"name": "V_RF_2V7", "rs": 0.5, "sweetberry": "A", "net": "V_RF_2V7", "channel": 24}, +{"name": "V_TP_3V3", "rs": 0.5, "sweetberry": "A", "net": "V_TP_3V3", "channel": 25}, +{"name": "V_ELVDD", "rs": 0.1, "sweetberry": "B", "net": "V_ELVDD", "channel": 16}, +{"name": "V_AVDD", "rs": 1.0, "sweetberry": "B", "net": "V_AVDD", "channel": 17}, +{"name": "VCI_3V", "rs": 0.1, "sweetberry": "A", "net": "VCI_3V", "channel": 26}, +{"name": "VDD_1V8_PANEL", "rs": 0.5, "sweetberry": "A", "net": "VDD_1V8_PANEL", "channel": 27}, +{"name": "V_TP_1V8", "rs": 0.1, "sweetberry": "A", "net": "V_TP_1V8", "channel": 28}, +{"name": "V_CAM2_D1V2", "rs": 0.1, "sweetberry": "A", "net": "V_CAM2_D1V2", "channel": 31}, +{"name": "V_CAMIO_1V8", "rs": 0.1, "sweetberry": "A", "net": "V_CAMIO_1V8", "channel": 32}, +{"name": "V_CAM1_VCM2V85", "rs": 0.5, "sweetberry": "B", "net": "V_CAM1_VCM2V85", "channel": 18}, +{"name": "V_CAM1_A2V85", "rs": 1.0, "sweetberry": "B", "net": "V_CAM1_A2V85", "channel": 19}, +{"name": "V_CAM1_D1V0", "rs": 0.02, "sweetberry": "A", "net": "V_CAM1_D1V0", "channel": 33}, +{"name": "V_CAMIO_1V8_", "rs": 1.0, "sweetberry": "B", "net": "V_CAMIO_1V8", "channel": 20}, +{"name": "VBAT_ADC_IN", "rs": 0.01, "sweetberry": "A", "net": "V_DCIN", "channel": 34}, +{"name": "VDD_RX", "rs": 1.0, "sweetberry": "B", "net": "V_IO_1V8", "channel": 21}, +{"name": "VDD_MIC_BIAS", "rs": 0.01, "sweetberry": "A", "net": "V_BOOST_BYPASS", "channel": 35}, +{"name": "PVDD/VDD", "rs": 0.1, "sweetberry": "A", "net": "V_AUD_AMP_3V3", "channel": 36}, +{"name": "V_DCIN", "rs": 0.01, "sweetberry": "A", "net": "V_DCIN", "channel": 47}, +{"name": "V_AUDIO_2V15", "rs": 0.02, "sweetberry": "A", "net": "V_AUDIO_2V15", "channel": 38}, +{"name": "V_AUDIO_1V3", "rs": 0.02, "sweetberry": "A", "net": "V_AUDIO_1V3", "channel": 39}, +{"name": "PVIN/AVIN", "rs": 0.02, "sweetberry": "A", "net": "V_DCIN", "channel": 40}, +{"name": "VBATT", "rs": 0.5, "sweetberry": "B", "net": "VPA_BATT", "channel": 24}, +{"name": "VCC_GSM", "rs": 0.01, "sweetberry": "B", "net": "VPA_APT", "channel": 25}, +{"name": "VCC1_3G", "rs": 0.01, "sweetberry": "B", "net": "VPA", "channel": 26}, +{"name": "VAPT", "rs": 0.01, "sweetberry": "B", "net": "VPA_APT", "channel": 27}, +{"name": "VCC1", "rs": 0.01, "sweetberry": "B", "net": "VPA", "channel": 28}, +{"name": "VPA_BATT", "rs": 0.5, "sweetberry": "B", "net": "VPA_BATT", "channel": 29}, +{"name": "VDD_RF1_TVCO", "rs": 0.1, "sweetberry": "A", "net": "VREG_RF_1P0", "channel": 42}, +{"name": "V_GPS_1V8", "rs": 1.0, "sweetberry": "A", "net": "V_GPS_1V8", "channel": 43}, +{"name": "VDDIO_XTAL", "rs": 1.0, "sweetberry": "A", "net": "VDDIO_XTAL_1V8", "channel": 44}, +{"name": "VDD_FEM", "rs": 0.05, "sweetberry": "A", "net": "V_DCIN", "channel": 45}, +{"name": "VDD33", "rs": 0.1, "sweetberry": "B", "net": "V_VDDRF_3V2", "channel": 31}, +{"name": "DVDD11", "rs": 0.1, "sweetberry": "B", "net": "V_VDDRF_1V1", "channel": 32}, +{"name": "VDD(PAD)", "rs": 0.5, "sweetberry": "B", "net": "V_NFC_1V8", "channel": 33}, +{"name": "VBAT/VBAT2/VDD(UP)", "rs": 0.1, "sweetberry": "B", "net": "V_MBAT", "channel": 34}, +{"name": "NFC_5V_BOOST", "rs": 0.1, "sweetberry": "B", "net": "NFC_5V_BOOST", "channel": 35} +] diff --git a/extra/usb_power/board/marlin/marlin_all_A.scenario b/extra/usb_power/board/marlin/marlin_all_A.scenario new file mode 100644 index 0000000000..a024b698d7 --- /dev/null +++ b/extra/usb_power/board/marlin/marlin_all_A.scenario @@ -0,0 +1,42 @@ +[ "VBAT", +"VDD_MEM", +"VDD_EBI_PHY", +"VDD_PCIE_1P8", +"VDD_PCIE_CORE", +"VDD_MIPI_CSI", +"VDD_A1", +"VDD_A2", +"VDD_P2", +"VDD_P5", +"VDD_P6", +"VDD_P10", +"VDD_P12", +"VDD_USB_HS_3P1", +"VDD_CORE", +"VDD_GFX", +"VDD_MODEM", +"VDD_APC", +"VDD_P1", +"VDD_SSC_CORE", +"VDD_SSC_MEM", +"V_EMMC_2V95", +"V_LED_3V3", +"V_SR_2V85", +"V_USBSS_SW_1V8", +"V_RF_2V7", +"V_TP_3V3", +"VCI_3V", +"VDD_1V8_PANEL", +"V_TP_1V8", +"V_CAM2_D1V2", +"V_CAMIO_1V8", +"V_CAM1_D1V0", +"VBAT_ADC_IN", +"VDD_MIC_BIAS", +"PVDD/VDD", +"V_DCIN", +"V_AUDIO_2V15", +"V_AUDIO_1V3", +"VDD_RF1_TVCO", +"V_GPS_1V8", +"VDD_FEM"] diff --git a/extra/usb_power/board/marlin/marlin_all_B.scenario b/extra/usb_power/board/marlin/marlin_all_B.scenario new file mode 100644 index 0000000000..876d2dbfbd --- /dev/null +++ b/extra/usb_power/board/marlin/marlin_all_B.scenario @@ -0,0 +1,28 @@ +[ "VBAT_", +"VDD_P3", +"VDD_DDR_CORE_1P8", +"VCCQ2", +"VDD/VDDIO", +"VDD/VIO", +"V_SRIO_1V8", +"V_SRIO_1V8_", +"VBAT/VDD/VDDA", +"V_SRIO_1V8__", +"", +"V_ELVDD", +"V_AVDD", +"V_CAM1_VCM2V85", +"V_CAM1_A2V85", +"V_CAMIO_1V8_", +"VDD_RX", +"VBATT", +"VCC_GSM", +"VCC1_3G", +"VAPT", +"VCC1", +"VPA_BATT", +"VDD33", +"DVDD11", +"VDD(PAD)", +"VBAT/VBAT2/VDD(UP)", +"NFC_5V_BOOST" ] diff --git a/extra/usb_power/board/marlin/marlin_common.scenario b/extra/usb_power/board/marlin/marlin_common.scenario new file mode 100644 index 0000000000..7e20236c34 --- /dev/null +++ b/extra/usb_power/board/marlin/marlin_common.scenario @@ -0,0 +1 @@ +["VBAT", "VDD_MEM", "VDD_EBI_PHY", "VDD_PCIE_1P8", "VDD_PCIE_CORE", "VDD_MIPI_CSI", "VDD_A1", "VDD_CORE", "VDD_GFX", "VDD_MODEM", "VDD_APC", "VDD_P1", "VDD_SSC_CORE", "VDD_SSC_MEM", "VDD_1V8_PANEL", "V_CAM2_D1V2", "VBAT_ADC_IN", "VDD_FEM"] diff --git a/extra/usb_power/board/marlin/marlin_short.scenario b/extra/usb_power/board/marlin/marlin_short.scenario new file mode 100644 index 0000000000..2cfc8b0f9a --- /dev/null +++ b/extra/usb_power/board/marlin/marlin_short.scenario @@ -0,0 +1 @@ +["VBAT", "VDD_MEM", "VDD_CORE", "VDD_GFX", "VDD_1V8_PANEL"] diff --git a/extra/usb_power/board/marlin/marlin_vbat.scenario b/extra/usb_power/board/marlin/marlin_vbat.scenario new file mode 100644 index 0000000000..f1c18ca202 --- /dev/null +++ b/extra/usb_power/board/marlin/marlin_vbat.scenario @@ -0,0 +1 @@ +["VBAT"] diff --git a/extra/usb_power/powerlog.py b/extra/usb_power/powerlog.py new file mode 100755 index 0000000000..ebe95b8e26 --- /dev/null +++ b/extra/usb_power/powerlog.py @@ -0,0 +1,549 @@ +#!/usr/bin/python +# Copyright 2016 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. + +"""Program to fetch power logging data from a sweetberry device + or other usb device that exports a USB power logging interface. +""" +import argparse +import array +import json +import struct +import sys +import time +from pprint import pprint + +import usb + +# This can be overridden by -v. +debug = False +def debuglog(msg): + if debug: + print msg + +def logoutput(msg): + print msg + sys.stdout.flush() + + +class Spower(object): + """Power class to access devices on the bus. + + Usage: + bus = Spower() + + Instance Variables: + _logger: Sgpio tagged log output + _dev: pyUSB device object + _read_ep: pyUSB read endpoint for this interface + _write_ep: pyUSB write endpoint for this interface + """ + + INA231 = 1 + + # Map between header channel number (0-47) + # and INA I2C bus/addr on sweetberry. + CHMAP = { + 0: (3, 0x40), + 1: (1, 0x40), + 2: (2, 0x40), + 3: (0, 0x40), + 4: (3, 0x41), + 5: (1, 0x41), + 6: (2, 0x41), + 7: (0, 0x41), + 8: (3, 0x42), + 9: (1, 0x42), + 10: (2, 0x42), + 11: (0, 0x42), + 12: (3, 0x43), + 13: (1, 0x43), + 14: (2, 0x43), + 15: (0, 0x43), + 16: (3, 0x44), + 17: (1, 0x44), + 18: (2, 0x44), + 19: (0, 0x44), + 20: (3, 0x45), + 21: (1, 0x45), + 22: (2, 0x45), + 23: (0, 0x45), + 24: (3, 0x46), + 25: (1, 0x46), + 26: (2, 0x46), + 27: (0, 0x46), + 28: (3, 0x47), + 29: (1, 0x47), + 30: (2, 0x47), + 31: (0, 0x47), + 32: (3, 0x48), + 33: (1, 0x48), + 34: (2, 0x48), + 35: (0, 0x48), + 36: (3, 0x49), + 37: (1, 0x49), + 38: (2, 0x49), + 39: (0, 0x49), + 40: (3, 0x4a), + 41: (1, 0x4a), + 42: (2, 0x4a), + 43: (0, 0x4a), + 44: (3, 0x4b), + 45: (1, 0x4b), + 46: (2, 0x4b), + 47: (0, 0x4b), + } + + def __init__(self, vendor=0x18d1, + product=0x5020, interface=1, serialname=None): + # Find the stm32. + dev_list = usb.core.find(idVendor=vendor, idProduct=product, find_all=True) + if dev_list is None: + raise Exception("Power", "USB device not found") + + # Check if we have multiple stm32s and we've specified the serial. + dev = None + if serialname: + for d in dev_list: + dev_serial = "PyUSB dioesn't have a stable interface" + try: + dev_serial = usb.util.get_string(d, 256, d.iSerialNumber) + except: + dev_serial = usb.util.get_string(d, d.iSerialNumber) + if dev_serial == serialname: + dev = d + break + if dev is None: + raise SusbError("USB device(%s) not found" % serialname) + else: + try: + dev = dev_list[0] + except: + dev = dev_list.next() + + debuglog("Found USB device: %04x:%04x" % (vendor, product)) + self._dev = dev + + # Get an endpoint instance. + try: + dev.set_configuration() + except: + pass + cfg = dev.get_active_configuration() + + intf = usb.util.find_descriptor(cfg, custom_match=lambda i: \ + i.bInterfaceClass==255 and i.bInterfaceSubClass==0x54) + + self._intf = intf + debuglog("InterfaceNumber: %s" % intf.bInterfaceNumber) + + read_ep = usb.util.find_descriptor( + intf, + # match the first IN endpoint + custom_match = \ + lambda e: \ + usb.util.endpoint_direction(e.bEndpointAddress) == \ + usb.util.ENDPOINT_IN + ) + + self._read_ep = read_ep + debuglog("Reader endpoint: 0x%x" % read_ep.bEndpointAddress) + + write_ep = usb.util.find_descriptor( + intf, + # match the first OUT endpoint + custom_match = \ + lambda e: \ + usb.util.endpoint_direction(e.bEndpointAddress) == \ + usb.util.ENDPOINT_OUT + ) + + self._write_ep = write_ep + debuglog("Writer endpoint: 0x%x" % write_ep.bEndpointAddress) + + self.clear_ina_struct() + + debuglog("Found power logging USB endpoint.") + + def clear_ina_struct(self): + """ Clear INA description struct.""" + self._inas = [] + + def append_ina_struct(self, name, rs, port, addr, data=None): + """Add an INA descriptor into the list of active INAs. + + Args: + name: Readable name of this channel. + rs: Sense resistor value in ohms, floating point. + port: I2C channel this INA is connected to. + addr: I2C addr of this INA. + data: Misc data for special handling, board specific. + """ + ina = {} + ina['name'] = name + ina['rs'] = rs + ina['port'] = port + ina['addr'] = addr + # 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['data'] = data + self._inas.append(ina) + + def wr_command(self, write_list, read_count=1, wtimeout=100, rtimeout=1000): + """Write command to logger logic. + + This function writes byte command values list to stm, then reads + byte status. + + Args: + write_list: list of command byte values [0~255]. + read_count: number of status byte values to read. + + Interface: + write: [command, data ... ] + read: [status ] + + Returns: + bytes read, or None on failure. + """ + debuglog("Spower.wr_command(write_list=[%s] (%d), read_count=%s)" % ( + list(bytearray(write_list)), len(write_list), read_count)) + + # Clean up args from python style to correct types. + write_length = 0 + if write_list: + write_length = len(write_list) + if not read_count: + read_count = 0 + + # Send command to stm32. + if write_list: + cmd = write_list + ret = self._write_ep.write(cmd, wtimeout) + + debuglog("RET: %s " % ret) + + # Read back response if necessary. + if read_count: + bytesread = self._read_ep.read(512, rtimeout) + debuglog("BYTES: [%s]" % bytesread) + + if len(bytesread) != read_count: + pass + + debuglog("STATUS: 0x%02x" % int(bytesread[0])) + if read_count == 1: + return bytesread[0] + else: + return bytesread + + return None + + def clear(self): + """Clear pending reads on the stm32""" + try: + while True: + ret = self.wr_command("", read_count=512, rtimeout=100, wtimeout=50) + debuglog("Try Clear: read %s" % "success" if ret == 0 else "failure") + except: + pass + + def send_reset(self): + """Reset the power interface on the stm32""" + cmd = struct.pack(" 0: + self.clear() + try: + self.send_reset() + count = 0 + except Exception as e: + self.clear() + self.clear() + debuglog("TRY %d of 10: %s" % (count, e)) + finally: + count -= 1 + if count == 0: + raise Exception("Power", "Failed to reset") + + def stop(self): + """Stop any active data acquisition.""" + cmd = struct.pack(" INA231 + 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(" 0 or seconds > 0.: + forever = False + + with open(cfgfile) as data_file: + names = json.load(data_file) + + p = Spower(serialname=serial_a) + p.load_board(brdfile) + p.reset() + + for name in names: + p.add_ina_name(name) + + if sync_date: + p.set_time(time.time() * 1000000) + else: + p.set_time(0) + + + # We will get back the actual integration us. + integration_us = p.start(integration_us) + + if not seconds > 0.: + seconds = samples * integration_us / 1000000.; + end_time = time.time() + seconds + try: + while forever or end_time > time.time(): + if (integration_us > 5000): + time.sleep((integration_us / 1000000.) * sync_speed) + ret = p.read_line() + finally: + p.stop() + +if __name__ == "__main__": + main() + + -- cgit v1.2.1