@em-foundation/emscope 25.1.0 → 25.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -1
- package/dist/emscope +187 -77
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
## VERSION-25-0
|
|
1
|
+
## VERSION-25-3.0
|
|
2
|
+
|
|
3
|
+
* aligned with new `BlueJoule/capture` directory structure
|
|
4
|
+
* streamlined generation of `ABOUT.md` with automatic HW/SW inclusion
|
|
5
|
+
* one digit of precision after the decimal point in most results
|
|
6
|
+
|
|
7
|
+
## VERSION-25-2.0
|
|
8
|
+
|
|
9
|
+
* new `emscope grab -p, --ppk-supply` option
|
|
10
|
+
* new `emscope scan --refresh` option
|
|
11
|
+
* adds capture_time to generated .jls file
|
|
12
|
+
* minor bug fixes
|
|
13
|
+
* works with Joulescope UI 1.3.9
|
|
14
|
+
|
|
15
|
+
## VERSION-25-1.0
|
|
2
16
|
|
|
3
17
|
* uses `BlueJoule` repo as exemplar
|
|
4
18
|
* updated `README` documentation
|
package/dist/emscope
CHANGED
|
@@ -12323,6 +12323,7 @@ var Capture = class _Capture {
|
|
|
12323
12323
|
"duration",
|
|
12324
12324
|
"sampling_rate",
|
|
12325
12325
|
"sample_count",
|
|
12326
|
+
"version",
|
|
12326
12327
|
"voltage"
|
|
12327
12328
|
];
|
|
12328
12329
|
static #SAVE_KEYS = [
|
|
@@ -12335,6 +12336,7 @@ var Capture = class _Capture {
|
|
|
12335
12336
|
cap._rootdir = rootdir;
|
|
12336
12337
|
cap._duration = duration;
|
|
12337
12338
|
cap._device = device;
|
|
12339
|
+
cap._version = version();
|
|
12338
12340
|
cap._voltage = voltage;
|
|
12339
12341
|
cap._creation_date = /* @__PURE__ */ new Date();
|
|
12340
12342
|
cap._sampling_rate = _Capture.#SAMPLING_RATE.get(device) ?? 0;
|
|
@@ -12612,9 +12614,6 @@ var Window = class {
|
|
|
12612
12614
|
return this.#off >= 0 && this.#off + this.#wid <= this.#sig.data.length;
|
|
12613
12615
|
}
|
|
12614
12616
|
};
|
|
12615
|
-
function amps(val) {
|
|
12616
|
-
return toEng(val, "A");
|
|
12617
|
-
}
|
|
12618
12617
|
function fail(msg, cond = true) {
|
|
12619
12618
|
if (cond) {
|
|
12620
12619
|
console.log(`*** ${msg} ***`);
|
|
@@ -12625,7 +12624,7 @@ function infoMsg(msg) {
|
|
|
12625
12624
|
console.log(`${TAB}${msg}`);
|
|
12626
12625
|
}
|
|
12627
12626
|
function joules(j) {
|
|
12628
|
-
return toEng(j, "J");
|
|
12627
|
+
return toEng(j, "J", 0);
|
|
12629
12628
|
}
|
|
12630
12629
|
function parseHms(s) {
|
|
12631
12630
|
if (/^\d+$/.test(s)) return Number(s);
|
|
@@ -12643,12 +12642,18 @@ function secsToHms(total) {
|
|
|
12643
12642
|
const pad = (n) => n.toString().padStart(2, "0");
|
|
12644
12643
|
return `${pad(h)}:${pad(m)}:${pad(s)}`;
|
|
12645
12644
|
}
|
|
12646
|
-
function toEng(x, u) {
|
|
12645
|
+
function toEng(x, u, e) {
|
|
12647
12646
|
if (x == 0) return `0 ${u}`;
|
|
12648
|
-
const exp = Math.floor(Math.log10(Math.abs(x)) / 3) * 3;
|
|
12647
|
+
const exp = e ?? Math.floor(Math.log10(Math.abs(x)) / 3) * 3;
|
|
12649
12648
|
const mantissa = x / 10 ** exp;
|
|
12650
12649
|
const unit = { [-9]: ` n${u}`, [-6]: ` \xB5${u}`, [-3]: ` m${u}`, [0]: ` ${u}`, [3]: ` k${u}` }[exp] || `e${exp} ${u}`;
|
|
12651
|
-
return `${mantissa.toFixed(
|
|
12650
|
+
return `${mantissa.toFixed(1).padStart(4, " ")}${unit}`;
|
|
12651
|
+
}
|
|
12652
|
+
function uAmps(val) {
|
|
12653
|
+
return toEng(val, "A", -6);
|
|
12654
|
+
}
|
|
12655
|
+
function uJoules(j) {
|
|
12656
|
+
return toEng(j, "J", -6);
|
|
12652
12657
|
}
|
|
12653
12658
|
function version() {
|
|
12654
12659
|
const path = import_path.default.resolve(__dirname, "..", "package.json");
|
|
@@ -12686,10 +12691,28 @@ ${dpath}:`);
|
|
|
12686
12691
|
// src/Detecter.ts
|
|
12687
12692
|
function exec(opts) {
|
|
12688
12693
|
const cap = Capture.load(opts.capture);
|
|
12689
|
-
|
|
12694
|
+
let params = {};
|
|
12695
|
+
if (opts.refresh) {
|
|
12696
|
+
if (cap.analysis) {
|
|
12697
|
+
for (const opt of cap.analysis?.options) {
|
|
12698
|
+
const a = opt.split(" ");
|
|
12699
|
+
const [pname, pval] = [a[0].slice(2), Number(a[1])];
|
|
12700
|
+
params[pname] = Number(pval);
|
|
12701
|
+
}
|
|
12702
|
+
if (Number.isNaN(params.trim)) {
|
|
12703
|
+
params.trim = cap.analysis.events.length;
|
|
12704
|
+
}
|
|
12705
|
+
}
|
|
12706
|
+
} else {
|
|
12707
|
+
params.gap = opts.gap;
|
|
12708
|
+
params.min_dur = opts.minDuration;
|
|
12709
|
+
params.min_egy = opts.minEnergy;
|
|
12710
|
+
params.trim = opts.trim;
|
|
12711
|
+
}
|
|
12712
|
+
const aobj = analyze(cap, params);
|
|
12690
12713
|
cap.bind(aobj);
|
|
12691
12714
|
}
|
|
12692
|
-
function analyze(cap,
|
|
12715
|
+
function analyze(cap, params = {}) {
|
|
12693
12716
|
infoMsg("analyzing captured data...");
|
|
12694
12717
|
const rsig = cap.current_sig;
|
|
12695
12718
|
const width = rsig.secsToOff(25e-5);
|
|
@@ -12717,26 +12740,26 @@ function analyze(cap, trim, gap, min_dur, min_egy) {
|
|
|
12717
12740
|
}
|
|
12718
12741
|
}
|
|
12719
12742
|
let options = new Array();
|
|
12720
|
-
if (gap !== void 0) {
|
|
12721
|
-
markers = combineMarkers(rsig, markers, rsig.secsToOff(gap / 1e3));
|
|
12722
|
-
options.push(`--gap ${gap}`);
|
|
12743
|
+
if (params.gap !== void 0) {
|
|
12744
|
+
markers = combineMarkers(rsig, markers, rsig.secsToOff(params.gap / 1e3));
|
|
12745
|
+
options.push(`--gap ${params.gap}`);
|
|
12723
12746
|
}
|
|
12724
|
-
if (min_dur != void 0) {
|
|
12725
|
-
const min_wid = rsig.secsToOff(min_dur / 1e3);
|
|
12747
|
+
if (params.min_dur != void 0) {
|
|
12748
|
+
const min_wid = rsig.secsToOff(params.min_dur / 1e3);
|
|
12726
12749
|
markers = markers.filter((m) => m.width >= min_wid);
|
|
12727
|
-
options.push(`--min-duration ${min_dur}`);
|
|
12750
|
+
options.push(`--min-duration ${params.min_dur}`);
|
|
12728
12751
|
}
|
|
12729
|
-
if (min_egy != void 0) {
|
|
12730
|
-
markers = markers.filter((m) => cap.energyWithin(m) >= min_egy / 1e6);
|
|
12731
|
-
options.push(`--min-energy ${min_egy}`);
|
|
12752
|
+
if (params.min_egy != void 0) {
|
|
12753
|
+
markers = markers.filter((m) => cap.energyWithin(m) >= params.min_egy / 1e6);
|
|
12754
|
+
options.push(`--min-energy ${params.min_egy}`);
|
|
12732
12755
|
}
|
|
12733
12756
|
let span = rsig.window(rsig.data.length).toMarker();
|
|
12734
|
-
if (trim) {
|
|
12735
|
-
[span, markers] = trimEvents(cap, markers, trim);
|
|
12736
|
-
options.push(`--trim ${trim}`);
|
|
12757
|
+
if (params.trim) {
|
|
12758
|
+
[span, markers] = trimEvents(cap, markers, params.trim);
|
|
12759
|
+
options.push(`--trim ${params.trim}`);
|
|
12737
12760
|
}
|
|
12738
12761
|
infoMsg(`found ${markers.length} event(s)`);
|
|
12739
|
-
return { span, events: markers, sleep: si, options };
|
|
12762
|
+
return { span, events: markers, sleep: si, options, version: version() };
|
|
12740
12763
|
}
|
|
12741
12764
|
function combineMarkers(sig, markers, gap) {
|
|
12742
12765
|
let res = new Array();
|
|
@@ -12797,6 +12820,7 @@ function trimEvents(cap, markers, count) {
|
|
|
12797
12820
|
}
|
|
12798
12821
|
|
|
12799
12822
|
// src/AboutFile.ts
|
|
12823
|
+
var ChildProc = __toESM(require("child_process"));
|
|
12800
12824
|
var Fs3 = __toESM(require("fs"));
|
|
12801
12825
|
var Path3 = __toESM(require("path"));
|
|
12802
12826
|
var TAG = "@emscope-pack";
|
|
@@ -12805,25 +12829,10 @@ var END = `<!-- ${TAG}:end -->`;
|
|
|
12805
12829
|
var RE = /<!--\s*@emscope-pack:start\s*-->[\s\S]*?<!--\s*@emscope-pack:end\s*-->/m;
|
|
12806
12830
|
function update(capdir) {
|
|
12807
12831
|
const cap = Capture.load(capdir);
|
|
12808
|
-
const TXT =
|
|
12809
|
-
<h1 align="center">Hardware Platform \xB7 Software Environment</h1>
|
|
12810
|
-
|
|
12811
|
-
## HW/SW configuration
|
|
12812
|
-
|
|
12813
|
-
## EM•Scope results
|
|
12832
|
+
const TXT = `<h1 align="center">Hardware Platform \xB7 Software Environment \xB7 xVx</h1>
|
|
12814
12833
|
|
|
12815
12834
|
${START}
|
|
12816
|
-
|
|
12817
12835
|
${END}
|
|
12818
|
-
|
|
12819
|
-
## Typical event
|
|
12820
|
-
|
|
12821
|
-
<p align="center">
|
|
12822
|
-
<img src="event-ID.png" alt="Event" width="900">
|
|
12823
|
-
</p>
|
|
12824
|
-
|
|
12825
|
-
## Observations
|
|
12826
|
-
|
|
12827
12836
|
`;
|
|
12828
12837
|
const file = Path3.join(cap.rootdir, "ABOUT.md");
|
|
12829
12838
|
if (!Fs3.existsSync(file)) {
|
|
@@ -12831,10 +12840,7 @@ ${END}
|
|
|
12831
12840
|
}
|
|
12832
12841
|
const src = Fs3.readFileSync(file, "utf-8");
|
|
12833
12842
|
const gen = mkGen(cap);
|
|
12834
|
-
const block = `${START}
|
|
12835
|
-
|
|
12836
|
-
${gen}
|
|
12837
|
-
|
|
12843
|
+
const block = `${START}${gen}
|
|
12838
12844
|
${END}`;
|
|
12839
12845
|
const out = RE.test(src) ? src.replace(RE, block) : `${src.replace(/\s*$/, "")}
|
|
12840
12846
|
|
|
@@ -12842,8 +12848,26 @@ ${block}
|
|
|
12842
12848
|
`;
|
|
12843
12849
|
Fs3.writeFileSync(file, out);
|
|
12844
12850
|
}
|
|
12851
|
+
function getBuildDir(cap) {
|
|
12852
|
+
const bn = Path3.basename(cap.rootdir).split("-")[0];
|
|
12853
|
+
return Path3.join(Path3.dirname(cap.rootdir), bn);
|
|
12854
|
+
}
|
|
12855
|
+
function getEvtId(cap) {
|
|
12856
|
+
for (const fn of Fs3.readdirSync(cap.rootdir)) {
|
|
12857
|
+
const m = fn.match(/^event\-([A-Z])\.png$/);
|
|
12858
|
+
if (m) return m[1];
|
|
12859
|
+
}
|
|
12860
|
+
fail(`no 'event-ID.png' file found`);
|
|
12861
|
+
return "";
|
|
12862
|
+
}
|
|
12845
12863
|
function mkGen(cap) {
|
|
12846
|
-
|
|
12864
|
+
fail(`no prior analysis: run 'emscope scan ...'`, cap.analysis === void 0);
|
|
12865
|
+
const brd = Path3.basename(Path3.dirname(cap.rootdir));
|
|
12866
|
+
const brd_txt = readBrdTxt(brd);
|
|
12867
|
+
const bld_dir = getBuildDir(cap);
|
|
12868
|
+
const bld_txt = readBldTxt(bld_dir);
|
|
12869
|
+
const eid = getEvtId(cap);
|
|
12870
|
+
const aobj = cap.analysis;
|
|
12847
12871
|
const si = aobj.sleep;
|
|
12848
12872
|
const sl_v = cap.avg_voltage;
|
|
12849
12873
|
const sl_avg = aobj.sleep.avg;
|
|
@@ -12856,31 +12880,83 @@ function mkGen(cap) {
|
|
|
12856
12880
|
const egy10_s = sl_pwr * 10 + egy1_e;
|
|
12857
12881
|
const egy10_d = egy10_s * 86400 / 10;
|
|
12858
12882
|
const ems10 = 80 / egy10_d;
|
|
12859
|
-
const
|
|
12883
|
+
const cap_date = mkTimestamp(cap.creation_date);
|
|
12884
|
+
const gen_date = mkTimestamp(/* @__PURE__ */ new Date());
|
|
12860
12885
|
const GEN = `
|
|
12886
|
+
|
|
12887
|
+
<!-- *** AUTOMATICALLY GENERATED CONTENT \u2013 DO NOT EDIT *** -->
|
|
12888
|
+
|
|
12889
|
+
<p align="right"><sub>captured on ${cap_date}<br>generated on ${gen_date}</sub></p>
|
|
12890
|
+
|
|
12891
|
+
## HW/SW Configuration
|
|
12892
|
+
|
|
12893
|
+
${brd_txt}
|
|
12894
|
+
${bld_txt}
|
|
12895
|
+
|
|
12896
|
+
|
|
12897
|
+
## EM•Scope results \xB7 ${cap.device}
|
|
12898
|
+
|
|
12861
12899
|
### \u{1F7E0} sleep
|
|
12862
12900
|
|
|
12863
12901
|
| supply voltage |  current (avg)  |  current (std)  |  average power 
|
|
12864
12902
|
|:---:|:---:|:---:|:---:|
|
|
12865
|
-
| ${sl_v.toFixed(
|
|
12903
|
+
| ${sl_v.toFixed(1)} V | ${uAmps(sl_avg)} | ${uAmps(sl_std)} | ${toEng(sl_pwr, "W")} |
|
|
12866
12904
|
|
|
12867
12905
|
### \u{1F7E0} 1 s event period
|
|
12868
12906
|
|
|
12869
12907
|
|   event energy (avg)   |   energy per period   |   energy per day   |    **EM•eralds**   
|
|
12870
12908
|
|:---:|:---:|:---:|:---:|
|
|
12871
|
-
| ${
|
|
12909
|
+
| ${uJoules(egy1_e)} | ${uJoules(egy1_s)} | ${joules(egy1_d)} | ${ems1.toFixed(2)} |
|
|
12872
12910
|
|
|
12873
12911
|
### \u{1F7E0} 10 s event period
|
|
12874
12912
|
|
|
12875
12913
|
|   event energy (avg)   |   energy per period   |   energy per day   |    **EM•eralds**   
|
|
12876
12914
|
|:---:|:---:|:---:|:---:|
|
|
12877
|
-
| ${
|
|
12915
|
+
| ${uJoules(egy1_e)} | ${uJoules(egy10_s)} | ${joules(egy10_d)} | ${ems10.toFixed(2)} |
|
|
12916
|
+
|
|
12917
|
+
## Typical Event
|
|
12918
|
+
|
|
12919
|
+
<p align="center"><img src="event-${eid}.png" alt="Event" width="900"></p>
|
|
12878
12920
|
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
`;
|
|
12921
|
+
## Notes
|
|
12922
|
+
`;
|
|
12882
12923
|
return GEN;
|
|
12883
12924
|
}
|
|
12925
|
+
function mkTimestamp(d) {
|
|
12926
|
+
const ds = d.toISOString().split("T")[0];
|
|
12927
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
12928
|
+
const HH = pad(d.getUTCHours());
|
|
12929
|
+
const MM = pad(d.getUTCMinutes());
|
|
12930
|
+
const SS = pad(d.getUTCSeconds());
|
|
12931
|
+
const ts = `${HH}:${MM}:${SS}`;
|
|
12932
|
+
return `${ds} @ ${ts}`;
|
|
12933
|
+
}
|
|
12934
|
+
function readBldTxt(bld_dir) {
|
|
12935
|
+
try {
|
|
12936
|
+
const txt = Fs3.readFileSync(Path3.join(bld_dir, "BUILD.md"), { encoding: "utf-8" });
|
|
12937
|
+
return `${txt}
|
|
12938
|
+
* [BUILD ARTIFACTS](../${Path3.basename(bld_dir)})  \u2699\uFE0F
|
|
12939
|
+
`;
|
|
12940
|
+
} catch (e) {
|
|
12941
|
+
console.log(`... skipping 'BUILD.md' inclusion`);
|
|
12942
|
+
}
|
|
12943
|
+
return "";
|
|
12944
|
+
}
|
|
12945
|
+
function readBrdTxt(brd) {
|
|
12946
|
+
const url = `https://raw.githubusercontent.com/em-foundation/emscope/docs-stable/docs/boards/${brd}.md`;
|
|
12947
|
+
const is_win = process.platform === "win32";
|
|
12948
|
+
const cmd = is_win ? "curl.exe" : "curl";
|
|
12949
|
+
const args = is_win ? ["-fsSL", "--tlsv1.2", "--ssl-no-revoke", url] : ["-fsSL", url];
|
|
12950
|
+
try {
|
|
12951
|
+
const txt = ChildProc.execFileSync(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
12952
|
+
return `${txt}
|
|
12953
|
+
* [BOARD PINOUT](https://github.com/em-foundation/emscope/blob/docs-stable/docs/boards/${brd}.png)  \u2699\uFE0F
|
|
12954
|
+
`;
|
|
12955
|
+
} catch (e) {
|
|
12956
|
+
console.log(`... skipping 'BOARD.md' inclusion`);
|
|
12957
|
+
}
|
|
12958
|
+
return "";
|
|
12959
|
+
}
|
|
12884
12960
|
|
|
12885
12961
|
// src/Exporter.ts
|
|
12886
12962
|
var import_adm_zip = __toESM(require_adm_zip());
|
|
@@ -12911,6 +12987,16 @@ function deflateLfs(repo, gpath) {
|
|
|
12911
12987
|
import_child_process.default.execFileSync("git", ["lfs", "pull", "--include", gpath], { cwd: repo, stdio: "inherit" });
|
|
12912
12988
|
import_child_process.default.execFileSync("git", ["lfs", "checkout", gpath], { cwd: repo, stdio: "inherit" });
|
|
12913
12989
|
}
|
|
12990
|
+
function fetchOid(repo, gpath) {
|
|
12991
|
+
let res = "";
|
|
12992
|
+
try {
|
|
12993
|
+
const out = import_child_process.default.execFileSync("git", ["show", gpath], { cwd: repo, stdio: ["ignore", "pipe", "ignore"] }).toString();
|
|
12994
|
+
const m = out.match(/^\s*oid sha256:([0-9a-f]{64})/m);
|
|
12995
|
+
if (m) res = m[1];
|
|
12996
|
+
} catch {
|
|
12997
|
+
}
|
|
12998
|
+
return res;
|
|
12999
|
+
}
|
|
12914
13000
|
function findRepoDir(capdir) {
|
|
12915
13001
|
let repo = "";
|
|
12916
13002
|
let dir = capdir;
|
|
@@ -12951,6 +13037,12 @@ function toggleLfs(capdir, opts) {
|
|
|
12951
13037
|
import_fs2.default.rmSync(Capture.workdir(capdir), { recursive: true });
|
|
12952
13038
|
return;
|
|
12953
13039
|
}
|
|
13040
|
+
const oid = fetchOid(repo, `:${gpath}`);
|
|
13041
|
+
fail(`'emscope-capture.zip' not yet committed`, !oid);
|
|
13042
|
+
const oid_head = fetchOid(repo, `HEAD:${gpath}`);
|
|
13043
|
+
if (oid_head && oid_head != oid) {
|
|
13044
|
+
restoreLfs(repo, gpath);
|
|
13045
|
+
}
|
|
12954
13046
|
if (desc_flag) {
|
|
12955
13047
|
deflateLfs(repo, gpath);
|
|
12956
13048
|
}
|
|
@@ -13027,10 +13119,6 @@ var DATALOSS_THRESHOLD = 500;
|
|
|
13027
13119
|
var getMaskedValue = (value, { mask, pos }) => (value & mask) >> pos;
|
|
13028
13120
|
async function execCapture2(opts) {
|
|
13029
13121
|
const path_list = await findDevices();
|
|
13030
|
-
if (path_list.length == 0) {
|
|
13031
|
-
console.error("*** no PPK2 analyzer");
|
|
13032
|
-
process.exit(1);
|
|
13033
|
-
}
|
|
13034
13122
|
const progress = new Progress("capturing: ");
|
|
13035
13123
|
const port = new import_serialport.SerialPort({ path: path_list[0], baudRate: 9600, autoOpen: false });
|
|
13036
13124
|
await new Promise((resolve, reject) => {
|
|
@@ -13040,7 +13128,7 @@ async function execCapture2(opts) {
|
|
|
13040
13128
|
port.on("data", () => {
|
|
13041
13129
|
});
|
|
13042
13130
|
const cap = Capture.create(opts.capture, opts.duration, "PPK2", opts.voltage);
|
|
13043
|
-
const ppk = new PPK2(port
|
|
13131
|
+
const ppk = new PPK2(port);
|
|
13044
13132
|
await ppk.getModifiers();
|
|
13045
13133
|
if (opts.ampereMode) {
|
|
13046
13134
|
ppk.setMode("ampere");
|
|
@@ -13049,11 +13137,26 @@ async function execCapture2(opts) {
|
|
|
13049
13137
|
ppk.setSourceVoltage(cap.voltage * 1e3);
|
|
13050
13138
|
}
|
|
13051
13139
|
ppk.togglePower("on");
|
|
13052
|
-
await ppk.
|
|
13140
|
+
await ppk.record(cap, progress);
|
|
13053
13141
|
ppk.togglePower("off");
|
|
13054
13142
|
ppk.close();
|
|
13055
13143
|
return cap;
|
|
13056
13144
|
}
|
|
13145
|
+
async function powerOn(voltage) {
|
|
13146
|
+
const path_list = await findDevices();
|
|
13147
|
+
const progress = new Progress("powering: ");
|
|
13148
|
+
const port = new import_serialport.SerialPort({ path: path_list[0], baudRate: 9600, autoOpen: false });
|
|
13149
|
+
await new Promise((resolve, reject) => {
|
|
13150
|
+
port.open((err) => err ? reject(err) : resolve());
|
|
13151
|
+
});
|
|
13152
|
+
await progress.spin(2500);
|
|
13153
|
+
const ppk = new PPK2(port);
|
|
13154
|
+
await ppk.getModifiers();
|
|
13155
|
+
ppk.setMode("source");
|
|
13156
|
+
ppk.setSourceVoltage(voltage * 1e3);
|
|
13157
|
+
ppk.togglePower("on");
|
|
13158
|
+
progress.done();
|
|
13159
|
+
}
|
|
13057
13160
|
async function findDevices() {
|
|
13058
13161
|
let res = new Array();
|
|
13059
13162
|
for (const port of await import_serialport.SerialPort.list()) {
|
|
@@ -13063,6 +13166,7 @@ async function findDevices() {
|
|
|
13063
13166
|
res.push(port.path);
|
|
13064
13167
|
}
|
|
13065
13168
|
}
|
|
13169
|
+
fail("no PPK2 analyzer found", res.length == 0);
|
|
13066
13170
|
return res;
|
|
13067
13171
|
}
|
|
13068
13172
|
function parseMods(mods) {
|
|
@@ -13077,7 +13181,6 @@ function parseMods(mods) {
|
|
|
13077
13181
|
return res;
|
|
13078
13182
|
}
|
|
13079
13183
|
var PPK2 = class {
|
|
13080
|
-
#cap;
|
|
13081
13184
|
#port;
|
|
13082
13185
|
#modifiers = {
|
|
13083
13186
|
r: [1031.64, 101.65, 10.15, 0.94, 0.043],
|
|
@@ -13103,15 +13206,14 @@ var PPK2 = class {
|
|
|
13103
13206
|
#afterSpike;
|
|
13104
13207
|
#consecutiveRangeSample;
|
|
13105
13208
|
#currentVdd = 0;
|
|
13106
|
-
constructor(port
|
|
13107
|
-
this.#cap = cap;
|
|
13209
|
+
constructor(port) {
|
|
13108
13210
|
this.#port = port;
|
|
13109
13211
|
}
|
|
13110
|
-
async
|
|
13212
|
+
async record(cap, progress) {
|
|
13111
13213
|
await progress.spin(2e3);
|
|
13112
13214
|
this.startMeasurement();
|
|
13113
13215
|
return await new Promise((resolve) => {
|
|
13114
|
-
const raw = Buffer.allocUnsafe(
|
|
13216
|
+
const raw = Buffer.allocUnsafe(cap.duration * 1e5 * 4);
|
|
13115
13217
|
let offset = 0;
|
|
13116
13218
|
this.#port.on("data", (buf) => {
|
|
13117
13219
|
progress.update(`${(offset / 1e5 / 4).toFixed(3)} s`);
|
|
@@ -13124,7 +13226,7 @@ var PPK2 = class {
|
|
|
13124
13226
|
});
|
|
13125
13227
|
this.stopMeasurement();
|
|
13126
13228
|
for (const adcVal of new Uint32Array(raw.buffer, raw.byteOffset, raw.length / 4)) {
|
|
13127
|
-
|
|
13229
|
+
cap.current_ds.add(this.#handleRawDataSet(adcVal) / 1e6);
|
|
13128
13230
|
}
|
|
13129
13231
|
resolve();
|
|
13130
13232
|
}
|
|
@@ -13269,6 +13371,10 @@ var PPK2 = class {
|
|
|
13269
13371
|
async function exec3(opts) {
|
|
13270
13372
|
let c;
|
|
13271
13373
|
if (opts.js220) {
|
|
13374
|
+
if (opts.ppk2Supply) {
|
|
13375
|
+
const voltage = opts.ppk2Supply === true ? 3.3 : Number(opts.ppk2Supply);
|
|
13376
|
+
await powerOn(voltage);
|
|
13377
|
+
}
|
|
13272
13378
|
c = await execCapture(opts);
|
|
13273
13379
|
} else if (opts.ppk2) {
|
|
13274
13380
|
c = await execCapture2(opts);
|
|
@@ -13290,7 +13396,7 @@ function saveSignal(cap, cname, span, markers = []) {
|
|
|
13290
13396
|
const msig_I = cap.current_sig.window(span.width, span.offset).toSignal();
|
|
13291
13397
|
const msig_V = cap.voltage_sig.window(span.width, span.offset).toSignal();
|
|
13292
13398
|
const data_V = msig_V.data.length > 0 ? msig_V.data : new Float32Array(msig_I.data.length).fill(cap.avg_voltage);
|
|
13293
|
-
writer.store(msig_I.data, data_V, msig_I.sample_rate);
|
|
13399
|
+
writer.store(msig_I.data, data_V, msig_I.sample_rate, Math.trunc(cap.creation_date.getTime() / 1e3));
|
|
13294
13400
|
let cobj = {
|
|
13295
13401
|
id: "joulescope.ui.waveform_widget",
|
|
13296
13402
|
version: "1.0",
|
|
@@ -13346,7 +13452,8 @@ var WriterAux = class _WriterAux {
|
|
|
13346
13452
|
this.#jfile.close();
|
|
13347
13453
|
infoMsg(`wrote '${this.cname}.jls'`);
|
|
13348
13454
|
}
|
|
13349
|
-
store(f32_I, f32_V, sample_rate) {
|
|
13455
|
+
store(f32_I, f32_V, sample_rate, utc) {
|
|
13456
|
+
utc = Date.now() / 1e3;
|
|
13350
13457
|
const sdef = {
|
|
13351
13458
|
source_id: 1,
|
|
13352
13459
|
name: "mysource",
|
|
@@ -13374,11 +13481,13 @@ var WriterAux = class _WriterAux {
|
|
|
13374
13481
|
};
|
|
13375
13482
|
this.#jfile.signalDef(sigdef);
|
|
13376
13483
|
this.#jfile.writeF32(1, f32_I);
|
|
13484
|
+
this.#jfile.setTime(1, utc);
|
|
13377
13485
|
sigdef.signal_id = 2;
|
|
13378
13486
|
sigdef.name = "voltage";
|
|
13379
13487
|
sigdef.units = "V";
|
|
13380
13488
|
this.#jfile.signalDef(sigdef);
|
|
13381
13489
|
this.#jfile.writeF32(2, f32_V);
|
|
13490
|
+
this.#jfile.setTime(2, utc);
|
|
13382
13491
|
const f32_W = new Float32Array(f32_I.length);
|
|
13383
13492
|
for (let i = 0; i < f32_W.length; i++) {
|
|
13384
13493
|
f32_W[i] = f32_I[i] * f32_V[i];
|
|
@@ -13388,6 +13497,7 @@ var WriterAux = class _WriterAux {
|
|
|
13388
13497
|
sigdef.units = "W";
|
|
13389
13498
|
this.#jfile.signalDef(sigdef);
|
|
13390
13499
|
this.#jfile.writeF32(3, f32_W);
|
|
13500
|
+
this.#jfile.setTime(3, utc);
|
|
13391
13501
|
}
|
|
13392
13502
|
};
|
|
13393
13503
|
|
|
@@ -13397,7 +13507,8 @@ var import_os = __toESM(require("os"));
|
|
|
13397
13507
|
var import_path3 = __toESM(require("path"));
|
|
13398
13508
|
function exec4(opts) {
|
|
13399
13509
|
const cap = Capture.load(opts.capture);
|
|
13400
|
-
|
|
13510
|
+
fail(`no prior analysis: run 'emscope scan ...'`, cap.analysis === void 0);
|
|
13511
|
+
const aobj = cap.analysis;
|
|
13401
13512
|
if (opts.eventInfo) {
|
|
13402
13513
|
printEventInfo(cap, aobj.events);
|
|
13403
13514
|
return;
|
|
@@ -13458,34 +13569,33 @@ function printEventInfo(cap, markers) {
|
|
|
13458
13569
|
for (const m of markers) {
|
|
13459
13570
|
const egy = cap.energyWithin(m);
|
|
13460
13571
|
avg += egy * scale;
|
|
13461
|
-
const dur = (cap.current_sig.offToSecs(m.width) * 1e3).toFixed(
|
|
13462
|
-
const dur_s = cap.current_sig.offToSecs(m.width);
|
|
13572
|
+
const dur = (cap.current_sig.offToSecs(m.width) * 1e3).toFixed(2).padStart(5, " ");
|
|
13463
13573
|
const off_s = cap.current_sig.offToSecs(m.offset).toFixed(2).padStart(5, " ");
|
|
13464
|
-
infoMsg(`${lab} :: time = ${off_s} s, energy = ${
|
|
13574
|
+
infoMsg(`${lab} :: time = ${off_s} s, energy = ${uJoules(egy)}, duration = ${dur} s`);
|
|
13465
13575
|
lab = String.fromCharCode(lab.charCodeAt(0) + 1);
|
|
13466
13576
|
}
|
|
13467
13577
|
infoMsg("----");
|
|
13468
|
-
infoMsg(`average energy over ${markers.length} event(s): ${
|
|
13578
|
+
infoMsg(`average energy over ${markers.length} event(s): ${uJoules(avg)}`);
|
|
13469
13579
|
}
|
|
13470
13580
|
function printResults(cap, aobj, ev_rate, score_only) {
|
|
13471
13581
|
const sleep_pwr = aobj.sleep.avg * cap.avg_voltage;
|
|
13472
|
-
score_only || infoMsg(`event period:
|
|
13473
|
-
score_only || infoMsg(`average sleep power:
|
|
13582
|
+
score_only || infoMsg(`event period: ${secsToHms(ev_rate)}`);
|
|
13583
|
+
score_only || infoMsg(`average sleep power: ${toEng(sleep_pwr, "W")}`);
|
|
13474
13584
|
score_only || infoMsg("----");
|
|
13475
13585
|
const egy_1s = cap.energyWithin(aobj.span) / cap.current_sig.offToSecs(aobj.span.width);
|
|
13476
13586
|
const egy_1e = egy_1s - sleep_pwr * 1;
|
|
13477
13587
|
const egy_1c = sleep_pwr * ev_rate + egy_1e;
|
|
13478
|
-
score_only || infoMsg(`representative event: ${
|
|
13479
|
-
score_only || infoMsg(`energy per period:
|
|
13588
|
+
score_only || infoMsg(`representative event: ${uJoules(egy_1e)}`);
|
|
13589
|
+
score_only || infoMsg(`energy per period: ${uJoules(egy_1c)}`);
|
|
13480
13590
|
const egy_1d = egy_1c * 86400 / ev_rate;
|
|
13481
|
-
score_only || infoMsg(`energy per day:
|
|
13591
|
+
score_only || infoMsg(`energy per day: ${joules(egy_1d)}`);
|
|
13482
13592
|
const egy_1m = egy_1d * 30;
|
|
13483
13593
|
const ems = 2400 / egy_1m;
|
|
13484
13594
|
score_only || infoMsg("----");
|
|
13485
13595
|
infoMsg(`${ems.toFixed(2)} EM\u2022eralds`);
|
|
13486
13596
|
}
|
|
13487
13597
|
function printSleepInfo(cap, si) {
|
|
13488
|
-
infoMsg(`sleep current = ${
|
|
13598
|
+
infoMsg(`sleep current = ${uAmps(si.avg).trim()} @ ${cap.avg_voltage.toFixed(1)} V, standard deviation = ${uAmps(si.std).trim()}`);
|
|
13489
13599
|
}
|
|
13490
13600
|
|
|
13491
13601
|
// node_modules/commander/esm.mjs
|
|
@@ -13509,8 +13619,8 @@ var {
|
|
|
13509
13619
|
var CAP = ["-c --capture <directory path>", "working capture directory", "."];
|
|
13510
13620
|
var VERS = version();
|
|
13511
13621
|
var CMD = new Command("emscope").option("-C, --capture-glob [name pattern]", `apply this command to each matching child capture directory (default "**")`).version(VERS);
|
|
13512
|
-
CMD.command("grab").description("record power signals with an attached capture device").option(CAP[0], CAP[1], CAP[2]).option("-d --duration <value>", "capture duration in seconds", parseFloat, 3).option("-J --js220", "use a Joulescope JS220 device").option("-P --ppk2", "use a Nordic PPK2 device").addOption(new Option("-A --ampere-mode", "enable PPK ampere mode").conflicts(["sourceMode", "js220"])).addOption(new Option("-S --source-mode", "enable PPK source mode").default(true).conflicts(["ampereMode", "js220"])).addOption(new Option("-v, --voltage [value]", "source voltage").argParser(parseFloat).default(3.3).conflicts("js220")).action((opts, cmd) => execCmd(exec3, opts, cmd.parent.opts()));
|
|
13513
|
-
CMD.command("scan").description("analyze captured data and locate active events").option(CAP[0], CAP[1], CAP[2]).option("-d, --min-duration <milliseconds>", "remove events whose duration is under a threshold", parseFloat).option("-e, --min-energy <microJoules>", "remove events whose energy is under a threshold", parseFloat).option("-g, --gap <milliseconds>", "combine adjacent events whose gap is under a threshold", parseFloat).option("-t --trim <event count>", "remove extra events", parseFloat).action((opts, cmd) => execCmd(exec, opts, cmd.parent.opts()));
|
|
13622
|
+
CMD.command("grab").description("record power signals with an attached capture device").option(CAP[0], CAP[1], CAP[2]).option("-d --duration <value>", "capture duration in seconds", parseFloat, 3).option("-J --js220", "use a Joulescope JS220 device").option("-P --ppk2", "use a Nordic PPK2 device").addOption(new Option("-A --ampere-mode", "enable PPK ampere mode").conflicts(["sourceMode", "js220"])).addOption(new Option("-S --source-mode", "enable PPK source mode").default(true).conflicts(["ampereMode", "js220"])).addOption(new Option("-p, --ppk2-supply [voltage]", "supply JS220 voltage from a PPK").argParser(parseFloat).conflicts("ppk2")).addOption(new Option("-v, --voltage [value]", "source voltage").argParser(parseFloat).default(3.3).conflicts("js220")).action((opts, cmd) => execCmd(exec3, opts, cmd.parent.opts()));
|
|
13623
|
+
CMD.command("scan").description("analyze captured data and locate active events").option(CAP[0], CAP[1], CAP[2]).option("-d, --min-duration <milliseconds>", "remove events whose duration is under a threshold", parseFloat).option("-e, --min-energy <microJoules>", "remove events whose energy is under a threshold", parseFloat).option("-g, --gap <milliseconds>", "combine adjacent events whose gap is under a threshold", parseFloat).option("-t --trim <event count>", "remove extra events", parseFloat).option("--refresh", "(re-)scan using the last set of options").action((opts, cmd) => execCmd(exec, opts, cmd.parent.opts()));
|
|
13514
13624
|
CMD.command("view").description("present captured data in different formats").option(CAP[0], CAP[1], CAP[2]).option("-e --event-info", "characterize power consumption when active").option("-j --jls-file [event ID]", "generate a Joulescope .jls file containing events").option("-s --sleep-info", "characterize power consumption when inactive").option("-w --what-if [event period]", `extrapolate results for a given event period (default: '00:00:01')`, parseHms).option("--score", "only print the EM\u2022eralds benchmark score").action((opts, cmd) => execCmd(exec4, opts, cmd.parent.opts()));
|
|
13515
13625
|
CMD.command("pack").description(`bundle captured data into an 'emscope.zip' file`).option(CAP[0], CAP[1], CAP[2]).option("-a --about-file", `update the 'ABOUT.md' file only`).option("-s,--status", `status of the 'emscope.zip' file`).option("-u --unpack", `deflate the 'emscope.zip' file for local use`).option("-z --zip-file", `generate the 'emscope.zip' file`).option("--restore", `restores the 'emscope.zip' LFS descriptor (debug only)`).action((opts, cmd) => execCmd(exec2, opts, cmd.parent.opts()));
|
|
13516
13626
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@em-foundation/emscope",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.3.0",
|
|
4
4
|
"description": "benchmark energy efficiency in resource-constrained embedded systems",
|
|
5
5
|
"bin": {
|
|
6
6
|
"emscope": "dist/emscope"
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"bugs": {
|
|
33
33
|
"url": "https://github.com/em-foundation/emscope/issues"
|
|
34
34
|
},
|
|
35
|
-
"homepage": "https://github.com/em-foundation/emscope/blob/
|
|
35
|
+
"homepage": "https://github.com/em-foundation/emscope/blob/docs-stable/docs/ReadMore.md",
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@serialport/bindings-cpp": "^13.0.1",
|
|
38
38
|
"@types/adm-zip": "^0.5.7",
|
|
39
39
|
"@types/js-yaml": "^4.0.9",
|
|
40
40
|
"adm-zip": "^0.5.16",
|
|
41
41
|
"commander": "^14.0.0",
|
|
42
|
-
"jls-writer": "https://github.com/em-foundation/npm-packages/releases/download/resources/jls-writer-0.0.
|
|
42
|
+
"jls-writer": "https://github.com/em-foundation/npm-packages/releases/download/resources/jls-writer-0.0.3.tgz",
|
|
43
43
|
"joulescope_driver": "^1.10.0",
|
|
44
44
|
"js-yaml": "^4.1.0",
|
|
45
45
|
"picomatch": "^4.0.3",
|
|
@@ -50,4 +50,4 @@
|
|
|
50
50
|
"@types/picomatch": "^4.0.2",
|
|
51
51
|
"esbuild": "^0.25.8"
|
|
52
52
|
}
|
|
53
|
-
}
|
|
53
|
+
}
|