CHANGELOG#
This file contains the list of changes made to the Joulescope driver.
2.5.5#
2026 Oct 25 [in progress]
Updated documentation for doc.joulescope.com deployment.
2.5.4#
2026 Oct 16
Added Python 3.15 support.
Changed the Python package license metadata to an SPDX license expression.
2.5.3#
2026 Oct 16
Fixed opening a device that another process holds on Windows. The open failed with
1 UNSPECIFIED, and now fails at once with21 IN_USE, as on Linux and macOS since 2.5.1. The WinUSB backend now maps the Windows error code, which it also logs, to a jsdrv error code.Fixed the measure entry point on the JS110, which always exited with
PARAMETER_INVALIDfors/i/range/mode. On the JS110, that topic is the range suppression mode, so the entry point now selects the range withs/i/range/select, as the record and statistics entry points do.
2.5.2#
2026 Oct 15
Added jsdrv_is_driver_thread() and Driver.is_driver_thread(), which report whether the caller is the driver thread that invokes the subscriber callbacks. The driver has always forced commands issued from that thread to timeout 0, since a wait there would deadlock. This is now the documented behavior: a callback may call the driver with any timeout, and the command runs in order but reports its result only to the log. The log message for a forced timeout dropped from warning to info.
Fixed Driver.unsubscribe() and unsubscribe_all() from a callback. They treated the forced, asynchronous unsubscribe as confirmed and released the callback reference while C could still call it.
The libusb backend no longer warns “zero length bulk in transfer” at the end of a JS320 stream. The JS320 terminates its last bulk IN transfer with a zero-length packet, which arrives alone in about 1 of 12 stops. The message is now debug level and names the device and endpoint, as the WinUSB backend already handled this case silently.
The Python binding decodes the MB_STDMSG_TIMESYNC_MAP stdmsg, which the JS320 publishes on s/ts/!map, into a dict with the counter to UTC map, the sync exchange that last updated it, and the update counter. This exposes the sensor’s time synchronization to tools: a JS320 sensor clock 268 s behind the host was the cause of a three-instrument read that never completed.
2.5.1#
2026 Oct 13
Fixed a memory leak on Linux and macOS: each unplug of an open device kept its pool of USB transfers, 175 to 345 KB, until the driver finalized. Over 8 hours with 92 unplugs, a logger grew by 19 MB.
Fixed opening a device that another process holds. On Linux and macOS, the open now fails at once with
IN_USE, instead of an unnamed libusb error code, such as-6 UNKNOWN, on the JS110 and JS220, and a timeout on the JS320. Each failed open also leaked a USB file descriptor until the process exited. Windows still reportsUNSPECIFIED; see pyjoulescope_examples doc/windows_test_plan.md.The record, statistics and measure entry points now stop and exit 1 with “
removed: stop” when their device is unplugged. They kept running without data until Ctrl-C, and measure waited forever. Record.close() now logs a warning without a traceback when it cannot stop a signal, such as after an unplug. The file still closes.
Record now stops writing after the first JLS write error, such as a full disk, and logs it once, instead of raising in every data callback. Record.close() always releases the writer and raises RuntimeError when the file may be incomplete; pyjls 0.19.0 reports these errors. The record entry point prints “ERROR: recording may be incomplete” and exits 1.
2.5.0#
2026 Oct 9
Upgrade notes. Most applications need no changes. Check these:
JS220
defaultsopen now resets settings. Set what you need after open, or open withmode='restore'.Command-line tools select devices with
--device. set and statistics drop their positional device, threads-dnow means--device, and info no longer shows values: use the newvalues.Statistics
charge_i128/energy_i128(int_value) now use a 2**-52 scale on every model. The f64 fields are unchanged.device_filterAPI replaced (2.4.3 is yanked), andDriver.device_paths()takes specs first: pass timeout by keyword.Errors are louder. Unreceived publish errors now log at ERROR, and the host no longer retains values that the device rejected.
Driver.finalizecloses the devices it opened, and later calls raise RuntimeError.
This release also fixes intermittent JS110 crashes on Windows and several JS320 streaming gaps. Details follow.
JS220 behavior change: a defaults open now restores the default
settings. Previously, opening a JS220 in defaults mode (the default
mode, also used when mode is None) pushed nothing to the instrument. The
JS220 kept every setting from the previous session, such as
s/i/range/min, s/i/range/max, s/v/range/select and s/stats/scnt,
until it was power cycled, while the host reported no values for them.
A defaults open now pushes each writable device topic’s metadata default,
or the host’s retained value from the same Driver session, then reads the
device state back to the host, matching the JS320. Streaming stays off.
Scripts that rely on settings from a previous session must now set them
explicitly, or open with mode='restore' to keep the instrument’s current
settings. See
#16.
Signed the Windows executables (jsdrv.exe, minibitty.exe and the other example tools), jsdrv.dll and the Python extension module in the Windows wheels in main and release builds, so Windows Smart App Control does not block them.
Added DevicePath, a str subclass with backend, model, serial_number, brand and is_bootloader properties and a match(spec) method. Driver.device_paths() now returns DevicePath instances, which remain fully str compatible. A device in bootloader mode, such as “u/&js220/000415”, has the same model and brand as in application mode. Model specifications, such as “js220”, match both modes, and the “&” forms, such as “&js220”, only match bootloader mode.
Added optional specs and brand arguments to Driver.device_paths(), such as d.device_paths(‘js320’, brand=’joulescope’). Brands are case-insensitive and support aliases, such as “js” for “Joulescope”. The new first argument is specs, so pass timeout by keyword. A numeric first positional argument is still treated as timeout, with a DeprecationWarning.
Added Driver.find_one_device(specs, brand), which returns the single matching DevicePath or raises DeviceFilterError, and Driver.find_devices, an alias for Driver.device_paths.
Added Driver.device_watch(on_add, on_remove, specs, brand), which calls on_add for each connected device, then on_add and on_remove for each matching device addition and removal, with a DevicePath argument.
Driver.open now returns a DeviceContext, which accepts topics relative to the device. Its close, including on context exit, unsubscribes all subscriptions made through it and then closes the device: “with d.open(device_path) as device: device.publish(‘s/i/range/mode’, ‘auto’)”.
Driver.subscribe now returns a SubscribeContext, which unsubscribes on unsubscribe() or on exit: “with d.subscribe(topic, ‘pub’, fn): …”.
When a DeviceContext or SubscribeContext block raises, a close or unsubscribe error on exit is logged instead of replacing the block’s exception.
Publish errors that no caller receives now log at ERROR level, such as “publish u/js320/8W2A/s/nope failed: 16 NOT_FOUND” for a publish with timeout=0. MiniBitty-based devices, including the JS320, now confirm every publish so that device-side errors, such as an unknown topic, always return. Use a blocking publish to raise the error instead.
The Python Driver now defaults the native log level to “error” (was “off”), so these errors reach the Python “jsdrv” logger.
Fixed the host retaining a value that a device rejected. The rejected value is no longer cached: the previous value is restored and published to subscribers, or cleared when none existed. Previously, a query returned the rejected value, and publishing the same value again succeeded without reaching the device. A CLOSED device still keeps the value for the next “defaults” open.
Driver.finalize, including exiting “with Driver() as d:”, now closes each device that the instance opened and that is still connected. Afterwards, close, unsubscribe and unsubscribe_all do nothing, and the other methods raise RuntimeError. They previously crashed.
Driver topic and device_prefix arguments now accept str subclasses, such as DevicePath, and raise TypeError with the argument name for other types. open and close raise ValueError for an empty device_prefix.
The entry points now select devices with “–device” / “-d”, which takes device specifications, such as “js320” or “8W2A”.
The generic entry points, info, mem_test, metadata, program, scan, set, threads and values, match all devices and add an optional “–brand”, such as “–brand js”. program and metadata now report multiple devices when a non-Joulescope device, such as a MiniBitty, is also connected.
The Joulescope entry points, gpi, measure, record and statistics, only match Joulescope devices.
BREAKING: set and statistics replace their positional device argument with –device.
BREAKING: info now only displays system, package and device summary information, and –device and –brand filter the devices. Use the new “values” entry point to display the current values for one device, which info previously displayed with a positional device argument.
BREAKING: threads replaces “-d” for “–duration” with “–device”.
program –device-path and record –serial_number remain as aliases.
Updated the C example device matching (example/common/device_match.c) to match pyjoulescope_driver.device_filter: comma-separated specifications, “{model}-{serial_number}”, and brands with aliases. The pre-2.5.0 backend/model prefix, “u/js320” or “u/js320/”, remains a valid specification in both. Added device_is_bootloader, and the model functions ignore the “&” bootloader prefix, like DevicePath. minibitty fuzz_fwup now defaults to “js320”.
Added doc/getting_started.md (Python and C lifecycle, command-line tools, model differences, pitfalls), doc/streaming_topics.md (statistics and streaming payload formats), example/quickstart.c (minimal C program using only the public API, built as jsdrv_quickstart), and the JS320 topic reference doc/js320.json.
BREAKING: jsdrv_statistics_s charge_i128 and energy_i128 now use a 2**-52 scale on every model, defined as JSDRV_STATISTICS_I128_Q. The JS320 already produced 2**-52, but the JS110 and JS220 produced 2**-31, and pyjoulescope_driver int_scale claimed 2**-31 for charge and 2**-27 for energy on every model. The f64 fields are unchanged.
Fixed pyjoulescope_driver statistics int_value, which was wrong for negative accumulators and for values with bit 63 set.
Added tools/stats_i128_scale.py, which measures the int_value scale against the f64 fields on a connected Joulescope.
Added the device selection, DeviceContext and SubscribeContext API documentation, and documented that applications must finalize each Driver, with a context manager or by calling finalize().
Improved pyjoulescope_driver.device_filter module
BREAKING: Replaced the 2.4.3 functions. 2.4.3 is yanked. Use the module as a namespace with “from pyjoulescope_driver import device_filter”.
device_filter -> find
device_match -> DevicePath.match
device_model -> DevicePath.model
is_joulescope -> DevicePath.brand == ‘Joulescope’
find and find_one now match all devices by default, including non-Joulescope devices. Use brand=’joulescope’ to match only Joulescope instruments.
Added find_one, which returns the single matching DevicePath or raises DeviceFilterError, a ValueError, on zero or multiple matches.
Added comma-separated device specification strings to find, such as “31NB,js220”.
Added “{model}-{serial_number}” device specifications, such as “js320-31NB”, and “{backend}/{model}” specifications, such as “u/js320/” for every JS320 on USB, to DevicePath.match.
Fixed memory leaks and undefined behavior found by AddressSanitizer and UndefinedBehaviorSanitizer, and added a CI job that runs the C unit tests with both:
A JS320 leaked its partial sample messages when removed while streaming or when stream data arrived after close.
The libusb backend leaked its pooled USB transfers on exit.
Each initialize after the first leaked the heap mutex, and replaced it while other threads could hold it.
A thread join that timed out leaked 16 bytes.
Fixed signed shift overflow in the JS220 stream suspend and resume.
A JS110 leaked one message for each status poll while applying stream or extio settings, about 10 per capture.
Metadata that overflowed its JSON buffer formed a write pointer past the end of the buffer.
Buffer allocation with no active signals cast an infinite duration to int.
Fixed “jsdrv_bufsig_process_request info unavailable” warnings in the Joulescope UI when an instrument connects while another streams. Adding a signal resets the memory buffer, so requests already sent for the other signals found no data. The reset now drops pending requests, a request for a signal without data logs at INFO, and “signal add” and “signal remove” log the signal index instead of 0.
Replaced the “mbg/” sentinel that ended the
defaultsopen gather of host values with a pubsub subscribe completion. Applications no longer receive “mbg/…” publishes, and concurrent JS320 opens no longer share sentinel topics.Fixed Python Driver.subscribe(‘’) and unsubscribe(‘’) raising IndexError. The empty (root) topic subscribes to all publishes, as in the C API.
Fixed JS320 streams mislabeling about 3 ms of samples at the old sample rate when h/fs changes within 500 ms of a stream stop, such as a stop, h/fs change and restart. Requires no firmware update.
Fixed h/fs, h/fp, h/i_scale and h/v_scale having no host value after a JS320 open until the application set them, and h/fs and h/fp after a JS220 open. A JS320 restore open now reports the instrument’s rate.
Fixed a JS320 stream stop and immediate restart sometimes starting with the previous stream’s last frames, followed by a gap. Requires JS320 firmware with s/i/!ack, s/v/!ack and s/p/!ack; older firmware behaves as before.
Fixed JS320 streams dropping up to 2 s of samples, with a “!ack timeout” warning, after an h/fs change that kept the same instrument decimation, such as 5 Hz to 10 Hz.
Fixed a use-after-free in Driver.finalize() and device close after a JS110 streamed, the likely cause of intermittent access violations on Windows. A device thread busy with stream data never checked for the finalize command, so the 10 s join timed out and freed the device under the running thread. Device threads now check for commands every 64 stream messages, and a join timeout leaks the device instead.
Fixed an access violation on Windows when a device closes while a USB control transfer is in flight, such as a JS110 status poll. Freeing the WinUSB handle aborted the transfer, and the device thread then completed it with the freed handle. Close now cancels and waits for the transfer in flight, and answers each queued control transfer with JSDRV_ERROR_CLOSED. This was the remaining cause of intermittent crashes when a program stopped a JS110 with Ctrl-C.
An open now completes when the device drops off the bus during the open and enumerates again. The frontend retries the open on the re-added device and extends the open timeout to at least 3 s after the removal. Previously, the open timed out. On Windows, a JS320 does this when an open resumes its port within about 0.5 ms of USB selective suspend starting, such as a reopen 2 s after a close: the USB core then falls back to full speed, and Windows enumerates it again. Applications that watch device additions and removals still see the removal and addition.
The Windows backend now retries WinUsb_Initialize for up to about 200 ms when it fails with ERROR_BUSY, which Windows can return while it resumes a selectively suspended device. Previously, the open failed.
Increased the Python Driver.open default timeout from 1 s to 3 s, and added JSDRV_TIMEOUT_MS_OPEN for C callers. After a program exits without closing a JS320, the next open can take more than 1 s while the instrument recovers. An open that timed out then exited during the state read, which left a JS320 with older firmware refusing state reads until reset.
Fixed a JS110 open reporting h/fs as 2 MHz after the application set another rate.
Fixed a libusb backend log message that could crash at INFO level.
Added “jsdrv stream_watch –cycles” to stop and restart streams and report sample_id skips per cycle, and stream sample_id and rate checks to the fuzz example.
2.4.3#
2026 Oct 6
Added SPDX headers and REUSE.toml for REUSE compliance and SBOM generation. CI runs “reuse lint” and attaches the SPDX SBOM to each GitHub release.
Added offline topic metadata for documentation.
Moved JS320 host-side and buffer manager metadata into declarative jsdrvp_param_s tables, extracted into the packaged host_params.json.
Added metadata for the per-buffer and per-signal m/ topics.
Added “metadata –firmware” to generate the topic reference from firmware build outputs without a device, and “metadata –diff” to verify it against a connected device.
Fixed pyjoulescope_driver “info” entry point to use open restore by default.
Fixed pyjoulescope_driver “record” entry point to support the JS320. It also warns when “–open restore” leaves the JS220 or JS320 current range off.
Fixed JS320 current reading about 0 A in pyjoulescope_driver “statistics” and jsdrv “statistics” and “capture”. They now set s/i/range/mode to “auto”, and “statistics” now applies –frequency on the JS320.
Fixed four “fwup/…” device_lookup warnings logged at every startup. The frontend now publishes backend fwup/ topics directly.
Fixed device selection to ignore non-Joulescope devices, such as a MiniBitty at u/mb/{serial}. The pyjoulescope_driver entry points, jsdrv and minibitty now accept a device path, model or exact serial number. “record –serial_number 1” no longer matches serial number 31.
Fixed an intermittent access violation (0xC0000005) when a device closes from pyjoulescope_driver or joulescope.v1, on every model. Driver.close left the app field of its i32 value uninitialized, and jsdrvp_msg_free treated a stale app of BUFFER_INFO or BUFFER_RSP as a buffer pointer. Driver.close and Driver.query now zero the value, and jsdrvp_msg_free reads app only for binary values.
Fixed a pyjoulescope_driver use-after-free. Driver.unsubscribe with a new bound method object, such as obj.method accessed again, left the C callback subscribed to a freed object, which caused an access violation on the next publish. Driver now unsubscribes the registered object and holds each callback until C confirms the unsubscribe.
Fixed jsdrv_finalize freeing the context while the frontend thread still runs after a join timeout. Driver.finalize now uses the C default timeout instead of 1 second, and finalize twice is safe.
Fixed JS220 memory operations (h/mem/…/!read, !write, !erase).
Fixed a buffer leak on every completed read or write. mem_complete cleared the state with the size of the wrong field, which also zeroed the data pointer before it could be freed.
Fixed a !write larger than 512 KB never publishing its return code, so the caller waited for its timeout. It now returns JSDRV_ERROR_PARAMETER_INVALID immediately.
Added js220_usb_test unit tests for memory operations and the host-side parameters.
Cleaned up unused API surfaces.
Documented the jsdrv_initialize() args parameter as reserved: pass NULL. No arguments are defined, and the driver ignores it. The signature is unchanged.
Removed the unimplemented stream buffer “g/mode” topic definition and the unused “s/ZZZ/…” placeholder topic macros from the private buffer header. A publish to “g/mode” still returns JSDRV_ERROR_PARAMETER_INVALID.
Consolidated the open review items into doc/plans/open_issues.md and moved the pubsub request suffix and subscribe flag cleanup to doc/plans/pubsub_api.md.
Fixed msg_queue message removal before taking mutex.
2.4.2#
2026 Oct 5
Fixed MiniBitty bool topics (JS320 s/i/ctrl, s/gpi/0/ctrl, …) rejecting “on”/”off”. The metadata parser now reports dtype “bool” for u8 entries with dtype bit 7 (MB_PUBSUB_META_DTYPE_BOOL) set, so values accept case-insensitive true/false strings. Unknown entry flags no longer emit “flags”: [].
Improved Claude guidance.
Bumped JS320 firmware from 1.1.8 to 1.1.10
2.4.1#
2026 Aug 25
Added JS320 support to “pyjoulescope_driver measure”.
Added “metadata” entry point to pyjoulescope_driver.
Fixed metadata parsing.
Skip a topic whose reconstructed JSON exceeds the 2048-byte buffer rather than publishing the truncated, unparsable remainder.
Bounded the option array walk and the default value read by the entry size; a corrupt blob could read past the entry.
2.4.0#
2026 Aug 4
Performed a full design review focused on incomplete and partially complete features; findings and remaining work are tracked in doc/plans/design_review_2026-07.md.
Repurposed jsdrv_statistics_s reserved rsv3_u32 as decimate_factor32. The u8 decimate_factor truncated for JS320 (e.g. 256 -> 0) and now saturates at 255; consumers should prefer decimate_factor32 and fall back to decimate_factor when it reads 0 (older producers).
Fixed memory buffer (stream buffer) issues.
Fixed process abort when buffering signals with unsupported element types (JS320 s/adc/N/!data INT32, s/uart/!data UINT8); the signal is now rejected gracefully and removed from the signal list.
Fixed u1/u4 write path bit alignment: message lengths that left the ring at a sub-byte offset silently corrupted all subsequent samples.
Fixed skip-fill zero fill, which mixed sample and byte units.
Bounded time map growth over long captures: expiration now runs as the ring wraps (previously unbounded with an O(N) copy per message).
Implemented the documented g/hold clear on the 1 -> 0 transition.
Fixed request pool leak on failed requests and the finalize off-by-one that leaked buffer id 16’s thread on shutdown.
Fixed JS220 issues.
Fixed h/i_scale and h/v_scale, which were broken: the metadata published without the $ suffix (JSON became the retained value) and the handler read the unconverted union value.
Rejected h/fs=0 and h/fp=0 (divide-by-zero) and invalid h/filter values; sinc1 now rejects on firmware/FPGA < 1.3.0 instead of desynchronizing host and instrument decimation.
h/fs coercion (sinc1 signal_n 2/3 forced to 4) now logs and republishes the actual rate.
Fixed JS110 issues.
Fixed statistics max initialization (-FLT_MAX, not FLT_MIN), which reported max ~0 for always-negative signals; all-NaN blocks now report NaN instead of dividing by zero; rejected s/stats/scnt=0.
Fixed NaN current-range suppression to NaN exactly the window samples (previously 2*window+post, including the samples the mean/interp estimates depend on).
Restored missing-sample fill on USB packet skips (up to 512 frames) so sample_id, the time map, and statistics stay wall-clock aligned.
Validated the current-range suppression parameters against the sample processor limits.
Fixed JS320 issues.
Rejected s/dwnN/N above the 1000 register maximum and s/gpi/+/dwnN/mode above 3.
Rejected statistics messages with decimate=0 (divide-by-zero).
Fixed C core issues.
Fixed log level name table (missing commas): levels 5-8 reported wrong names and 9-10 returned NULL.
Fixed jsdrv_union_value_to_str for f32/f64/null (wrote nothing, leaving log buffers uninitialized) and u64/i64 (truncated to 32-bit).
Fixed jsdrv_union_as_type f64 conversions, which rejected all negative values for signed targets and limited u64/i64 to 32-bit.
jsdrv_union_eq now compares STDMSG/FRAME payloads (pubsub deduplication never applied to them).
Hardened JSON parsing: literals are now actually compared (“txyz” parsed as true), integers parse to i64 with overflow rejection, and nesting depth is bounded (metadata is untrusted device input).
Fixed metadata range parsing buffer overflow on malformed ranges.
Fixed frontend NULL dereference when subscribing to a removed device, and a dangling device list node on factory failure.
Fixed backend and mb_device issues.
Bounded the libusb shutdown wait at 10 s (previously could hang process exit forever if a device never went idle).
Fixed libusb bulk_in_close endpoint id mismatch (latent).
POSIX driver threads now sleep for the scheduled timeout instead of busy-polling every 2 ms.
Fixed POSIX msg_queue_pop_immediate, which reset the wakeup event while later messages remained queued. A burst of two or more responses stranded the tail until the next push or timeout; once the 2 ms busy-poll no longer masked it, this caused ~1 s stalls, JS220 open timeouts, and close() returning JSDRV_ERROR_TIMED_OUT after fire-and-forget publishes (issue #13’s remaining symptom). Now matches the WinUSB queue: reset only when the queue empties. Added msg_queue_test.
POSIX event pipe: the signal end is now nonblocking and reset drains until empty. Sustained streaming wrote one wakeup byte per msg_queue_push while resets ran only when a queue emptied, so the pipe could fill (64 KiB) and a blocking write then wedged the producer – the libusb backend thread – stalling every device until the instrument’s host-silence watchdog rebooted it. Dropped writes on a full pipe are safe: the pipe is already poll-readable. Added a regression test.
libusb now issues a bulk OUT clear_halt on the first OUT of each open session, and WinUSB resets the bulk OUT pipe on first use per open (Windows HIL validation pending). This re-synchronizes the device’s data toggle for fielded firmware with the stub SET_INTERFACE handler (fixed in MiniBitty 2026-08), which otherwise hardware-discarded the session’s first OUT packet as a duplicate, costing one 250 ms link retransmit per open (measured raw-open worst case 258 ms -> 8.3 ms on NUCLEO-C542RC with old firmware).
mb_device now answers device-initiated link PINGs with PONG and rejects device publishes with JSDRV_ERROR_CLOSED while not open.
Fixed host process abort (exit from JSDRV_ASSERT) when a MiniBitty-link device died mid-stream and re-enumerated: the libusb retired-slot drain echoed returned stream-buffer loans back as STREAM_IN_DATA messages with an i32 error value, and mb_device kept draining past the LL_TERMINATED sentinel into the forged message. The drain now reclaims loans (also fixing a transfer leak), mb_device stops at the sentinel like js110/js220, and non-BIN STREAM_IN_DATA messages are dropped instead of asserted fatal (guard now also in js110/js220 and the libusb loan-reclaim path). The retired-slot drain now frees other late messages instead of echoing error responses that could only dead-letter into the slot’s next session behind the sentinel.
Fixed pyjoulescope_driver issues.
Fixed Record for u1/u4 signals (current_range, gpi, trigger_in): only fsr_f32 was ever called, so these recorded garbage.
Fixed Record multi-device open, which subscribed every signal once per device and duplicated every JLS write; close() is now idempotent. Added record round-trip unit tests.
statistics CLI now supports the JS320; measure CLI returns a consistent dict, supports the JS110, and survives early interrupt; info CLI reports JS320 versions; threads CLI filters to JS220.
Exported TimeMap; corrected the open ‘defaults’ docstring to the 2026-06 semantics.
Fixed node_api issues.
Implemented the stream buffer info/response converters, which returned undefined; unknown binary payloads now convert to Uint8Array.
Fixed the test to actually fail on error and run it in CI.
Removed the dead src/emu.c / src/emulated.c skeleton (never compiled); a fresh emulated-device design is proposed in doc/plans/emulated_device.md.
Registered dbc_test and boot_info_test with ctest; removed the dead test_invariant_tmap.c.
Fixed pytest suite errors.
Updated embed_js320_firmware tests to the released list-format index.json (the tool moved to it in 2.0.7); the tool now reports the friendly error for an empty index instead of IndexError.
Excluded the standalone test/hw scripts from pytest collection; run them directly with JSDRV_HW_DEVICE set.
Fixed README Python requirement (3.12+) and published the JS220 topic reference and JS320 calibration/firmware-update docs on the docs site.
2.3.5#
2026 Jul 31
Fixed JS320 h/fs downsampling.
Remove 2000000 default, which is unsupported.
Added host-side downsampling for < 1 kHz: instrument decimates to 1 kHz, host applies a sincN filter matched to s/dwnN/mode.
Track s/dwnN/mode; bypass now reports the true decimate_factor.
Fixed Minibitty adapter Tracy integration for trace.
Fixed mb_device to ack close requests while already closed, so jsdrv_close() completes instead of timing out.
2.3.4#
2026 Jul 17
Fixed host sleep/resume recovery on Linux (and unclean-close recovery on all platforms).
Fixed mb_device open-time
!staterestore: full SET_CMD chunks exceeded the frame payload limit after the publish wrapper was added and were silently dropped, so device state leaked from a prior session survived open. This caused the “only power displays until a second restart” symptom after an unclean session end. Oversized publishes now log an error instead of vanishing.libusb backend: a device that dies without a hotplug event (Linux reset-resume after host sleep force-unbinds usbfs; no LEFT/ARRIVED fires) is now torn down properly and re-discovered by a bounded timed rescan, so clients can reconnect without an app restart.
mb_device link-silence supervision: sustained RX silence while the keep-alive is active now triggers the same link revalidation and handshake replay as the Windows host-resume power event, recovering a session whose device link was wiped by a resume bus reset. This is OS-agnostic and also covers macOS sleep.
h/link/keep=0disables it together with the keep-alive.Host-crash recovery is unchanged: a killed host with an active bus still causes the device comm-watchdog reset and re-enumeration.
Added
jsdrv stream_watchexample: watch i/v/p streams and log per-second JSON evidence for sleep/resume and recovery testing.Added mb_device unit tests (state chunking, silence supervision).
2.3.2#
2026 Jul 15
Fixed USB suspend/resume handling.
mb_device announces host SLEEP_REQ so the firmware can release its host-inactivity watchdog.
Add PING keepalive.
winusb backend forwards WM_POWERBROADCAST suspend/resume to open devices.
mb_device revalidates the link on resume (ping) handshake when the device re-enumerated (Windows resets the bus on resume from S3), restoring streaming without a close/reopen.
Bundled JS320 firmware 1.1.5, which supports SLEEP_REQ.
Added
--timeoutoption to the minibitty stream example and made its no-data monitor host-sleep aware (measures post-wake stream recovery).
2.3.0#
2026 Jun 26
Fixed current reading stuck at ±2.2A max on some JS320 units.
Bumped JS320 from 1.1.2 to 1.1.3 which reduced current overflow from almost 100% to 95% of ADC max.
Dropped support for Python 3.11 and earlier. See NEP 29.
2.2.12#
2026 Jun 18
Fixed occasional 1 sample glitch on JS320 current autoranging.
Bumped JS320 from 1.1.1 to 1.1.2
2.2.11#
2026 Jun 18
Force s/dwnN/N 2 & 3 to 4.
Fixed JS320 open race condition.
Fixed JS320 current and voltage scaling.
Added missing tmap bounds check.
Bumped node.js package lock versions.
2.2.10#
2026 Jun 17
Fixed state synchronization on device open.
Bumped JS320 firmware to 1.1.1.
Added host topic metadata.
2.2.9#
2026 Jun 15
Migrated GitHub action to use “Visual Studio 18 2026”
2.2.8#
2026 Jun 14
Bumped JS320 firmware to 1.0.7.
2.2.7#
2026 Jun 9
Changed JS320 flash organization to support production 1.0.3+ units.
2.2.6#
2026 Jun 8
Changed JS320 flash organization to support production 1.0 units.
Removed erase slot 0 hack for JS320 firmware < 1.0.
2.2.4#
2026 Jun 1
Improved minibitty info command.
Bumped JS320 firmware to 0.6.4.
2.2.3#
2026 May 30
Fixed WARNING log entries on Window’s device close.
Fixed WARNING log message on USB reconnect.
2.2.2#
2026 May 30
Improved JS320 calibration logging.
2.2.1#
2026 May 29
Modified offset calibration to save/restore state once, not every point.
2.2.0#
2026 May 29
Added JS320 current and voltage offset calibration.
2.1.2#
2026 May 28
Added fwup/js320/version topic to JS320 devices to support introspection.
Bumped node.js dependencies.
2.1.1#
2026 May 26
Fixed small errors introduced by buffer_signal.c for JS320
Quantization error on standard deviation
Correctly weight summaries by number of samples rather than equal weight
2.1.0#
2026 Apr 27
Added Windows 11 ARM build.
2.0.7#
2026 Apr 27
Improved firmware update for the JS320.
Added pyjoulescope_driver program support for JS320.
Improved JS320 fwup progress reporting.
2.0.6#
2026 Apr 25
Fixed firmware update.
Modified JS320 fwup to use image slot 1 in external SPI flash.
Switched to RAW open mode.
2.0.5#
2026 Apr 24
Added latest stable JS320 firmware to image on release.
fwup/@/!add: response payload changed from int32 rc to an 8-byte struct
{int32_t rc, uint32_t worker_id}so callers can subscribe to the specificfwup/NNN/statustheir request spawned. zip_size of 0 in the add header now uses the JS320 firmware embedded in the driver instead of caller-supplied bytes; stub builds return JSDRV_ERROR_UNAVAILABLE.example/minibitty fwup: accept
-as the package path to program with the driver’s embedded firmware.Improved RAW open mode support.
Fixed example minibitty firmware and fpga_mem to open in RAW mode.
2.0.4#
2026 Apr 21
Fixed SEGFAULT on macOS and crash on Linux detected by fuzz test.
2.0.3#
2026 Apr 20
Breaking API changes#
jsdrv_stream_signal_s: added 8-byte preamble (version + reserved) so sample_id stays 8-byte aligned. JSDRV_STREAM_HEADER_SIZE changed from 48 to 56. All consumers that depend on the struct layout must be rebuilt.
Switched tmap to copy-on-publish. Removed jsdrv_tmap_ref_incr, jsdrv_tmap_ref_decr, jsdrv_tmap_reader_enter, and jsdrv_tmap_reader_exit. Added jsdrv_tmap_free and jsdrv_tmap_copy. jsdrv_buffer_info_s.tmap is now a consumer-owned snapshot that the consumer must free with jsdrv_tmap_free().
jsdrv_calibration_hash now returns int32_t (was void). Returns JSDRV_ERROR_PARAMETER_INVALID when msg or hash is NULL, or when length is 0 or not a multiple of 32 bytes.
jsdrv_subscribe: flags == 0 is now treated as the common default (JSDRV_SFLAG_PUB | JSDRV_SFLAG_RETAIN) instead of subscribing silently to nothing. Callers who want no callbacks (rare) must pass a non-zero mask that excludes JSDRV_SFLAG_PUB.
jsdrv_log_publish: level parameter type changed uint8_t -> int8_t to match the rest of the log API and preserve the signed JSDRV_LOG_LEVEL_OFF = -1 value.
jsdrv_thread_create: priority parameter type changed int -> int32_t.
jsdrv_thread_is_current: parameter type changed jsdrv_thread_t const * -> const jsdrv_thread_t *.
error_code.h: jsdrv_error_code_name and jsdrv_error_code_description parameter type changed int -> int32_t.
cstr.h: every return type changed int -> int32_t; every char const * parameter changed to const char *.
jsdrv_statistics_s.rsv3_u8 field renamed to rsv3_u32 to match its uint32_t type.
Header guard macros JSDRV_OS_H_ renamed to JSDRV_OS_H to avoid ISO C §7.1.3 reserved identifiers.
os_thread.h macros THREAD_RETURN_TYPE / THREAD_ARG_TYPE / THREAD_RETURN() renamed to JSDRV_THREAD_RETURN_TYPE / JSDRV_THREAD_ARG_TYPE / JSDRV_THREAD_RETURN() to remove global-namespace pollution.
New APIs#
jsdrv_union_copy() — copy a jsdrv_union_s into caller-owned storage; safe replacement for aliasing callback pointers.
jsdrv_tmap_free(), jsdrv_tmap_copy() — replace the ref-counted lifetime and reader/writer sections.
JSDRV_TIMEOUT_MS_ASYNC constant (value 0) for self-documenting asynchronous calls.
New features#
Added MiniBitty support for 3rd generation Joulescope products.
Added externally available OS abstraction in include/jsdrv/os_*.h (sem, event, mutex, thread, atomic).
Implemented jsdrv_meta_syntax_check() (previously a stub).
File layout#
Moved device-specific files into src/devices/{js110,js220,js320, mb_device}/ (similarly in include_private/jsdrv_prv/devices/ and test/devices/). No code logic changed.
Fixed#
Latent segfaults on force disconnects.
jsdrvp_msg_free now also frees info.tmap for BUFFER_INFO payloads (previously only BUFFER_RSP, which leaked one tmap per info publish).
jsdrvp_msg_clone now deep-copies info.tmap for BUFFER_INFO / BUFFER_RSP payloads so clones and originals each own an independent instance.
Missing JSDRV_API qualifier on os_event.h and os_mutex.h public functions; on Windows DLL builds, those symbols were not exported.
Documentation rot: jsdrv_union_eq reference to non-existent eq_strict; jsdrv_union_widen copy-pasted description; stale “deprecated time_map” comment; “length in invalid” typo in error codes.
jsdrv.h now includes jsdrv/error_code.h.
Contract documentation (no code change)#
jsdrv_subscribe_fn: callback payload and every pointer reachable through it (including jsdrv_buffer_info_s.tmap) are valid only for the duration of the callback. Copy before returning.
jsdrv_statistics_s / jsdrv_stream_signal_s / jsdrv_buffer_info_s / jsdrv_buffer_request_s / jsdrv_buffer_response_s: consumers MUST check the version field; future versions only repurpose reserved fields or append.
jsdrv_publish / subscribe / unsubscribe / open / close timeouts: JSDRV_TIMEOUT_MS_ASYNC (0) is asynchronous; timeout > 0 is synchronous and guaranteed complete on return. The return code reflects synchronous processing only.
jsdrv_finalize: the context is no longer usable after return, regardless of status. Nonzero status may indicate leaked resources.
jsdrv_unsubscribe: cbk_fn AND cbk_user_data must both match the values passed to jsdrv_subscribe; silent success on mismatch.
1.12.0#
2026 Jan 5
Added JS220 sample publish rate h/fp.
Updated node package versions to address flagged security vulnerabilities.
1.11.0#
2025 Dec 2
Added Python 3.14 support and dropped Python 3.10 support.
Update build dependencies.
Added time64.as_isostr()
1.10.0#
2025 Jul 15
Added Typescript support. Thanks @biosbob !
1.9.4#
2025 Jul 7
Fixed tmap NULL pointer reference (Joulescope UI 321).
1.9.3#
2025 May 19
Implemented “–set” option to record entry point.
Changed “UTC add is not monotonically increasing” log errors to warnings and reduced frequency.
1.9.2#
2025 May 6
Fixed self->tmap NULL pointer access in jsdrv_bufsig_info.
Added NULL pointer handling to tmap.
1.9.1#
2025 Apr 9
Handle 500 ksps on-instrument downsampling by forcing to 250 ksps.
Fixed time sync inaccuracy by including FPGA 1.3.3
handle large update gaps
bound error on sampling rate
1.9.0#
2025 Mar 29
Fixed TimeMap.get() in Python binding.
Deprecated jsdrv_buffer_info_s.time_map. Use tmap.
Renamed jsdrv_tmap_size to jsdrv_tmap_length.
Changed jsdrv_tmap_get() signature.
1.8.0#
2025 Mar 27
Added improved time mapping to keep buffer time map consistent.
Added jsdrv/tmap.h, tmap.c and tmap_test.c.
Added jsdrv_buffer_info_s.tmap field.
Added jsdrv_buffer_info_s.decimate_factor field.
Maintained jsdrv_buffer_response_s.info.time_map functionality.
Added Linux ARM64 builds.
1.7.4#
2025 Mar 4
Fixed memory leak on every JS220 command.
Increased JSDRV_STREAM_DATA_SIZE from 64 kB to 256 kB to support larger buffer requests.
1.7.3#
2025 Jan 7
Fixed memory leak on JS220 repeated open without close.
Fixed setup.py links (fixes PyPi links).
1.7.2#
2024 Dec 10
Fixed time sync inaccuracy by including FPGA 1.3.2
1.7.1#
2024 Nov 25
Fixed memory leak on error condition for Windows backend.
Removed unused file device.h.
Fixed time sync inaccuracy by including FPGA 1.3.1
1.7.0#
2024 Nov 8
Added support for JS220 on-instrument downsampling with fw 1.3.0 & fpga 1.3.0
Migrated to numpy 2
Added Python 3.13 support
Dropped Python 3.9 support
Added arbitrary scaler for current & voltage
1.6.0#
2024 Oct 18
Added support for notes to Record class and record entry point.
Added user_data parameter to Record.open().
Added “–note” option to record entry point.
1.5.6#
2024 Sep 20
Reduced log verbosity for some JS220 messages.
Added js220_i128_is_neg.
1.5.5#
2024 Aug 22
Modified Python record entry point to use all connected Joulescopes by default. Use the “–serial_number” argument to record from a specific Joulescope when the host computer has more than one Joulescope connected.
Catch exceptions on pyjoulescope_driver callbacks to Python code.
1.5.4#
2024 Jun 28
Pinned numpy version dependency to < 2.
1.5.3#
2024 May 28
Improved libusb (macOS, linux) backend message processing.
Handle closed command queues to improve firmware update reliability.
Added device command queues to poll for improved performance.
Handle all pending device commands with each pass.
1.5.2#
2024 May 8
Added “capture” subcommand to jsdrv example executable.
1.5.1#
2024 Apr 27
Fixed JSDRV_DOWNSAMPLE_MODE_AVERAGE glitches due to C type conversion.
Fixed incorrect downsampling initialization.
1.5.0#
2024 Apr 24
Added node.js binding.
Fixed downsampling to round to nearest integer for integer types.
Added downsampling mode JSDRV_DOWNSAMPLE_MODE_AVERAGE, but not yet connected.
1.4.10#
2024 Mar 20
Fixed JS110 to only issue one CTRL IN status request at a time.
1.4.9#
2024 Mar 18
Refactored record entry point.
Fixed JS110 performance degradation (blocking status in device thread) #8
1.4.8#
2024 Feb 26
Fixed python statistics entry point to remove 1.0 second default duration.
1.4.7#
2024 Feb 14
Initialized buffer_mgr_s instance_.context to NULL.
Improved python binding error reporting.
Added optional duration to statistics entry point.
Bumped minimum pyjls version from 0.8.2 to 0.9.2.
1.4.6#
2023 Dec 9
Fixed timestamp on POSIX (macOS, linux) systems.
1.4.5#
2023 Dec 8
Fixed stream buffer use-after-free and remove timeout.
Added fuzz tester.
1.4.4#
2023 Dec 7
Improved J110 & JS220 state reset on open. Fixes JS110 fixes UTC time sync.
Fixed JS220 communication reliability with FPGA 1.2.1 and FW 1.2.1.
Improved JS110 time map for long-term stability.
1.4.1#
2023 Nov 30
Fixed JS220 “h/fs” restore.
Improved JS220 UTC time sync with FW 1.2.0 & FPGA 1.2.0 support.
Improved JS220 skip / drop sample handling.
1.4.0#
2023 Nov 11
Added jsdrv_calibration_hash and pyjoulescope_driver.calibration_hash.
1.3.21#
2023 Nov 10
Updated to FW 1.1.1.
Added measure entry point to pyjoulescope_driver.
1.3.20#
2023 Oct 26
Updated to FPGA 1.1.0 for beta release (was mistakenly left at 1.0.4).
1.3.19#
2023 Oct 25
Fixed help text for “program” entry point.
Build for Python 3.12.
Upgraded to FW & FPGA 1.1.0 stable releases.
Upgraded record entry point to pyjls 0.8.2 to 1.0.0.
1.3.18#
2023 Jul 24
Fixed buffer_signal summaryN incorrect when computing multiple values in a single call.
Added “noexcept” to python callbacks. Cython 3.0 deprecates implicit noexcept.
1.3.17#
2023 Jul 11
Fixed “in frame_id mismatch” warning log message on first frame.
Fixed JS220 signal “s/X/ctrl” 0 not correctly closing signal.
Added Record “auto” parameter to optionally bypass automatic signal enable/disable.
1.3.16#
2023 Jun 14
Parallelized GitHub Actions build. Removed cibuildwheel.
Fixed JS220 statistics for macOS. 1.3.15 was segfaulting on unaligned accesses.
Added args parameter to pyjoulescope_driver.main.run().
Added quit_ handling to jsdrv.exe examples.
Bumped pyjls version check from 0.7.0 to 0.7.2.
1.3.15#
2023 Jun 8
Fixed JS220 firmware images omitted by 1.3.14 build process changes.
Changed firmware image download to script invoke, not import.
1.3.14#
2023 Jun 8
Improved documentation.
Improved GitHub Actions build process.
Moved test/jsdrv_util to example/jsdrv.
Bumped minimum python version from 3.8 to 3.9.
1.3.12#
2023 May 31
Reduced libusb backend log level. Was too active for JS110 statistics.
Bumped JLS version to 0.7.0.
1.3.11#
2023 May 24
Added JS110 on-instrument (sensor) statistics option #3.
1.3.10#
2023 May 19
Improved threading and priorities on Windows.
Improved Windows timer resolution (timeBeginPeriod).
1.3.9#
2023 May 17
Fixed installation on Ubuntu #6.
1.3.8#
2023 May 16
Updated info entry point.
Added automatic include path for jsdrv static CMake builds.
Added support for building a shared library. Initialize build subdir with “cmake -DBUILD_SHARED_LIBS=ON ..”
1.3.7#
2023 Apr 28
Fixed “info” entry point to correctly display multiple Joulescopes.
Fixed “record” entry point to correctly add first UTC timestamp.
Cleaned up build & install process (needs more work).
1.3.6#
2023 Apr 27
Fixed JS110 sample_id for downsampled 1-bit channels.
Updated to pyjls 0.6.1 for improved robustness.
1.3.5#
2023 Apr 26
Added JS220 FW 1.0.7 and FPGA 1.0.4 as alpha & beta.
1.3.4#
2023 Apr 26
Fixed record jls version check.
Send buffer signal clear on free.
Updated to pyjls 0.6.0.
Fixed pyjoulescope_driver.record to not remove sample_id offset.
1.3.3#
2023 Apr 19
Cleared all message fields at allocation.
Added api_timeout entry point test.
Improved thread entry point test.
Reordered unsubscribe to ensure callback validity.
Added malloc/free mutex for guaranteed thread safety.
Added runtime pyjls version check.
Improved logging robustness and thread safety.
Fixed JS110 open causing IN+ to OUT+ disconnect.
Added JS110 open modes: defaults, resume.
1.3.2#
2023 Apr 13
Improved record close error handling.
Added JS220 streaming data ignore when device not open.
Improved record entry point.
Open in “defaults” mode by default with optional “restore”.
Added parameter “–set” option.
1.3.1#
2023 Apr 4
Decreased JS110 status polling interval to reduce USB message spamming.
Added JS110 streaming when only statistics requested (uses host-side stats).
Increased process priority and backend thread priority for Windows.
1.3.0#
2023 Mar 30
Added pyjoulescope_driver.time64 module (from UI).
Fixed buffer_signal summary_get handling on zero size.
Added “record” module and entry point to record streaming samples.
Fixed buffer_signal range advertisement when empty.
Improved skipped / duplicate sample handling for JS220.
1.2.2#
2023 Mar 19
Fixed intermittent timeout broken for API calls.
1.2.1#
2023 Mar 16
Truncate memory buffer sample responses that are too long (segfault).
Fixed buffer signal shift correction overflowing buffer (segfault).
Fixed garbage data at end when shift required for u1 and u4 data types.
Fixed zero length message send for highly downsampled signals.
1.2.0#
2023 Mar 9
Added memory buffer for f32, u4, u1 data types.
Bumped python support (3.8 - 3.11). Dropped 3.7.
Added API struct jsdrv_time_map_s and functions jsdrv_time_from_counter(), jsdrv_time_to_counter.
Added jsdrv_time_map_s to jsdrv_stream_signal_s and jsdrv_statistics_s.
Added host-side time map.
Fixed JS110 sample stream message size.
Fixed buffer_signal sample and utc response time entries.
1.1.4#
2023 Jan 25
Added JS110 GPI read request: s/gpi/+/!req -> s/gpi/+/!value.
Fixed incorrect topic match on {device}/@/!finalize
1.1.3#
2023 Jan 24
Fixed open to correctly handle error on lower-level device open.
Improved statistics output to include time/sample_freq and time/range.
Reduced DEVICES_MAX for libusb backend to prevent breaking select.
1.1.2#
2022 Dec 20
Fixed i128 math functions js220_i128_neg() and js220_i128_lshift().
Fixed incorrect constant for platforms with i32 constants.
1.1.1#
2022 Nov 30
Fixed build dependencies.
Specified python 3.10 for GitHub actions.
1.1.0#
2022 Nov 11
Modified jsdrv_stream_signal_s (requires app recompile).
Fixes pyjoulescope and pyjoulescope_ui integration.
Added sample_rate.
Added decimate_factor.
Added JS220 host-side downsampling.
Rename JS110 topic s/fs to h/fs, matches new JS220 topic.
Fixed old JS220 data sent on stream enable after disable.
Added free for partial input stream messages on device close.
Fixed firmware image include and added pkgdata load check.
1.0.7#
2022 Nov 8
Improved documentation.
1.0.6#
2022 Nov 2
Fixed build from tar.gz package.
Updated README.
1.0.5#
2022 Nov 1
Fixed JS110 current range processing for window N and M.
Fixed JS110 sample alignment.
Fixed JS110 statistics generation time and rate.
1.0.4#
2022 Oct 30
Added JS220_CTRL_OP_DISCONNECT for cleaner disconnect/reconnect. Requires js220_ctrl firmware 1.0.4, no effect on earlier versions.
Fixed JS110 support.
Improve firmware update support.
1.0.3#
2022 Oct 24
Fixed linux by disabling BULK IN timeout. Linux was losing data on timeout. Fixed cancel, which still allows graceful shutdown.
Added JS110 downsampling on host.
Switched from obsolete pypiwin32 to pywin32.
Fixed js110_sp_process when i_range was off or missing.
1.0.2#
2022 Oct 15
Fixed jsdrv_util app_match to work with multiple Joulescopes.
1.0.1#
2022 Oct 9
Added native and python threading demonstrations.
Improve python binding to support u64 and i64 types.
Added firmware/gateware updates.
Added build support for including most recent firmware images.
Added “program” entry point.
Fixed access violation on publish to close device.
Fixed python Driver.device_paths returning [“”] instead of [] when no devices found.
Reduced bulk in error on device removal to warning.
1.0.0#
2022 Oct 6
Fixed JS220 power computation.
Fixed trigger GPI spec (7 not 255).
Fixed sample_id 32-bit rollover handling.
Added publish bytes support (needed for memory writes).
0.2.7#
2022 Oct 4
Added host-side power computation to JS220.
Improved JS110 driver to provide current_range, gpi0, gpi1.
Fixed power, charge and energy computation. Power fixes require FPGA 0.2.6 upgrade.
Fixed JS110 stop/start streaming.
Added JS110 statistics.
0.2.6#
2022 Sep 29
Reduced POSIX file descriptor limit request to 4096 max.
0.2.5#
2022 Sep 26
Fixed process hang due to logging on macOS & Linux.
Fixed device disconnect for macOS & Linux.
Increased file handle limit on macOS & Linux.
0.2.4#
2022 Sep 24
Added responder for removed devices.
Fixed JSDRV_MSG_DEVICE_ADD retained subscribe. Was sending each device then full comma-separated list.
Added check for API call from jsdrv frontend thread.
0.2.3#
2022 Sep 21
Fixed support for multiple (not just first found) of same device type.
Improved JS110 support.
Added macOS and Linux support using libusb library.
0.2.2#
2022 Sep 9
Completed JS220 memory read operation.
Completed JS220 memory erase operation.
Modifed jsdrvp_msg_alloc_value to support heap allocated values, not just jsdrv_publish(). Needed for read data messages.
Added jsdrv_topic_remove().
Completed controller-side signed & encrypted & signed firmware update.
Move UI to private repository. Need to avoid Qt dependencies here.
Removed “noise.py” entry point, which is not meaningful to end users.
Added python command-line –log_level and –jsdrv_log_level options.
Fixed python publish string values encoding.
Improved native metadata validating to accept integer values as strings.
Renamed python “set.py” to “set_parameter.py” to avoid reserved word “set”.
Added JS220 “opening” state to “h/state” metadata.
Simplified native jsdrv_util set to use native support for string values.
Fixed driver based upon beta build feedback.
Fixed JS220 handling of missing/duplicated sample ids.
Converted to element_size_bits from element_size_pow2.
Added GPIO streaming support (u1 data type).
Redefined JSDRV_DATA_TYPE_FLOAT to align with JLS v2.
Reduced logging verbosity.
0.2.1#
2022 Aug 1
Initial public commit.