diff --git a/CHANGELOG b/CHANGELOG index 2b16f9c..ff381cf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +2022-03-01: new sample rates 32k, 640k, doc update, tools update [4cb4edb] 2022-02-28: upversion to FW0210, new sample rate 128 kS/s (ID: 113) [f4755d2] 2022-02-08: more tool programs in examples [6c9d2d7] 2022-02-05: Merge branch 'main' of github.com:Ho-Ro/Hantek6022API fix last commit [078dffd] diff --git a/PyHT6022/LibUsbScope.py b/PyHT6022/LibUsbScope.py index c7742bf..129fad1 100644 --- a/PyHT6022/LibUsbScope.py +++ b/PyHT6022/LibUsbScope.py @@ -1,6 +1,7 @@ __author__ = 'Robert Cope', 'Jochen Hoenicke' import os +import sys import time import usb1 import array @@ -221,7 +222,11 @@ def open_handle(self): self.device_handle = self.device.open() if os.name == 'posix' and self.device_handle.kernelDriverActive(0): self.device_handle.detachKernelDriver(0) - self.device_handle.claimInterface(0) + try: + self.device_handle.claimInterface(0) + except Exception as e: + print( e, file=sys.stderr ) + return False if self.is_device_firmware_present: self.set_num_channels(2) self.set_interface(0) @@ -236,9 +241,13 @@ def close_handle(self, release_interface=True): """ if not self.device_handle: return True - if release_interface: - self.device_handle.releaseInterface(0) - self.device_handle.close() + try: + if release_interface: + self.device_handle.releaseInterface(0) + self.device_handle.close() + except Exception as e: + print( e, file=sys.stderr ) + return False self.device_handle = None return True diff --git a/README.md b/README.md index c0a9382..7bf6e3b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repo is based on the excellent work of [Robert](https://github.com/rpcope1/Hantek6022API) and [Jochen](https://github.com/jhoenicke/Hantek6022API) -and focusses mainly on Hantek6022BE/BL under Linux (development system: debian buster). +and focusses mainly on Hantek6022BE/BL under Linux (development system: Debian stable). ## Hantek 6022 Firmware @@ -18,42 +18,61 @@ and focusses mainly on Hantek6022BE/BL under Linux (development system: debian b Scope Visualisation Example -This is a API for Python for the -ultra-cheap, reasonably usable (and hackable) 6022 DSO, with a libusb implementation via libusb1 for Linux. +This is a API for Python for the ultra-cheap, reasonably usable (and hackable) 6022 DSO, +with a libusb implementation via libusb1 for Linux. -The scope can be accessed by instantiating an oscilloscope object with the correct scopeid (always 0 for one scope -attached). Things like voltage divisions and sampling rates can be set by the appropriate methods. -Please check the provided example programs, the comments will give you more hints for own experiments. -Each method has some documentation as to what it does currently though, and hopefully -variable names are clear enough to give you some idea what they are for. +The scope can be accessed by instantiating an oscilloscope object. +Things like voltage divisions and sampling rates can be set by the appropriate methods. +Please check the provided [example programs](https://github.com/Ho-Ro/Hantek6022API/tree/main/examples), +the comments will give you more hints for own experiments. +Each method has documentation about what it is doing, and hopefully the variable names are clear enough +to give you an idea of what they are for. -## Developed under Linux +## Linux Install -If you're on Linux, you're in luck. Provided are bindings for libusb to operate this -little device. You may wish to first add 60-hantek-6022-usb.rules to your udev rules, via +If you're on Linux, you're in luck. +Provided are bindings for libusb to operate this little device with simple python commands. +If you are a user, you can simply download the latest Debian package from +[releases](https://github.com/Ho-Ro/Hantek6022API/releases) and use the utilities in +[examples](https://github.com/Ho-Ro/Hantek6022API/tree/main/examples), +all tools named `*_6022.py` are copied to `/usr/bin` and are thus globally available. + +## Developer Info + +If you are a developer, you will definitely clone the repo and work with it more intensively. So please read on... + +You may wish to first add `60-hantek-6022-usb.rules` (living in [udev](https://github.com/Ho-Ro/Hantek6022API/tree/main/udev)) +to your udev rules, via sudo cp 60-hantek-6022-usb.rules /etc/udev/rules.d/ After you've done this, the scope should automatically come up with the correct permissions to be accessed without being root user. -The following instructions are tested with Debian (*stretch* and *buster*) -and are executed also automatically under Ubuntu (*2004*) - have a look +The following instructions are tested with Debian stable versions *stretch*, *buster* and *bullseye* +and are executed also automatically by GitHub under Ubuntu (*2004*) after each push to this repo - have a look at the [GitHub Action](https://github.com/Ho-Ro/Hantek6022API/actions/workflows/build_check.yml). -On each successful run a debian package is available under *Artifacts*. +On each successful run a Debian package is available under *Artifacts*. + +### Build Preparations To compile the custom firmware you have to install (as root) the *small devices c compiler* `sdcc` and the tool `pkgconf`: sudo apt install sdcc pkgconf -### Submodule fx2lib -Hantek6022API uses the submodule [fx2lib](https://github.com/Ho-Ro/fx2lib) that I cloned from the [original fx2lib](https://github.com/djmuhlestein/fx2lib) to do minor maintenance updates. +Take care when the SDCC version gets updated. the step from 3.9 to 4.0 introduced a nasty regression due to [less optimal code](https://github.com/Ho-Ro/Hantek6022API/blob/4cb4edbf1e6d2d5df21dbb4dabb8f51c932a0348/PyHT6022/Firmware/DSO6022BE/scope6022.inc#L80) +from the newer version. + +Hantek6022API uses the submodule [fx2lib](https://github.com/Ho-Ro/fx2lib) that I cloned from the +[original fx2lib](https://github.com/djmuhlestein/fx2lib) to do minor maintenance updates. -Pull the submodule in: +Pull the submodule in (once): git submodule init git submodule update --remote +### Linux Build + To build the custom firmware run `make` in the top level directory: make @@ -79,10 +98,44 @@ The installed programs can also be uninstalled cleanly with sudo dpkg -P hantek6022api -With the device plugged in, run `upload_firmware_6022.py` once to bootstrap the scope for use. + You can then look at the scope traces via `capture_6022.py -t 0.01 | plot_from_capture_6022.py`, or write your own programs - look at the programs in `examples` as a start. +If you want to make low-level experiments with the python commands you should bootstrap the scope for use: +With the device plugged in, run `upload_6022_firmware.py` once. +The *user tools* `*_6022.py` do this automatically at start. + +**Don't Panik!** +The firmware is uploaded into RAM and is lost after switching off the scope or disconnecting +the USB, so the device can never be *bricked*. + +This simple program sets the calibration output frequency to 400 Hz +(you can use each even divison of 2 MHz between 32 Hz and 100 kHz). + +```python +#!/usr/bin/python3 + +# get the python package +from PyHT6022.LibUsbScope import Oscilloscope + +# create an Osclloscope object +scope = Oscilloscope() + +# setup the scope +scope.setup() + +# attach to the scope +scope.open_handle() + +# upload firmware unless already uploaded +if (not scope.is_device_firmware_present): + scope.flash_firmware() + +# and now set the calibration frequency output to 400 Hz +scope.set_calibration_frequency( 400 ) +``` + ## It even works under Windows [@justlep](https://github.com/justlep) wrote: @@ -150,10 +203,14 @@ Configure with command line arguments: -e, --eeprom store calibration values in eeprom -g, --measure_gain interactively measure gain (as well as offset) +### Fast Offset Calibration + Apply 0 V to both inputs (e.g. connect both probes to the GND calibration connector) and execute: calibrate_6022.py -e +### Complete Offset and Gain Calibration + If is also possible to measure and create also gain calibration. To calibrate gain you have to apply a well known voltage (setpoint) and compare it with the actual value that is read by the scope: @@ -172,24 +229,26 @@ the program measures and compares them against the expected gain settings: 6. The program option `-e` stores the calibration values in eeprom 7. The program option `-c` creates a config file `modelDSO6022.conf` -This config file can be copied into directory `~/.config/OpenHantek`. +This (optional) config file can be copied into directory `~/.config/OpenHantek`. On every startup OpenHantek reads this file and applies the calibratipon accordingly. +The config file has higher priority than the eeprom content. +It has also the advantage not to mess with the eeprom. The calibration voltages do not have to correspond absolutely to the given value, -but the applied voltage should not be much higher than the given value and must be determined exactly - -e.g. by measuring it with a multimeter. Type in the measured voltage at the prompt. -4 AA batteries in a battery holder are a simple and reliable voltage source: +but the applied voltage should not be much higher than the proposed value and must be determined exactly - +e.g. by measuring it with a multimeter. Type in the real measured voltage at the prompt. +4 fresh AA batteries in a battery holder are a simple and reliable voltage source: -Requested Voltage | Applied Voltage | Comment -------------------|-----------------|-------- -0.4 V | 0.3 V | 2 x AA with 1/10 probe -0.8 V | 0.6 V | 4 x AA with 1/10 probe -2.0 V | 1.5 V | 1 x AA -4.0 V | 3.0 V or 4.5 V | 2 or 3 x AA +Requested Voltage | Applied Voltage | Comment +------------------|------------------|-------- +0.4 V | ~0.3 V | 2 x AA with 1/10 probe +0.8 V | ~0.6 V | 4 x AA with 1/10 probe +2.0 V | ~1.5 V | 1 x AA +4.0 V | ~3.0 V or ~4.5 V | 2 or 3 x AA [Read more about the eeprom content...](docs/README.md#eeprom) -## Use the device as a data logger ## +## Use the device as a data logger The program `capture_6022.py` (also in `/usr/bin/`) allows to capture both channels over a long time. diff --git a/examples/calibrate_6022.py b/examples/calibrate_6022.py index 4f669bc..0d88c0d 100755 --- a/examples/calibrate_6022.py +++ b/examples/calibrate_6022.py @@ -20,6 +20,7 @@ from PyHT6022.LibUsbScope import Oscilloscope +import sys import time import binascii @@ -91,7 +92,8 @@ def read_avg( voltage_range, sample_rate=110, repeat = 1, samples = 12 * 1024 ): scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) if (not scope.is_device_firmware_present): scope.flash_firmware() diff --git a/examples/capture_6022.py b/examples/capture_6022.py index 00e9d89..1d8b4c1 100755 --- a/examples/capture_6022.py +++ b/examples/capture_6022.py @@ -92,7 +92,8 @@ scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) # upload correct firmware into device's RAM if (not scope.is_device_firmware_present): diff --git a/examples/continous_read.py b/examples/continous_read.py index d62472d..4d10770 100755 --- a/examples/continous_read.py +++ b/examples/continous_read.py @@ -4,6 +4,7 @@ from PyHT6022.LibUsbScope import Oscilloscope import matplotlib.pyplot as plt +import sys import time import numpy as np from collections import deque @@ -36,7 +37,8 @@ def build_stability_array(data, threshold=1.0): scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit() scope.flash_firmware() scope.set_interface(1) # choose ISO scope.set_num_channels(1) diff --git a/examples/get_calibration.py b/examples/get_calibration.py index 82c780f..79b85cb 100755 --- a/examples/get_calibration.py +++ b/examples/get_calibration.py @@ -2,14 +2,16 @@ __author__ = 'Jochen Hoenicke' +import sys from PyHT6022.LibUsbScope import Oscilloscope scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) + calibration = scope.get_calibration_values( 48 ) scope.close_handle() - # print( calibration ) for x in calibration: print( hex(x), end=" " ) diff --git a/examples/get_firmware_version.py b/examples/get_firmware_version.py index f42cf45..e2c1d51 100755 --- a/examples/get_firmware_version.py +++ b/examples/get_firmware_version.py @@ -8,6 +8,6 @@ scope = Oscilloscope() scope.setup() -scope.open_handle() -print( hex( scope.get_fw_version() ) ) -scope.close_handle() +version = scope.get_fw_version() +if version: + print( hex( version ) ) diff --git a/examples/read_eeprom.py b/examples/read_eeprom.py index c80dfc3..a7539a4 100755 --- a/examples/read_eeprom.py +++ b/examples/read_eeprom.py @@ -2,11 +2,14 @@ __author__ = 'Jochen Hoenicke' +import sys from PyHT6022.LibUsbScope import Oscilloscope scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) + eeprom = scope.read_eeprom(0, 8) scope.close_handle() diff --git a/examples/read_eeprom_256_byte.py b/examples/read_eeprom_256_byte.py index a6c5ce1..83c95dd 100755 --- a/examples/read_eeprom_256_byte.py +++ b/examples/read_eeprom_256_byte.py @@ -1,10 +1,13 @@ #!/usr/bin/python3 +import sys from PyHT6022.LibUsbScope import Oscilloscope scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) + eeprom = scope.read_eeprom( 0, 256 ) scope.close_handle() diff --git a/examples/read_firmware.py b/examples/read_firmware.py index 75777b9..9bbc81f 100755 --- a/examples/read_firmware.py +++ b/examples/read_firmware.py @@ -6,7 +6,9 @@ scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) + firmware = scope.read_firmware(length=16*1024, chunk_len=32) scope.close_handle() diff --git a/examples/record_wav.py b/examples/record_wav.py index 727da3a..b013b13 100755 --- a/examples/record_wav.py +++ b/examples/record_wav.py @@ -23,7 +23,8 @@ scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit() if (not scope.is_device_firmware_present): scope.flash_firmware() else: diff --git a/examples/reset_eeprom_6021.py b/examples/reset_eeprom_6021.py index 9913aba..645b7f3 100755 --- a/examples/reset_eeprom_6021.py +++ b/examples/reset_eeprom_6021.py @@ -1,10 +1,13 @@ #!/usr/bin/python3 +import sys from PyHT6022.LibUsbScope import Oscilloscope scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) + scope.flash_firmware() print( "FW version", hex( scope.get_fw_version() ) ) diff --git a/examples/reset_eeprom_6022.py b/examples/reset_eeprom_6022.py index 2382fda..527debd 100755 --- a/examples/reset_eeprom_6022.py +++ b/examples/reset_eeprom_6022.py @@ -1,10 +1,13 @@ #!/usr/bin/python3 +import sys from PyHT6022.LibUsbScope import Oscilloscope scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) + scope.flash_firmware() print( "FW version", hex( scope.get_fw_version() ) ) diff --git a/examples/set_cal_out_freq_6022.py b/examples/set_cal_out_freq_6022.py index 16bb7ff..e3e43b3 100755 --- a/examples/set_cal_out_freq_6022.py +++ b/examples/set_cal_out_freq_6022.py @@ -10,16 +10,17 @@ if len( sys.argv ) < 2: print( usage, file=sys.stderr ) - sys.exit() + sys.exit( -1 ) cal_freq = int( sys.argv[1]) if cal_freq < 32 or cal_freq > 100000: print( usage, file=sys.stderr ) - sys.exit() + sys.exit( -1 ) scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) if not scope.set_calibration_frequency( cal_freq ): print( 'error', file=sys.stderr ) diff --git a/examples/upload_6021_firmware.py b/examples/upload_6021_firmware.py index 4977c6a..1126803 100755 --- a/examples/upload_6021_firmware.py +++ b/examples/upload_6021_firmware.py @@ -1,5 +1,6 @@ #!/usr/bin/python3 +import sys from PyHT6022.LibUsbScope import Oscilloscope firmware = "dso6021-firmware.hex" @@ -8,7 +9,8 @@ scope = Oscilloscope( VID, PID ) scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) scope.flash_firmware_from_hex( firmware ) print( "FW version", hex( scope.get_fw_version() ) ) scope.close_handle() diff --git a/examples/upload_6021_firmware_from_hex.py b/examples/upload_6021_firmware_from_hex.py index eb0c2d9..e505694 100755 --- a/examples/upload_6021_firmware_from_hex.py +++ b/examples/upload_6021_firmware_from_hex.py @@ -2,17 +2,17 @@ # flash the firmware from hex file - +import sys from PyHT6022.LibUsbScope import Oscilloscope -from sys import argv if len( argv ) > 1: - firmware = argv[ 1 ] - scope = Oscilloscope() - scope.setup() - scope.open_handle() - scope.flash_firmware_from_hex( firmware ) - print( "FW version", hex( scope.get_fw_version() ) ) - scope.close_handle() + firmware = argv[ 1 ] + scope = Oscilloscope() + scope.setup() + if not scope.open_handle(): + sys.exit( -1 ) + scope.flash_firmware_from_hex( firmware ) + print( "FW version", hex( scope.get_fw_version() ) ) + scope.close_handle() else: - print( "usage: " + argv[0] + " path_to_hexfile" ) + print( "usage: " + argv[0] + " path_to_hexfile" ) diff --git a/examples/upload_6022_firmware.py b/examples/upload_6022_firmware.py index 672ec22..0ce4ce1 100755 --- a/examples/upload_6022_firmware.py +++ b/examples/upload_6022_firmware.py @@ -2,15 +2,16 @@ """ Flash default firmware into device -ither firmare-DSO6022BE or firmware-DSO6022BL or firmware-DSO6021 +either firmare-DSO6022BE or firmware-DSO6022BL or firmware-DSO6021 depending on VID/PID """ - +import sys from PyHT6022.LibUsbScope import Oscilloscope scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) scope.flash_firmware() print( "FW version", hex( scope.get_fw_version() ) ) scope.close_handle() diff --git a/examples/upload_6022_firmware_from_hex.py b/examples/upload_6022_firmware_from_hex.py index eb0c2d9..e505694 100755 --- a/examples/upload_6022_firmware_from_hex.py +++ b/examples/upload_6022_firmware_from_hex.py @@ -2,17 +2,17 @@ # flash the firmware from hex file - +import sys from PyHT6022.LibUsbScope import Oscilloscope -from sys import argv if len( argv ) > 1: - firmware = argv[ 1 ] - scope = Oscilloscope() - scope.setup() - scope.open_handle() - scope.flash_firmware_from_hex( firmware ) - print( "FW version", hex( scope.get_fw_version() ) ) - scope.close_handle() + firmware = argv[ 1 ] + scope = Oscilloscope() + scope.setup() + if not scope.open_handle(): + sys.exit( -1 ) + scope.flash_firmware_from_hex( firmware ) + print( "FW version", hex( scope.get_fw_version() ) ) + scope.close_handle() else: - print( "usage: " + argv[0] + " path_to_hexfile" ) + print( "usage: " + argv[0] + " path_to_hexfile" ) diff --git a/examples/upload_default_firmware.py b/examples/upload_default_firmware.py index 634fb09..d996153 100755 --- a/examples/upload_default_firmware.py +++ b/examples/upload_default_firmware.py @@ -2,12 +2,15 @@ __author__ = 'Robert Cope' +import sys from PyHT6022.LibUsbScope import Oscilloscope from PyHT6022.Firmware import firmware as Firmware scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) + scope.flash_firmware( firmware = Firmware ) print( "FW version", hex( scope.get_fw_version() ) ) scope.close_handle() diff --git a/examples/upload_firmware_mod_01.py b/examples/upload_firmware_mod_01.py index 586d528..f59e751 100755 --- a/examples/upload_firmware_mod_01.py +++ b/examples/upload_firmware_mod_01.py @@ -2,11 +2,13 @@ __author__ = 'Robert Cope' +import sys from PyHT6022.LibUsbScope import Oscilloscope from PyHT6022.Firmware import mod_firmware_01 as Firmware scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) scope.flash_firmware( firmware = Firmware ) scope.close_handle() diff --git a/examples/upload_firmware_mod_iso.py b/examples/upload_firmware_mod_iso.py index d2619ee..f337991 100755 --- a/examples/upload_firmware_mod_iso.py +++ b/examples/upload_firmware_mod_iso.py @@ -2,11 +2,13 @@ __author__ = 'Robert Cope' +import sys from PyHT6022.LibUsbScope import Oscilloscope from PyHT6022.Firmware import mod_firmware_iso as Firmware scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) scope.flash_firmware( firmware = Firmware ) scope.close_handle() diff --git a/examples/upload_firmware_stock.py b/examples/upload_firmware_stock.py index e420775..4cdb9af 100755 --- a/examples/upload_firmware_stock.py +++ b/examples/upload_firmware_stock.py @@ -2,11 +2,13 @@ __author__ = 'Robert Cope' +import sys from PyHT6022.LibUsbScope import Oscilloscope from PyHT6022.Firmware import stock_firmware as Firmware scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) scope.flash_firmware( firmware = Firmware ) scope.close_handle() diff --git a/examples/upload_firmware_to_DSO2020.py b/examples/upload_firmware_to_DSO2020.py index e9a7533..fe51809 100755 --- a/examples/upload_firmware_to_DSO2020.py +++ b/examples/upload_firmware_to_DSO2020.py @@ -4,6 +4,7 @@ # this device has the same HW as DSO6022, but different PID=0x2020 # it will become a DSO6022 when the FW is loaded +import sys from PyHT6022.LibUsbScope import Oscilloscope firmware = "dso6022be-firmware.hex" @@ -12,7 +13,8 @@ scope = Oscilloscope( VID, PID ) scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) scope.flash_firmware_from_hex( firmware ) print( "FW version", hex( scope.get_fw_version() ) ) scope.close_handle() diff --git a/examples/write_eeprom.py b/examples/write_eeprom.py index f6df21c..5da1f71 100755 --- a/examples/write_eeprom.py +++ b/examples/write_eeprom.py @@ -2,12 +2,14 @@ __author__ = 'Jochen Hoenicke' +import sys from PyHT6022.LibUsbScope import Oscilloscope scope = Oscilloscope() scope.setup() -scope.open_handle() +if not scope.open_handle(): + sys.exit( -1 ) # read at end-16, 16 bytes eeprom = scope.read_eeprom( 256 - 16, 16 ) diff --git a/setup.py b/setup.py index 78f2f7c..0776553 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -__version__ = '2.10.1' +__version__ = '2.10.2' from setuptools import setup