Backport recent changes from mainline.
This includes all changes from4c660b46c1
Makefile.am: Add missing src/serial_hid.h. up to39ea7b7d39
dmm/eev121gw: add missing scale items for sub display in power modes This is possible since none of the changes above change or remove public API calls of the library.
This commit is contained in:
parent
8686b747cd
commit
e4204b1757
8
Doxyfile
8
Doxyfile
|
@ -743,7 +743,7 @@ WARN_LOGFILE =
|
|||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = src include $(BUILDDIR)include/libsigrok
|
||||
INPUT = $(SRCDIR)src $(SRCDIR)include $(BUILDDIR)include/libsigrok
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
@ -763,7 +763,11 @@ INPUT_ENCODING = UTF-8
|
|||
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
|
||||
# *.qsf, *.as and *.js.
|
||||
|
||||
FILE_PATTERNS =
|
||||
# BEWARE! DON'T set the variable to an empty value. Don't set the variable
|
||||
# at all instead. See https://github.com/doxygen/doxygen/issues/7190 and
|
||||
# https://sigrok.org/bugzilla/show_bug.cgi?id=1422 (can get reverted when
|
||||
# the Doxygen version which causes the issue no longer is used in the wild).
|
||||
## FILE_PATTERNS =
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
|
|
5
HACKING
5
HACKING
|
@ -61,8 +61,9 @@ This is a rough overview of what you need to do in order to add a new driver
|
|||
(using the Tondaj SL-814 device as example). It's basically what the
|
||||
'new-driver' script (see above) does for you:
|
||||
|
||||
- Makefile.am: Add HW_TONDAJ_SL_814 and add to libsigrok_la_SOURCES.
|
||||
- configure.ac: Add a DRIVER() and DRIVER2() call.
|
||||
- Makefile.am: Add to src_libdrivers_la_SOURCES under the HW_TONDAJ_SL_814
|
||||
condition.
|
||||
- configure.ac: Add an SR_DRIVER() call.
|
||||
- src/drivers.c: Add a tondaj_sl_814_driver_info entry in two places.
|
||||
- src/hardware/tondaj-sl-814/ directory: Add api.c, protocol.c, protocol.h.
|
||||
|
||||
|
|
70
Makefile.am
70
Makefile.am
|
@ -95,6 +95,7 @@ libsigrok_la_SOURCES += \
|
|||
src/output/ols.c \
|
||||
src/output/srzip.c \
|
||||
src/output/vcd.c \
|
||||
src/output/wavedrom.c \
|
||||
src/output/null.c
|
||||
|
||||
# Transform modules
|
||||
|
@ -116,9 +117,21 @@ libsigrok_la_SOURCES += \
|
|||
src/scpi/vxi_xdr.c \
|
||||
src/scpi/vxi.h
|
||||
endif
|
||||
# if HAVE_BLUETOOTH
|
||||
libsigrok_la_SOURCES += \
|
||||
src/bt/bt_bluez.c
|
||||
# endif
|
||||
if NEED_SERIAL
|
||||
libsigrok_la_SOURCES += \
|
||||
src/serial.c \
|
||||
src/serial_bt.c \
|
||||
src/serial_hid.c \
|
||||
src/serial_hid.h \
|
||||
src/serial_hid_bu86x.c \
|
||||
src/serial_hid_ch9325.c \
|
||||
src/serial_hid_cp2110.c \
|
||||
src/serial_hid_victor.c \
|
||||
src/serial_libsp.c \
|
||||
src/scpi/scpi_serial.c
|
||||
endif
|
||||
if NEED_USB
|
||||
|
@ -148,6 +161,7 @@ endif
|
|||
libsigrok_la_SOURCES += \
|
||||
src/dmm/asycii.c \
|
||||
src/dmm/bm25x.c \
|
||||
src/dmm/bm86x.c \
|
||||
src/dmm/dtm0660.c \
|
||||
src/dmm/eev121gw.c \
|
||||
src/dmm/es519xx.c \
|
||||
|
@ -155,6 +169,7 @@ libsigrok_la_SOURCES += \
|
|||
src/dmm/fs9922.c \
|
||||
src/dmm/m2110.c \
|
||||
src/dmm/metex14.c \
|
||||
src/dmm/ms2115b.c \
|
||||
src/dmm/ms8250d.c \
|
||||
src/dmm/rs9lcd.c \
|
||||
src/dmm/ut372.c \
|
||||
|
@ -165,7 +180,8 @@ libsigrok_la_SOURCES += \
|
|||
# Hardware (LCR chip parsers)
|
||||
if NEED_SERIAL
|
||||
libsigrok_la_SOURCES += \
|
||||
src/lcr/es51919.c
|
||||
src/lcr/es51919.c \
|
||||
src/lcr/vc4080.c
|
||||
endif
|
||||
|
||||
# Hardware (Scale protocol parsers)
|
||||
|
@ -238,12 +254,6 @@ src_libdrivers_la_SOURCES += \
|
|||
src/hardware/beaglelogic/beaglelogic_native.c \
|
||||
src/hardware/beaglelogic/beaglelogic_tcp.c
|
||||
endif
|
||||
if HW_BRYMEN_BM86X
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/brymen-bm86x/protocol.h \
|
||||
src/hardware/brymen-bm86x/protocol.c \
|
||||
src/hardware/brymen-bm86x/api.c
|
||||
endif
|
||||
if HW_BRYMEN_DMM
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/brymen-dmm/parser.c \
|
||||
|
@ -437,18 +447,36 @@ src_libdrivers_la_SOURCES += \
|
|||
src/hardware/manson-hcs-3xxx/protocol.c \
|
||||
src/hardware/manson-hcs-3xxx/api.c
|
||||
endif
|
||||
if HW_MASTECH_MS6514
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/mastech-ms6514/protocol.h \
|
||||
src/hardware/mastech-ms6514/protocol.c \
|
||||
src/hardware/mastech-ms6514/api.c
|
||||
endif
|
||||
if HW_MAYNUO_M97
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/maynuo-m97/protocol.h \
|
||||
src/hardware/maynuo-m97/protocol.c \
|
||||
src/hardware/maynuo-m97/api.c
|
||||
endif
|
||||
if HW_MICROCHIP_PICKIT2
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/microchip-pickit2/protocol.h \
|
||||
src/hardware/microchip-pickit2/protocol.c \
|
||||
src/hardware/microchip-pickit2/api.c
|
||||
endif
|
||||
if HW_MIC_985XX
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/mic-985xx/protocol.h \
|
||||
src/hardware/mic-985xx/protocol.c \
|
||||
src/hardware/mic-985xx/api.c
|
||||
endif
|
||||
if HW_MOOSHIMETER_DMM
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/mooshimeter-dmm/protocol.h \
|
||||
src/hardware/mooshimeter-dmm/protocol.c \
|
||||
src/hardware/mooshimeter-dmm/api.c
|
||||
endif
|
||||
if HW_MOTECH_LPS_30X
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/motech-lps-30x/protocol.h \
|
||||
|
@ -509,6 +537,12 @@ src_libdrivers_la_SOURCES += \
|
|||
src/hardware/saleae-logic-pro/protocol.c \
|
||||
src/hardware/saleae-logic-pro/api.c
|
||||
endif
|
||||
if HW_SCPI_DMM
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/scpi-dmm/protocol.h \
|
||||
src/hardware/scpi-dmm/protocol.c \
|
||||
src/hardware/scpi-dmm/api.c
|
||||
endif
|
||||
if HW_SCPI_PPS
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/scpi-pps/protocol.h \
|
||||
|
@ -524,6 +558,8 @@ src_libdrivers_la_SOURCES += \
|
|||
endif
|
||||
if HW_SERIAL_LCR
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/serial-lcr/protocol.h \
|
||||
src/hardware/serial-lcr/protocol.c \
|
||||
src/hardware/serial-lcr/api.c
|
||||
endif
|
||||
if HW_SIGLENT_SDS
|
||||
|
@ -542,6 +578,12 @@ src_libdrivers_la_SOURCES += \
|
|||
src/hardware/sysclk-lwla/protocol.c \
|
||||
src/hardware/sysclk-lwla/api.c
|
||||
endif
|
||||
if HW_SYSCLK_SLA5032
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/sysclk-sla5032/protocol.h \
|
||||
src/hardware/sysclk-sla5032/protocol.c \
|
||||
src/hardware/sysclk-sla5032/api.c
|
||||
endif
|
||||
if HW_TELEINFO
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/teleinfo/protocol.h \
|
||||
|
@ -572,12 +614,6 @@ src_libdrivers_la_SOURCES += \
|
|||
src/hardware/uni-t-ut32x/protocol.c \
|
||||
src/hardware/uni-t-ut32x/api.c
|
||||
endif
|
||||
if HW_VICTOR_DMM
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/victor-dmm/protocol.h \
|
||||
src/hardware/victor-dmm/protocol.c \
|
||||
src/hardware/victor-dmm/api.c
|
||||
endif
|
||||
if HW_YOKOGAWA_DLM
|
||||
src_libdrivers_la_SOURCES += \
|
||||
src/hardware/yokogawa-dlm/protocol.h \
|
||||
|
@ -711,7 +747,7 @@ nodist_bindings_cxx_libsigrokcxx_la_include_HEADERS = \
|
|||
pkgconfig_DATA += bindings/cxx/libsigrokcxx.pc
|
||||
|
||||
doxy/xml/index.xml: include/libsigrok/libsigrok.h
|
||||
$(AM_V_GEN)cd $(srcdir) && BUILDDIR=$(abs_builddir)/ doxygen Doxyfile 2>/dev/null
|
||||
$(AM_V_GEN)cd $(srcdir) && SRCDIR=$(abs_srcdir)/ BUILDDIR=$(abs_builddir)/ doxygen Doxyfile 2>/dev/null
|
||||
|
||||
bindings/swig/enums.i: bindings/cxx/enums.timestamp
|
||||
bindings/cxx/enums.cpp: bindings/cxx/enums.timestamp
|
||||
|
@ -746,7 +782,7 @@ CPPXMLDOC = bindings/cxx/doxy/xml/index.xml
|
|||
|
||||
$(CPPXMLDOC): bindings/cxx/include/libsigrokcxx/libsigrokcxx.hpp \
|
||||
bindings/cxx/enums.timestamp
|
||||
$(AM_V_GEN)cd $(srcdir)/bindings/cxx && BUILDDIR=$(abs_builddir)/bindings/cxx/ doxygen Doxyfile 2>/dev/null
|
||||
$(AM_V_GEN)cd $(srcdir)/bindings/cxx && SRCDIR=$(abs_srcdir)/bindings/cxx/ BUILDDIR=$(abs_builddir)/bindings/cxx/ doxygen Doxyfile 2>/dev/null
|
||||
|
||||
# Macro definitions to be used by the SWIG parser.
|
||||
swig_defs = -Dnoexcept= -Dprivate=protected -DG_GNUC_BEGIN_IGNORE_DEPRECATIONS= -DG_GNUC_END_IGNORE_DEPRECATIONS=
|
||||
|
@ -794,7 +830,7 @@ python-clean:
|
|||
-$(AM_V_at)$(setup_py) clean --all 2>/dev/null
|
||||
|
||||
python-doc:
|
||||
$(AM_V_at)cd $(srcdir)/$(PDIR) && BUILDDIR="$(abs_builddir)/$(PDIR)/" doxygen Doxyfile 2>/dev/null
|
||||
$(AM_V_at)cd $(srcdir)/$(PDIR) && SRCDIR="$(abs_srcdir)/$(PDIR)/" BUILDDIR="$(abs_builddir)/$(PDIR)/" doxygen Doxyfile 2>/dev/null
|
||||
|
||||
BUILD_EXTRA += python-build
|
||||
INSTALL_EXTRA += python-install
|
||||
|
@ -911,7 +947,7 @@ java-clean:
|
|||
-$(AM_V_at)rm -fr $(JDIR)/doxy
|
||||
|
||||
java-doc:
|
||||
$(AM_V_at)cd $(srcdir)/$(JDIR) && BUILDDIR="$(abs_builddir)/$(JDIR)/" doxygen Doxyfile
|
||||
$(AM_V_at)cd $(srcdir)/$(JDIR) && SRCDIR="$(abs_srcdir)/$(JDIR)/" BUILDDIR="$(abs_builddir)/$(JDIR)/" doxygen Doxyfile
|
||||
|
||||
BUILD_EXTRA += java-build
|
||||
INSTALL_EXTRA += java-install
|
||||
|
|
2
NEWS
2
NEWS
|
@ -473,7 +473,7 @@ Note: This release DOES change the libsigrok API. That means it is NOT
|
|||
- LeCroy LogicStudio
|
||||
- mcupro Logic16 clone
|
||||
- Pipistrello OLS
|
||||
- SysClk LWLA1016
|
||||
- Sysclk LWLA1016
|
||||
- Oscilloscopes:
|
||||
- Rigol/Agilent DS1000Z series
|
||||
- Yokogawa DLM2000 series
|
||||
|
|
3
README
3
README
|
@ -41,9 +41,12 @@ Requirements for the C library:
|
|||
- libserialport >= 0.1.1 (optional, used by some drivers)
|
||||
- librevisa >= 0.0.20130412 (optional, used by some drivers)
|
||||
- libusb-1.0 >= 1.0.16 (optional, used by some drivers)
|
||||
- hidapi >= 0.8.0 (optional, used for some HID based "serial cables")
|
||||
- bluez/libbluetooth >= 4.0 (optional, used for Bluetooth/BLE communication)
|
||||
- libftdi1 >= 1.0 (optional, used by some drivers)
|
||||
- libgpib (optional, used by some drivers)
|
||||
- libieee1284 (optional, used by some drivers)
|
||||
- libgio >= 2.32.0 (optional, used by some drivers)
|
||||
- check >= 0.9.4 (optional, only needed to run unit tests)
|
||||
- doxygen (optional, only needed for the C API docs)
|
||||
- graphviz (optional, only needed for the C API docs)
|
||||
|
|
198
README.devices
198
README.devices
|
@ -37,6 +37,11 @@ The following drivers/devices require a firmware upload upon connection:
|
|||
'sigrok-firmware' repository/project under a license which allows us
|
||||
to redistribute them.
|
||||
|
||||
- dreamsourcelab-dslogic: The DreamSourceLab DSLogic/DSCope device series
|
||||
requires various firmware files and FPGA bitstream files.
|
||||
These can be extracted/downloaded from the vendor's GitHub repo using a
|
||||
tool from our 'sigrok-util' repository/project.
|
||||
|
||||
- fx2lafw: Logic analyzers based on the Cypress FX2(LP) chip need the
|
||||
firmware files from the 'sigrok-firmware-fx2lafw' repository/project.
|
||||
The firmware is written from scratch and licensed under the GNU GPLv2+.
|
||||
|
@ -64,6 +69,11 @@ The following drivers/devices require a firmware upload upon connection:
|
|||
These can be extracted from the vendor's Linux application using a tool
|
||||
from our 'sigrok-util' repository/project.
|
||||
|
||||
- saleae-logic-pro: The Saleae Logic Pro 16 needs a firmware file for the
|
||||
Cypress FX3 chip in the device, as well as an FPGA bitstream file.
|
||||
These can be extracted from the vendor's Linux application using a tool
|
||||
from our 'sigrok-util' repository/project.
|
||||
|
||||
- sysclk-lwla:
|
||||
|
||||
- The Sysclk LWLA1034 requires various bitstream files.
|
||||
|
@ -74,6 +84,12 @@ The following drivers/devices require a firmware upload upon connection:
|
|||
These can be extracted from the vendor's Windows drivers using a tool
|
||||
from our 'sigrok-util' repository/project.
|
||||
|
||||
- sysclk-sla5032: The Sysclk SLA5032 needs an FPGA bitstream file.
|
||||
This file can be copied (and renamed) from the Windows vendor software
|
||||
installation directory. Details:
|
||||
|
||||
https://sigrok.org/wiki/Sysclk_SLA5032#Firmware
|
||||
|
||||
The following drivers/devices do not need any firmware upload:
|
||||
|
||||
- agilent-dmm
|
||||
|
@ -82,7 +98,6 @@ The following drivers/devices do not need any firmware upload:
|
|||
- atten-pps3xxx
|
||||
- baylibre-acme
|
||||
- beaglelogic
|
||||
- brymen-bm86x
|
||||
- brymen-dmm
|
||||
- cem-dt-885x
|
||||
- center-3xx (including all subdrivers)
|
||||
|
@ -90,28 +105,40 @@ The following drivers/devices do not need any firmware upload:
|
|||
- colead-slm
|
||||
- conrad-digi-35-cpu
|
||||
- demo
|
||||
- fluke-45
|
||||
- fluke-dmm
|
||||
- ftdi-la
|
||||
- gmc-mh-1x-2x (including all subdrivers)
|
||||
- gwinstek-gds-800
|
||||
- gwinstek-gpd
|
||||
- hameg-hmo
|
||||
- hantek-4032l
|
||||
- hp-3457a
|
||||
- hp-3478a
|
||||
- hung-chang-dso-2100
|
||||
- ikalogic-scanalogic2
|
||||
- ikalogic-scanaplus
|
||||
- ipdbg-la
|
||||
- kecheng-kc-330b
|
||||
- kern-scale
|
||||
- korad-kaxxxxp
|
||||
- lascar-el-usb
|
||||
- lecroy-xstream
|
||||
- link-mso19
|
||||
- manson-hcs-3xxx
|
||||
- maynuo-m97
|
||||
- mic-985xx (including all subdrivers)
|
||||
- microchip-pickit2
|
||||
- mooshimeter-dmm
|
||||
- motech-lps-30x
|
||||
- norma-dmm
|
||||
- openbench-logic-sniffer
|
||||
- pce-322a
|
||||
- pipistrello-ols
|
||||
- rdtech-dps
|
||||
- rigol-ds
|
||||
- rohde-schwarz-sme-0x
|
||||
- scpi-dmm
|
||||
- scpi-pps
|
||||
- serial-dmm (including all subdrivers)
|
||||
- serial-lcr (including all subdrivers)
|
||||
|
@ -121,16 +148,23 @@ The following drivers/devices do not need any firmware upload:
|
|||
- tondaj-sl-814
|
||||
- uni-t-dmm (including all subdrivers)
|
||||
- uni-t-ut32x
|
||||
- victor-dmm
|
||||
- yokogawa-dlm
|
||||
- zeroplus-logic-cube
|
||||
- zketech-ebd-usb
|
||||
|
||||
|
||||
Specifying serial ports
|
||||
-----------------------
|
||||
|
||||
Many devices supported by libsigrok use serial port based cables (real RS232
|
||||
or USB-to-serial ones) to connect to a PC.
|
||||
or USB-to-serial ones, CDC class) to connect to a PC. These serial cables are
|
||||
supported by the libserialport library. Some vendors prefer to use HID chips
|
||||
instead of CDC chips in their serial cables. These cables can get supported
|
||||
by means of the hidapi library. Note that each chip type requires specific
|
||||
support in the libsigrok library. Bluetooth connected devices may be supported
|
||||
as well when they communicate by means of RFCOMM channels, or one of the
|
||||
implemented BLE notification/indication approaches, and one of the Bluetooth
|
||||
supporting platforms is used.
|
||||
|
||||
For all these devices, you need to specify the serial port they are connected
|
||||
to (e.g. using the 'conn' option in sigrok-cli). It is not possible to scan
|
||||
|
@ -139,67 +173,42 @@ for such devices without specifying a serial port.
|
|||
Example:
|
||||
|
||||
$ sigrok-cli --driver <somedriver>:conn=/dev/ttyUSB0 ...
|
||||
$ sigrok-cli --driver <somedriver>:conn=hid/cp2110 ...
|
||||
$ sigrok-cli --driver <somedriver>:conn=bt/rfcomm/01-23-45-67-89-ab ...
|
||||
|
||||
The following drivers/devices require a serial port specification. Some of
|
||||
the drivers implement a default for the connection.
|
||||
Formal syntax for serial communication:
|
||||
|
||||
- agilent-dmm
|
||||
- appa-55ii
|
||||
- atten-pps3xxx
|
||||
- brymen-dmm
|
||||
- cem-dt-885x
|
||||
- center-3xx (including all subdrivers)
|
||||
- colead-slm
|
||||
- conrad-digi-35-cpu
|
||||
- fluke-dmm
|
||||
- gmc-mh-1x-2x (including all subdrivers)
|
||||
- hameg-hmo
|
||||
- link-mso19
|
||||
- mic-985xx (including all subdrivers)
|
||||
- norma-dmm
|
||||
- openbench-logic-sniffer
|
||||
- rigol-ds (for RS232; not required for USBTMC or TCP)
|
||||
- serial-dmm (including all subdrivers)
|
||||
- serial-lcr (including all subdrivers)
|
||||
- teleinfo
|
||||
- tondaj-sl-814
|
||||
- COM ports (RS232, USB CDC):
|
||||
conn=<com-port>
|
||||
- USB HID cables:
|
||||
conn=hid[/<chip>]
|
||||
conn=hid[/<chip>]/usb=<bus>.<dev>[.<if>]
|
||||
conn=hid[/<chip>]/raw=<path>
|
||||
conn=hid[/<chip>]/sn=<serno>
|
||||
chip can be: bu86x, ch9325, cp2110, victor
|
||||
path may contain slashes
|
||||
path and serno are "greedy" (span to the end of the spec)
|
||||
- Bluetooth Classic and Bluetooth Low Energy (BLE):
|
||||
conn=bt/<conn>/<addr>
|
||||
conn can be: rfcomm, ble122, nrf51, cc254x
|
||||
addr can be "dense" or separated, bt/cc254x/0123456789ab or
|
||||
bt/rfcomm/11-22-33-44-55-66 or bt/ble122/88:6b:12:34:56:78
|
||||
(note that colons may not be available when the conn= spec is taken
|
||||
from a string that separates fields by colon, e.g. in the "--driver
|
||||
<name>:conn=<spec>" example, that is why the dense form and the use
|
||||
of dashes for separation are supported)
|
||||
|
||||
The following drivers/devices do not require a serial port specification:
|
||||
Some of the drivers implement a default for the connection. Some of the
|
||||
drivers can auto-detect USB connected devices.
|
||||
|
||||
- asix-sigma
|
||||
- brymen-bm86x
|
||||
- chronovu-la
|
||||
- demo
|
||||
- fx2lafw
|
||||
- hantek-dso
|
||||
- ikalogic-scanalogic2
|
||||
- ikalogic-scanaplus
|
||||
- kecheng-kc-330b
|
||||
- lascar-el-usb
|
||||
- pipistrello-ols
|
||||
- rigol-ds (USBTMC or TCP)
|
||||
- saleae-logic16
|
||||
- sysclk-lwla
|
||||
- uni-t-dmm (including all subdrivers)
|
||||
- uni-t-ut32x
|
||||
- victor-dmm
|
||||
- yokogawa-dlm (USBTMC or TCP)
|
||||
- zeroplus-logic-cube
|
||||
|
||||
Beyond strict serial communication over COM ports (e.g. /dev/ttyUSB0), the
|
||||
Beyond strict serial communication over COM ports (discussed above), the
|
||||
conn= property can also address specific USB devices, as well as specify TCP
|
||||
or VXI communication parameters. See these examples:
|
||||
|
||||
$ sigrok-cli --driver <somedriver>:conn=<vid>.<pid> ...
|
||||
$ sigrok-cli --driver <somedriver>:conn=tcp-raw/<ipaddr>/<port> ...
|
||||
$ sigrok-cli --driver <somedriver>:conn=vxi/<ipaddr> ...
|
||||
|
||||
The following drivers/devices accept network communication parameters:
|
||||
|
||||
- hameg-hmo
|
||||
- rigol-ds
|
||||
- siglent-sds
|
||||
- yokogawa-dlm
|
||||
$ sigrok-cli --driver <somedriver>:conn=usbtmc/<bus>.<addr> ...
|
||||
|
||||
|
||||
Specifying serial port parameters
|
||||
|
@ -284,9 +293,11 @@ UNI-T DMM (and rebranded models) cables
|
|||
UNI-T multimeters (and rebranded devices, e.g. some Voltcraft models) can
|
||||
ship with different PC connectivity cables:
|
||||
|
||||
- UT-D02 (RS232 cable)
|
||||
- UT-D04 (USB/HID cable with Hoitek HE2325U chip, USB VID/PID 04fa:2490)
|
||||
- UT-D04 (USB/HID cable with WCH CH9325 chip, USB VID/PID 1a86:e008)
|
||||
- UT-D02 (RS232 cable)
|
||||
- UT-D07 (Bluetooth adapter, ISSC BL79 BLETR chip)
|
||||
- UT-D09 (USB/HID cable with SiL CP2110 chip, USB VID/PID 10c4:ea80)
|
||||
|
||||
The above cables are all physically compatible (same IR connector shape)
|
||||
with all/most currently known UNI-T multimeters. For example, you can
|
||||
|
@ -361,7 +372,12 @@ a short list for convenience:
|
|||
|
||||
- BBC Goertz Metrawatt M2110: Briefly press the "Start/Reset" button on the
|
||||
interface panel on top.
|
||||
- Brymen BM257s: Press HOLD during power-on.
|
||||
- Digitek DT4000ZC: Briefly press the "RS232" button.
|
||||
- EEVBlog 121GW: Hold "1ms PEAK" until the "BT" indicator is shown.
|
||||
- ES51919 based LCR meters (DER EE DE-5000, PeakTech 2170, UNI-T UT612):
|
||||
Press the button with the "RS232" or "USB" or "PC link" label (usually
|
||||
the "up" cursor button).
|
||||
- Gossen Metrawatt Metrahit 1x/2x devices, driver gmc-mh-1x-2x-rs232:
|
||||
- Power on the device with the "DATA" button pressed.
|
||||
- Metrahit 2x devices must be configured for the respective interface type.
|
||||
|
@ -373,6 +389,7 @@ a short list for convenience:
|
|||
'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must
|
||||
be configured to the same baud rate as the host (default 9600).
|
||||
Multimeter and interface must be configured to the same address.
|
||||
- MASTECH MS6514: Press the "Setup/PC-Link" button for roughly 3 seconds.
|
||||
- Metrix MX56C: Press the PRINT button to have the meter send acquisition
|
||||
data via IR. Hold the PRINT button to adjust the meter's transmission
|
||||
interval.
|
||||
|
@ -434,3 +451,74 @@ Example:
|
|||
|
||||
$ sigrok-cli --driver ols:conn=/dev/ttyACM0 ...
|
||||
|
||||
|
||||
Mooshimeter
|
||||
-----------
|
||||
|
||||
The Mooshim Engineering Mooshimeter is controlled via Bluetooth Low Energy
|
||||
(sometimes called Bluetooth 4.0), as such it requires a supported Bluetooth
|
||||
interface available. The 'conn' option is required and must contain the
|
||||
Bluetooth MAC address of the meter.
|
||||
|
||||
Example:
|
||||
|
||||
$ sigrok-cli --driver mooshimeter-dmm:conn=12-34-56-78-9A-BC ...
|
||||
|
||||
Since the Mooshimeter has no physical interface on the meter itself, the
|
||||
channel configuration is set with the 'channel_config' option. The format
|
||||
of this option is 'CH1,CH2' where each channel configuration has the form
|
||||
'MODE:RANGE:ANALYSIS', with later parts being optional. In addition for
|
||||
CLI compatibility, the ',' in the channels can also be a '/' and the ':' in
|
||||
the individual configuration can be a ';'.
|
||||
|
||||
Available channel 1 modes:
|
||||
|
||||
- Current, A: Current in amps
|
||||
- Temperature, T, K: Internal meter temperature in Kelvin
|
||||
- Resistance, Ohm, W: Resistance in ohms
|
||||
- Diode, D: Diode voltage
|
||||
- Aux, LV: Auxiliary (W input) low voltage sensor (1.2V max)
|
||||
|
||||
Available channel 2 modes:
|
||||
|
||||
- Voltage, V: Voltage
|
||||
- Temperature, T, K: Internal meter temperature in Kelvin
|
||||
- Resistance, Ohm, W: Resistance in ohms
|
||||
- Diode, D: Diode voltage
|
||||
- Aux, LV: Auxiliary (W input) low voltage sensor (1.2V max)
|
||||
|
||||
Only one channel can use the shared inputs at a time (e.g. if CH1 is measuring
|
||||
resistance, CH2 cannot measure low voltage). Temperature is excepted from
|
||||
this, so the meter can measure internal temperature and low voltage at the
|
||||
same time.
|
||||
|
||||
Additionally, the meter can calculate the real power of both channels. This
|
||||
generally only makes sense when CH1 is set to current and CH2 is set to a
|
||||
voltage and so it is disabled by default. It must be enabled by enabling the
|
||||
'P' channel (the third channel).
|
||||
|
||||
The range of the channel specification sets the maximum input for that channel
|
||||
and is rounded up to the next value the meter itself supports. For example,
|
||||
specifying 50 for the voltage will result in the actual maximum of 60.
|
||||
Specifying 61 would result in 600. If omitted, sigrok will perform
|
||||
auto-ranging of the channel by selecting the next greater value than the
|
||||
latest maximum.
|
||||
|
||||
The analysis option sets how the meter reports its internal sampling buffer
|
||||
to sigrok:
|
||||
|
||||
- Mean, DC: The default is a simple arithmetic mean of the sample buffer
|
||||
- RMS, AC: The root mean square of the sample buffer
|
||||
- Buf, Buffer, Samples: Report the entire sample buffer to sigrok. This
|
||||
results in packets that contain all the samples in the buffer instead
|
||||
of a single output value.
|
||||
|
||||
The size of the sample buffer is set with the 'avg_samples' option, while
|
||||
the sampling rate is set with the 'samplerate' option. So the update rate
|
||||
is avg_samples/samplerate. Both are rounded up to the next supported value
|
||||
by the meter.
|
||||
|
||||
Example:
|
||||
|
||||
$ sigrok-cli -c channel_config="Aux;0.1/T" --driver mooshimeter-dmm...
|
||||
$ sigrok-cli -c channel_config="A;;AC/V;;AC" --driver mooshimeter-dmm...
|
||||
|
|
|
@ -8,7 +8,7 @@ const DataType *ConfigKey::data_type() const
|
|||
return DataType::get(info->datatype);
|
||||
}
|
||||
|
||||
string ConfigKey::identifier() const
|
||||
std::string ConfigKey::identifier() const
|
||||
{
|
||||
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
|
||||
if (!info)
|
||||
|
@ -16,7 +16,7 @@ string ConfigKey::identifier() const
|
|||
return valid_string(info->id);
|
||||
}
|
||||
|
||||
string ConfigKey::description() const
|
||||
std::string ConfigKey::description() const
|
||||
{
|
||||
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
|
||||
if (!info)
|
||||
|
@ -24,7 +24,7 @@ string ConfigKey::description() const
|
|||
return valid_string(info->name);
|
||||
}
|
||||
|
||||
const ConfigKey *ConfigKey::get_by_identifier(string identifier)
|
||||
const ConfigKey *ConfigKey::get_by_identifier(std::string identifier)
|
||||
{
|
||||
const struct sr_key_info *info = sr_key_info_name_get(SR_KEY_CONFIG, identifier.c_str());
|
||||
if (!info)
|
||||
|
@ -70,7 +70,7 @@ static inline double stod( const std::string& str )
|
|||
}
|
||||
#endif
|
||||
|
||||
Glib::VariantBase ConfigKey::parse_string(string value, enum sr_datatype dt)
|
||||
Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt)
|
||||
{
|
||||
GVariant *variant;
|
||||
uint64_t p, q;
|
||||
|
@ -116,7 +116,7 @@ Glib::VariantBase ConfigKey::parse_string(string value, enum sr_datatype dt)
|
|||
return Glib::VariantBase(variant, false);
|
||||
}
|
||||
|
||||
Glib::VariantBase ConfigKey::parse_string(string value) const
|
||||
Glib::VariantBase ConfigKey::parse_string(std::string value) const
|
||||
{
|
||||
enum sr_datatype dt = (enum sr_datatype)(data_type()->id());
|
||||
return parse_string(value, dt);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/** Data type used for this configuration key. */
|
||||
const DataType *data_type() const;
|
||||
/** String identifier for this configuration key, suitable for CLI use. */
|
||||
string identifier() const;
|
||||
std::string identifier() const;
|
||||
/** Description of this configuration key. */
|
||||
string description() const;
|
||||
std::string description() const;
|
||||
/** Get configuration key by string identifier. */
|
||||
static const ConfigKey *get_by_identifier(string identifier);
|
||||
static const ConfigKey *get_by_identifier(std::string identifier);
|
||||
/** Parse a string argument into the appropriate type for this key. */
|
||||
static Glib::VariantBase parse_string(string value, enum sr_datatype dt);
|
||||
Glib::VariantBase parse_string(string value) const;
|
||||
static Glib::VariantBase parse_string(std::string value, enum sr_datatype dt);
|
||||
Glib::VariantBase parse_string(std::string value) const;
|
||||
|
|
|
@ -743,7 +743,7 @@ WARN_LOGFILE =
|
|||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = include/libsigrokcxx/libsigrokcxx.hpp \
|
||||
INPUT = $(SRCDIR)include/libsigrokcxx/libsigrokcxx.hpp \
|
||||
$(BUILDDIR)include/libsigrokcxx/enums.hpp
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
vector<const QuantityFlag *>
|
||||
std::vector<const QuantityFlag *>
|
||||
QuantityFlag::flags_from_mask(unsigned int mask)
|
||||
{
|
||||
auto result = vector<const QuantityFlag *>();
|
||||
auto result = std::vector<const QuantityFlag *>();
|
||||
while (mask)
|
||||
{
|
||||
unsigned int new_mask = mask & (mask - 1);
|
||||
|
@ -12,7 +12,7 @@ vector<const QuantityFlag *>
|
|||
return result;
|
||||
}
|
||||
|
||||
unsigned int QuantityFlag::mask_from_flags(vector<const QuantityFlag *> flags)
|
||||
unsigned int QuantityFlag::mask_from_flags(std::vector<const QuantityFlag *> flags)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
for (auto flag : flags)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/** Get flags corresponding to a bitmask. */
|
||||
static vector<const QuantityFlag *>
|
||||
static std::vector<const QuantityFlag *>
|
||||
flags_from_mask(unsigned int mask);
|
||||
|
||||
/** Get bitmask corresponding to a set of flags. */
|
||||
static unsigned int mask_from_flags(
|
||||
vector<const QuantityFlag *> flags);
|
||||
std::vector<const QuantityFlag *> flags);
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
namespace sigrok
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
|
||||
/** Helper function to translate C errors to C++ exceptions. */
|
||||
static void check(int result)
|
||||
{
|
||||
|
@ -377,6 +379,14 @@ shared_ptr<Packet> Context::create_analog_packet(
|
|||
return shared_ptr<Packet>{new Packet{nullptr, packet}, default_delete<Packet>{}};
|
||||
}
|
||||
|
||||
shared_ptr<Packet> Context::create_end_packet()
|
||||
{
|
||||
auto packet = g_new(struct sr_datafeed_packet, 1);
|
||||
packet->type = SR_DF_END;
|
||||
return shared_ptr<Packet>{new Packet{nullptr, packet},
|
||||
default_delete<Packet>{}};
|
||||
}
|
||||
|
||||
shared_ptr<Session> Context::load_session(string filename)
|
||||
{
|
||||
return shared_ptr<Session>{
|
||||
|
@ -936,6 +946,7 @@ Session::Session(shared_ptr<Context> context, string filename) :
|
|||
_owned_devices.emplace(sdi, move(device));
|
||||
}
|
||||
_context->_session = this;
|
||||
g_slist_free(dev_list);
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
|
@ -970,6 +981,7 @@ vector<shared_ptr<Device>> Session::devices()
|
|||
auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
|
||||
result.push_back(get_device(sdi));
|
||||
}
|
||||
g_slist_free(dev_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1651,6 +1663,11 @@ Output::~Output()
|
|||
check(sr_output_free(_structure));
|
||||
}
|
||||
|
||||
shared_ptr<OutputFormat> Output::format()
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
|
||||
string Output::receive(shared_ptr<Packet> packet)
|
||||
{
|
||||
GString *out;
|
||||
|
|
|
@ -87,8 +87,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
|||
namespace sigrok
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* Forward declarations */
|
||||
class SR_API Error;
|
||||
class SR_API Context;
|
||||
|
@ -124,7 +122,7 @@ class SR_API Option;
|
|||
class SR_API UserDevice;
|
||||
|
||||
/** Exception thrown when an error code is returned by any libsigrok call. */
|
||||
class SR_API Error: public exception
|
||||
class SR_API Error: public std::exception
|
||||
{
|
||||
public:
|
||||
explicit Error(int result);
|
||||
|
@ -139,7 +137,7 @@ class SR_API ParentOwned
|
|||
{
|
||||
private:
|
||||
/* Weak pointer for shared_from_this() implementation. */
|
||||
weak_ptr<Class> _weak_this;
|
||||
std::weak_ptr<Class> _weak_this;
|
||||
|
||||
static void reset_parent(Class *object)
|
||||
{
|
||||
|
@ -162,14 +160,14 @@ protected:
|
|||
This strategy ensures that the destructors for both the child and
|
||||
the parent are called at the correct time, i.e. only when all
|
||||
references to both the parent and all its children are gone. */
|
||||
shared_ptr<Parent> _parent;
|
||||
std::shared_ptr<Parent> _parent;
|
||||
|
||||
ParentOwned() {}
|
||||
|
||||
/* Note, this implementation will create a new smart_ptr if none exists. */
|
||||
shared_ptr<Class> shared_from_this()
|
||||
std::shared_ptr<Class> shared_from_this()
|
||||
{
|
||||
shared_ptr<Class> shared = _weak_this.lock();
|
||||
std::shared_ptr<Class> shared = _weak_this.lock();
|
||||
|
||||
if (!shared)
|
||||
{
|
||||
|
@ -180,7 +178,7 @@ protected:
|
|||
return shared;
|
||||
}
|
||||
|
||||
shared_ptr<Class> share_owned_by(shared_ptr<Parent> parent)
|
||||
std::shared_ptr<Class> share_owned_by(std::shared_ptr<Parent> parent)
|
||||
{
|
||||
if (!parent)
|
||||
throw Error(SR_ERR_BUG);
|
||||
|
@ -190,7 +188,7 @@ protected:
|
|||
|
||||
public:
|
||||
/* Get parent object that owns this object. */
|
||||
shared_ptr<Parent> parent()
|
||||
std::shared_ptr<Parent> parent()
|
||||
{
|
||||
return _parent;
|
||||
}
|
||||
|
@ -198,14 +196,14 @@ public:
|
|||
|
||||
/* Base template for classes whose resources are owned by the user. */
|
||||
template <class Class>
|
||||
class SR_API UserOwned : public enable_shared_from_this<Class>
|
||||
class SR_API UserOwned : public std::enable_shared_from_this<Class>
|
||||
{
|
||||
protected:
|
||||
UserOwned() {}
|
||||
|
||||
shared_ptr<Class> shared_from_this()
|
||||
std::shared_ptr<Class> shared_from_this()
|
||||
{
|
||||
auto shared = enable_shared_from_this<Class>::shared_from_this();
|
||||
auto shared = std::enable_shared_from_this<Class>::shared_from_this();
|
||||
if (!shared)
|
||||
throw Error(SR_ERR_BUG);
|
||||
return shared;
|
||||
|
@ -213,7 +211,7 @@ protected:
|
|||
};
|
||||
|
||||
/** Type of log callback */
|
||||
typedef function<void(const LogLevel *, string message)> LogCallbackFunction;
|
||||
typedef std::function<void(const LogLevel *, std::string message)> LogCallbackFunction;
|
||||
|
||||
/** Resource reader delegate. */
|
||||
class SR_API ResourceReader
|
||||
|
@ -223,7 +221,7 @@ public:
|
|||
virtual ~ResourceReader();
|
||||
private:
|
||||
/** Resource open hook. */
|
||||
virtual void open(struct sr_resource *res, string name) = 0;
|
||||
virtual void open(struct sr_resource *res, std::string name) = 0;
|
||||
/** Resource close hook. */
|
||||
virtual void close(struct sr_resource *res) = 0;
|
||||
/** Resource read hook. */
|
||||
|
@ -243,19 +241,19 @@ class SR_API Context : public UserOwned<Context>
|
|||
{
|
||||
public:
|
||||
/** Create new context */
|
||||
static shared_ptr<Context> create();
|
||||
static std::shared_ptr<Context> create();
|
||||
/** libsigrok package version. */
|
||||
static string package_version();
|
||||
static std::string package_version();
|
||||
/** libsigrok library version. */
|
||||
static string lib_version();
|
||||
static std::string lib_version();
|
||||
/** Available hardware drivers, indexed by name. */
|
||||
map<string, shared_ptr<Driver> > drivers();
|
||||
std::map<std::string, std::shared_ptr<Driver> > drivers();
|
||||
/** Available input formats, indexed by name. */
|
||||
map<string, shared_ptr<InputFormat> > input_formats();
|
||||
std::map<std::string, std::shared_ptr<InputFormat> > input_formats();
|
||||
/** Lookup the responsible input module for an input file. */
|
||||
shared_ptr<InputFormat> input_format_match(string filename);
|
||||
std::shared_ptr<InputFormat> input_format_match(std::string filename);
|
||||
/** Available output formats, indexed by name. */
|
||||
map<string, shared_ptr<OutputFormat> > output_formats();
|
||||
std::map<std::string, std::shared_ptr<OutputFormat> > output_formats();
|
||||
/** Current log level. */
|
||||
const LogLevel *log_level() const;
|
||||
/** Set the log level.
|
||||
|
@ -270,41 +268,43 @@ public:
|
|||
* @param reader The resource reader delegate, or nullptr to unset. */
|
||||
void set_resource_reader(ResourceReader *reader);
|
||||
/** Create a new session. */
|
||||
shared_ptr<Session> create_session();
|
||||
std::shared_ptr<Session> create_session();
|
||||
/** Create a new user device. */
|
||||
shared_ptr<UserDevice> create_user_device(
|
||||
string vendor, string model, string version);
|
||||
std::shared_ptr<UserDevice> create_user_device(
|
||||
std::string vendor, std::string model, std::string version);
|
||||
/** Create a header packet. */
|
||||
shared_ptr<Packet> create_header_packet(Glib::TimeVal start_time);
|
||||
std::shared_ptr<Packet> create_header_packet(Glib::TimeVal start_time);
|
||||
/** Create a meta packet. */
|
||||
shared_ptr<Packet> create_meta_packet(
|
||||
map<const ConfigKey *, Glib::VariantBase> config);
|
||||
std::shared_ptr<Packet> create_meta_packet(
|
||||
std::map<const ConfigKey *, Glib::VariantBase> config);
|
||||
/** Create a logic packet. */
|
||||
shared_ptr<Packet> create_logic_packet(
|
||||
std::shared_ptr<Packet> create_logic_packet(
|
||||
void *data_pointer, size_t data_length, unsigned int unit_size);
|
||||
/** Create an analog packet. */
|
||||
shared_ptr<Packet> create_analog_packet(
|
||||
vector<shared_ptr<Channel> > channels,
|
||||
std::shared_ptr<Packet> create_analog_packet(
|
||||
std::vector<std::shared_ptr<Channel> > channels,
|
||||
float *data_pointer, unsigned int num_samples, const Quantity *mq,
|
||||
const Unit *unit, vector<const QuantityFlag *> mqflags);
|
||||
const Unit *unit, std::vector<const QuantityFlag *> mqflags);
|
||||
/** Create an end packet. */
|
||||
std::shared_ptr<Packet> create_end_packet();
|
||||
/** Load a saved session.
|
||||
* @param filename File name string. */
|
||||
shared_ptr<Session> load_session(string filename);
|
||||
std::shared_ptr<Session> load_session(std::string filename);
|
||||
/** Create a new trigger.
|
||||
* @param name Name string for new trigger. */
|
||||
shared_ptr<Trigger> create_trigger(string name);
|
||||
std::shared_ptr<Trigger> create_trigger(std::string name);
|
||||
/** Open an input file.
|
||||
* @param filename File name string. */
|
||||
shared_ptr<Input> open_file(string filename);
|
||||
std::shared_ptr<Input> open_file(std::string filename);
|
||||
/** Open an input stream based on header data.
|
||||
* @param header Initial data from stream. */
|
||||
shared_ptr<Input> open_stream(string header);
|
||||
map<string, string> serials(shared_ptr<Driver> driver) const;
|
||||
std::shared_ptr<Input> open_stream(std::string header);
|
||||
std::map<std::string, std::string> serials(std::shared_ptr<Driver> driver) const;
|
||||
private:
|
||||
struct sr_context *_structure;
|
||||
map<string, unique_ptr<Driver> > _drivers;
|
||||
map<string, unique_ptr<InputFormat> > _input_formats;
|
||||
map<string, unique_ptr<OutputFormat> > _output_formats;
|
||||
std::map<std::string, std::unique_ptr<Driver> > _drivers;
|
||||
std::map<std::string, std::unique_ptr<InputFormat> > _input_formats;
|
||||
std::map<std::string, std::unique_ptr<OutputFormat> > _output_formats;
|
||||
Session *_session;
|
||||
LogCallbackFunction _log_callback;
|
||||
Context();
|
||||
|
@ -319,7 +319,7 @@ class SR_API Configurable
|
|||
{
|
||||
public:
|
||||
/** Supported configuration keys. */
|
||||
set<const ConfigKey *> config_keys() const;
|
||||
std::set<const ConfigKey *> config_keys() const;
|
||||
/** Read configuration for the given key.
|
||||
* @param key ConfigKey to read. */
|
||||
Glib::VariantBase config_get(const ConfigKey *key) const;
|
||||
|
@ -332,7 +332,7 @@ public:
|
|||
Glib::VariantContainerBase config_list(const ConfigKey *key) const;
|
||||
/** Enumerate configuration capabilities for the given configuration key.
|
||||
* @param key ConfigKey to enumerate capabilities for. */
|
||||
set<const Capability *> config_capabilities(const ConfigKey *key) const;
|
||||
std::set<const Capability *> config_capabilities(const ConfigKey *key) const;
|
||||
/** Check whether a configuration capability is supported for a given key.
|
||||
* @param key ConfigKey to check.
|
||||
* @param capability Capability to check for. */
|
||||
|
@ -353,19 +353,19 @@ class SR_API Driver : public ParentOwned<Driver, Context>, public Configurable
|
|||
{
|
||||
public:
|
||||
/** Name of this driver. */
|
||||
string name() const;
|
||||
std::string name() const;
|
||||
/** Long name for this driver. */
|
||||
string long_name() const;
|
||||
std::string long_name() const;
|
||||
/** Scan options supported by this driver. */
|
||||
set<const ConfigKey *> scan_options() const;
|
||||
std::set<const ConfigKey *> scan_options() const;
|
||||
/** Scan for devices and return a list of devices found.
|
||||
* @param options Mapping of (ConfigKey, value) pairs. */
|
||||
vector<shared_ptr<HardwareDevice> > scan(map<const ConfigKey *, Glib::VariantBase>
|
||||
options = map<const ConfigKey *, Glib::VariantBase>());
|
||||
std::vector<std::shared_ptr<HardwareDevice> > scan(std::map<const ConfigKey *, Glib::VariantBase>
|
||||
options = std::map<const ConfigKey *, Glib::VariantBase>());
|
||||
private:
|
||||
struct sr_dev_driver *_structure;
|
||||
bool _initialized;
|
||||
vector<HardwareDevice *> _devices;
|
||||
std::vector<HardwareDevice *> _devices;
|
||||
explicit Driver(struct sr_dev_driver *structure);
|
||||
~Driver();
|
||||
friend class Context;
|
||||
|
@ -379,19 +379,19 @@ class SR_API Device : public Configurable
|
|||
{
|
||||
public:
|
||||
/** Vendor name for this device. */
|
||||
string vendor() const;
|
||||
std::string vendor() const;
|
||||
/** Model name for this device. */
|
||||
string model() const;
|
||||
std::string model() const;
|
||||
/** Version string for this device. */
|
||||
string version() const;
|
||||
std::string version() const;
|
||||
/** Serial number for this device. */
|
||||
string serial_number() const;
|
||||
std::string serial_number() const;
|
||||
/** Connection ID for this device. */
|
||||
string connection_id() const;
|
||||
std::string connection_id() const;
|
||||
/** List of the channels available on this device. */
|
||||
vector<shared_ptr<Channel> > channels();
|
||||
std::vector<std::shared_ptr<Channel> > channels();
|
||||
/** Channel groups available on this device, indexed by name. */
|
||||
map<string, shared_ptr<ChannelGroup> > channel_groups();
|
||||
std::map<std::string, std::shared_ptr<ChannelGroup> > channel_groups();
|
||||
/** Open device. */
|
||||
void open();
|
||||
/** Close device. */
|
||||
|
@ -399,13 +399,13 @@ public:
|
|||
protected:
|
||||
explicit Device(struct sr_dev_inst *structure);
|
||||
~Device();
|
||||
virtual shared_ptr<Device> get_shared_from_this() = 0;
|
||||
shared_ptr<Channel> get_channel(struct sr_channel *ptr);
|
||||
virtual std::shared_ptr<Device> get_shared_from_this() = 0;
|
||||
std::shared_ptr<Channel> get_channel(struct sr_channel *ptr);
|
||||
|
||||
struct sr_dev_inst *_structure;
|
||||
map<struct sr_channel *, unique_ptr<Channel> > _channels;
|
||||
std::map<struct sr_channel *, std::unique_ptr<Channel> > _channels;
|
||||
private:
|
||||
map<string, unique_ptr<ChannelGroup> > _channel_groups;
|
||||
std::map<std::string, std::unique_ptr<ChannelGroup> > _channel_groups;
|
||||
|
||||
friend class Session;
|
||||
friend class Channel;
|
||||
|
@ -422,12 +422,12 @@ class SR_API HardwareDevice :
|
|||
{
|
||||
public:
|
||||
/** Driver providing this device. */
|
||||
shared_ptr<Driver> driver();
|
||||
std::shared_ptr<Driver> driver();
|
||||
private:
|
||||
HardwareDevice(shared_ptr<Driver> driver, struct sr_dev_inst *structure);
|
||||
HardwareDevice(std::shared_ptr<Driver> driver, struct sr_dev_inst *structure);
|
||||
~HardwareDevice();
|
||||
shared_ptr<Device> get_shared_from_this();
|
||||
shared_ptr<Driver> _driver;
|
||||
std::shared_ptr<Device> get_shared_from_this();
|
||||
std::shared_ptr<Driver> _driver;
|
||||
|
||||
friend class Driver;
|
||||
friend class ChannelGroup;
|
||||
|
@ -441,11 +441,11 @@ class SR_API UserDevice :
|
|||
{
|
||||
public:
|
||||
/** Add a new channel to this device. */
|
||||
shared_ptr<Channel> add_channel(unsigned int index, const ChannelType *type, string name);
|
||||
std::shared_ptr<Channel> add_channel(unsigned int index, const ChannelType *type, std::string name);
|
||||
private:
|
||||
UserDevice(string vendor, string model, string version);
|
||||
UserDevice(std::string vendor, std::string model, std::string version);
|
||||
~UserDevice();
|
||||
shared_ptr<Device> get_shared_from_this();
|
||||
std::shared_ptr<Device> get_shared_from_this();
|
||||
|
||||
friend class Context;
|
||||
friend struct std::default_delete<UserDevice>;
|
||||
|
@ -457,10 +457,10 @@ class SR_API Channel :
|
|||
{
|
||||
public:
|
||||
/** Current name of this channel. */
|
||||
string name() const;
|
||||
std::string name() const;
|
||||
/** Set the name of this channel. *
|
||||
* @param name Name string to set. */
|
||||
void set_name(string name);
|
||||
void set_name(std::string name);
|
||||
/** Type of this channel. */
|
||||
const ChannelType *type() const;
|
||||
/** Enabled status of this channel. */
|
||||
|
@ -491,13 +491,13 @@ class SR_API ChannelGroup :
|
|||
{
|
||||
public:
|
||||
/** Name of this channel group. */
|
||||
string name() const;
|
||||
std::string name() const;
|
||||
/** List of the channels in this group. */
|
||||
vector<shared_ptr<Channel> > channels();
|
||||
std::vector<std::shared_ptr<Channel> > channels();
|
||||
private:
|
||||
ChannelGroup(const Device *device, struct sr_channel_group *structure);
|
||||
~ChannelGroup();
|
||||
vector<Channel *> _channels;
|
||||
std::vector<Channel *> _channels;
|
||||
friend class Device;
|
||||
friend struct std::default_delete<ChannelGroup>;
|
||||
};
|
||||
|
@ -507,17 +507,17 @@ class SR_API Trigger : public UserOwned<Trigger>
|
|||
{
|
||||
public:
|
||||
/** Name of this trigger configuration. */
|
||||
string name() const;
|
||||
std::string name() const;
|
||||
/** List of the stages in this trigger. */
|
||||
vector<shared_ptr<TriggerStage> > stages();
|
||||
std::vector<std::shared_ptr<TriggerStage> > stages();
|
||||
/** Add a new stage to this trigger. */
|
||||
shared_ptr<TriggerStage> add_stage();
|
||||
std::shared_ptr<TriggerStage> add_stage();
|
||||
private:
|
||||
Trigger(shared_ptr<Context> context, string name);
|
||||
Trigger(std::shared_ptr<Context> context, std::string name);
|
||||
~Trigger();
|
||||
struct sr_trigger *_structure;
|
||||
shared_ptr<Context> _context;
|
||||
vector<unique_ptr<TriggerStage> > _stages;
|
||||
std::shared_ptr<Context> _context;
|
||||
std::vector<std::unique_ptr<TriggerStage> > _stages;
|
||||
friend class Context;
|
||||
friend class Session;
|
||||
friend struct std::default_delete<Trigger>;
|
||||
|
@ -531,19 +531,19 @@ public:
|
|||
/** Index number of this stage. */
|
||||
int number() const;
|
||||
/** List of match conditions on this stage. */
|
||||
vector<shared_ptr<TriggerMatch> > matches();
|
||||
std::vector<std::shared_ptr<TriggerMatch> > matches();
|
||||
/** Add a new match condition to this stage.
|
||||
* @param channel Channel to match on.
|
||||
* @param type TriggerMatchType to apply. */
|
||||
void add_match(shared_ptr<Channel> channel, const TriggerMatchType *type);
|
||||
void add_match(std::shared_ptr<Channel> channel, const TriggerMatchType *type);
|
||||
/** Add a new match condition to this stage.
|
||||
* @param channel Channel to match on.
|
||||
* @param type TriggerMatchType to apply.
|
||||
* @param value Threshold value. */
|
||||
void add_match(shared_ptr<Channel> channel, const TriggerMatchType *type, float value);
|
||||
void add_match(std::shared_ptr<Channel> channel, const TriggerMatchType *type, float value);
|
||||
private:
|
||||
struct sr_trigger_stage *_structure;
|
||||
vector<unique_ptr<TriggerMatch> > _matches;
|
||||
std::vector<std::unique_ptr<TriggerMatch> > _matches;
|
||||
explicit TriggerStage(struct sr_trigger_stage *structure);
|
||||
~TriggerStage();
|
||||
friend class Trigger;
|
||||
|
@ -556,25 +556,25 @@ class SR_API TriggerMatch :
|
|||
{
|
||||
public:
|
||||
/** Channel this condition matches on. */
|
||||
shared_ptr<Channel> channel();
|
||||
std::shared_ptr<Channel> channel();
|
||||
/** Type of match. */
|
||||
const TriggerMatchType *type() const;
|
||||
/** Threshold value. */
|
||||
float value() const;
|
||||
private:
|
||||
TriggerMatch(struct sr_trigger_match *structure, shared_ptr<Channel> channel);
|
||||
TriggerMatch(struct sr_trigger_match *structure, std::shared_ptr<Channel> channel);
|
||||
~TriggerMatch();
|
||||
struct sr_trigger_match *_structure;
|
||||
shared_ptr<Channel> _channel;
|
||||
std::shared_ptr<Channel> _channel;
|
||||
friend class TriggerStage;
|
||||
friend struct std::default_delete<TriggerMatch>;
|
||||
};
|
||||
|
||||
/** Type of session stopped callback */
|
||||
typedef function<void()> SessionStoppedCallback;
|
||||
typedef std::function<void()> SessionStoppedCallback;
|
||||
|
||||
/** Type of datafeed callback */
|
||||
typedef function<void(shared_ptr<Device>, shared_ptr<Packet>)>
|
||||
typedef std::function<void(std::shared_ptr<Device>, std::shared_ptr<Packet>)>
|
||||
DatafeedCallbackFunction;
|
||||
|
||||
/* Data required for C callback function to call a C++ datafeed callback */
|
||||
|
@ -599,7 +599,7 @@ class SR_API SessionDevice :
|
|||
private:
|
||||
explicit SessionDevice(struct sr_dev_inst *sdi);
|
||||
~SessionDevice();
|
||||
shared_ptr<Device> get_shared_from_this();
|
||||
std::shared_ptr<Device> get_shared_from_this();
|
||||
|
||||
friend class Session;
|
||||
friend struct std::default_delete<SessionDevice>;
|
||||
|
@ -611,9 +611,9 @@ class SR_API Session : public UserOwned<Session>
|
|||
public:
|
||||
/** Add a device to this session.
|
||||
* @param device Device to add. */
|
||||
void add_device(shared_ptr<Device> device);
|
||||
void add_device(std::shared_ptr<Device> device);
|
||||
/** List devices attached to this session. */
|
||||
vector<shared_ptr<Device> > devices();
|
||||
std::vector<std::shared_ptr<Device> > devices();
|
||||
/** Remove all devices from this session. */
|
||||
void remove_devices();
|
||||
/** Add a datafeed callback to this session.
|
||||
|
@ -632,27 +632,27 @@ public:
|
|||
/** Set callback to be invoked on session stop. */
|
||||
void set_stopped_callback(SessionStoppedCallback callback);
|
||||
/** Get current trigger setting. */
|
||||
shared_ptr<Trigger> trigger();
|
||||
std::shared_ptr<Trigger> trigger();
|
||||
/** Get the context. */
|
||||
shared_ptr<Context> context();
|
||||
std::shared_ptr<Context> context();
|
||||
/** Set trigger setting.
|
||||
* @param trigger Trigger object to use. */
|
||||
void set_trigger(shared_ptr<Trigger> trigger);
|
||||
void set_trigger(std::shared_ptr<Trigger> trigger);
|
||||
/** Get filename this session was loaded from. */
|
||||
string filename() const;
|
||||
std::string filename() const;
|
||||
private:
|
||||
explicit Session(shared_ptr<Context> context);
|
||||
Session(shared_ptr<Context> context, string filename);
|
||||
explicit Session(std::shared_ptr<Context> context);
|
||||
Session(std::shared_ptr<Context> context, std::string filename);
|
||||
~Session();
|
||||
shared_ptr<Device> get_device(const struct sr_dev_inst *sdi);
|
||||
std::shared_ptr<Device> get_device(const struct sr_dev_inst *sdi);
|
||||
struct sr_session *_structure;
|
||||
const shared_ptr<Context> _context;
|
||||
map<const struct sr_dev_inst *, unique_ptr<SessionDevice> > _owned_devices;
|
||||
map<const struct sr_dev_inst *, shared_ptr<Device> > _other_devices;
|
||||
vector<unique_ptr<DatafeedCallbackData> > _datafeed_callbacks;
|
||||
const std::shared_ptr<Context> _context;
|
||||
std::map<const struct sr_dev_inst *, std::unique_ptr<SessionDevice> > _owned_devices;
|
||||
std::map<const struct sr_dev_inst *, std::shared_ptr<Device> > _other_devices;
|
||||
std::vector<std::unique_ptr<DatafeedCallbackData> > _datafeed_callbacks;
|
||||
SessionStoppedCallback _stopped_callback;
|
||||
string _filename;
|
||||
shared_ptr<Trigger> _trigger;
|
||||
std::string _filename;
|
||||
std::shared_ptr<Trigger> _trigger;
|
||||
|
||||
friend class Context;
|
||||
friend class DatafeedCallbackData;
|
||||
|
@ -667,14 +667,14 @@ public:
|
|||
/** Type of this packet. */
|
||||
const PacketType *type() const;
|
||||
/** Payload of this packet. */
|
||||
shared_ptr<PacketPayload> payload();
|
||||
std::shared_ptr<PacketPayload> payload();
|
||||
private:
|
||||
Packet(shared_ptr<Device> device,
|
||||
Packet(std::shared_ptr<Device> device,
|
||||
const struct sr_datafeed_packet *structure);
|
||||
~Packet();
|
||||
const struct sr_datafeed_packet *_structure;
|
||||
shared_ptr<Device> _device;
|
||||
unique_ptr<PacketPayload> _payload;
|
||||
std::shared_ptr<Device> _device;
|
||||
std::unique_ptr<PacketPayload> _payload;
|
||||
|
||||
friend class Session;
|
||||
friend class Output;
|
||||
|
@ -694,7 +694,7 @@ protected:
|
|||
PacketPayload();
|
||||
virtual ~PacketPayload() = 0;
|
||||
private:
|
||||
virtual shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent) = 0;
|
||||
virtual std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent) = 0;
|
||||
|
||||
friend class Packet;
|
||||
friend class Output;
|
||||
|
@ -714,7 +714,7 @@ public:
|
|||
private:
|
||||
explicit Header(const struct sr_datafeed_header *structure);
|
||||
~Header();
|
||||
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
|
||||
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
|
||||
|
||||
const struct sr_datafeed_header *_structure;
|
||||
|
||||
|
@ -728,14 +728,14 @@ class SR_API Meta :
|
|||
{
|
||||
public:
|
||||
/* Mapping of (ConfigKey, value) pairs. */
|
||||
map<const ConfigKey *, Glib::VariantBase> config() const;
|
||||
std::map<const ConfigKey *, Glib::VariantBase> config() const;
|
||||
private:
|
||||
explicit Meta(const struct sr_datafeed_meta *structure);
|
||||
~Meta();
|
||||
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
|
||||
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
|
||||
|
||||
const struct sr_datafeed_meta *_structure;
|
||||
map<const ConfigKey *, Glib::VariantBase> _config;
|
||||
std::map<const ConfigKey *, Glib::VariantBase> _config;
|
||||
|
||||
friend class Packet;
|
||||
};
|
||||
|
@ -755,7 +755,7 @@ public:
|
|||
private:
|
||||
explicit Logic(const struct sr_datafeed_logic *structure);
|
||||
~Logic();
|
||||
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
|
||||
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
|
||||
|
||||
const struct sr_datafeed_logic *_structure;
|
||||
|
||||
|
@ -780,7 +780,7 @@ public:
|
|||
/** Number of samples in this packet. */
|
||||
unsigned int num_samples() const;
|
||||
/** Channels for which this packet contains data. */
|
||||
vector<shared_ptr<Channel> > channels();
|
||||
std::vector<std::shared_ptr<Channel> > channels();
|
||||
/** Size of a single sample in bytes. */
|
||||
unsigned int unitsize() const;
|
||||
/** Samples use a signed data type. */
|
||||
|
@ -798,15 +798,15 @@ public:
|
|||
/** TBD */
|
||||
bool is_digits_decimal() const;
|
||||
/** TBD */
|
||||
shared_ptr<Rational> scale();
|
||||
std::shared_ptr<Rational> scale();
|
||||
/** TBD */
|
||||
shared_ptr<Rational> offset();
|
||||
std::shared_ptr<Rational> offset();
|
||||
/** Measured quantity of the samples in this packet. */
|
||||
const Quantity *mq() const;
|
||||
/** Unit of the samples in this packet. */
|
||||
const Unit *unit() const;
|
||||
/** Measurement flags associated with the samples in this packet. */
|
||||
vector<const QuantityFlag *> mq_flags() const;
|
||||
std::vector<const QuantityFlag *> mq_flags() const;
|
||||
/**
|
||||
* Provides a Logic packet that contains a conversion of the analog
|
||||
* data using a simple threshold.
|
||||
|
@ -817,7 +817,7 @@ public:
|
|||
* logic->data_pointer() will be allocated and must
|
||||
* be freed by the caller.
|
||||
*/
|
||||
shared_ptr<Logic> get_logic_via_threshold(float threshold,
|
||||
std::shared_ptr<Logic> get_logic_via_threshold(float threshold,
|
||||
uint8_t *data_ptr=nullptr) const;
|
||||
/**
|
||||
* Provides a Logic packet that contains a conversion of the analog
|
||||
|
@ -833,12 +833,12 @@ public:
|
|||
* logic->data_pointer() will be allocated and must be
|
||||
* freed by the caller.
|
||||
*/
|
||||
shared_ptr<Logic> get_logic_via_schmitt_trigger(float lo_thr,
|
||||
std::shared_ptr<Logic> get_logic_via_schmitt_trigger(float lo_thr,
|
||||
float hi_thr, uint8_t *state, uint8_t *data_ptr=nullptr) const;
|
||||
private:
|
||||
explicit Analog(const struct sr_datafeed_analog *structure);
|
||||
~Analog();
|
||||
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
|
||||
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
|
||||
|
||||
const struct sr_datafeed_analog *_structure;
|
||||
|
||||
|
@ -859,7 +859,7 @@ public:
|
|||
private:
|
||||
explicit Rational(const struct sr_rational *structure);
|
||||
~Rational();
|
||||
shared_ptr<Rational> share_owned_by(shared_ptr<Analog> parent);
|
||||
std::shared_ptr<Rational> share_owned_by(std::shared_ptr<Analog> parent);
|
||||
|
||||
const struct sr_rational *_structure;
|
||||
|
||||
|
@ -873,18 +873,18 @@ class SR_API InputFormat :
|
|||
{
|
||||
public:
|
||||
/** Name of this input format. */
|
||||
string name() const;
|
||||
std::string name() const;
|
||||
/** Description of this input format. */
|
||||
string description() const;
|
||||
std::string description() const;
|
||||
/** A list of preferred file name extensions for this file format.
|
||||
* @note This list is a recommendation only. */
|
||||
vector<string> extensions() const;
|
||||
std::vector<std::string> extensions() const;
|
||||
/** Options supported by this input format. */
|
||||
map<string, shared_ptr<Option> > options();
|
||||
std::map<std::string, std::shared_ptr<Option> > options();
|
||||
/** Create an input using this input format.
|
||||
* @param options Mapping of (option name, value) pairs. */
|
||||
shared_ptr<Input> create_input(map<string, Glib::VariantBase>
|
||||
options = map<string, Glib::VariantBase>());
|
||||
std::shared_ptr<Input> create_input(std::map<std::string, Glib::VariantBase>
|
||||
options = std::map<std::string, Glib::VariantBase>());
|
||||
private:
|
||||
explicit InputFormat(const struct sr_input_module *structure);
|
||||
~InputFormat();
|
||||
|
@ -901,7 +901,7 @@ class SR_API Input : public UserOwned<Input>
|
|||
{
|
||||
public:
|
||||
/** Virtual device associated with this input. */
|
||||
shared_ptr<InputDevice> device();
|
||||
std::shared_ptr<InputDevice> device();
|
||||
/** Send next stream data.
|
||||
* @param data Next stream data.
|
||||
* @param length Length of data. */
|
||||
|
@ -910,11 +910,11 @@ public:
|
|||
void end();
|
||||
void reset();
|
||||
private:
|
||||
Input(shared_ptr<Context> context, const struct sr_input *structure);
|
||||
Input(std::shared_ptr<Context> context, const struct sr_input *structure);
|
||||
~Input();
|
||||
const struct sr_input *_structure;
|
||||
shared_ptr<Context> _context;
|
||||
unique_ptr<InputDevice> _device;
|
||||
std::shared_ptr<Context> _context;
|
||||
std::unique_ptr<InputDevice> _device;
|
||||
|
||||
friend class Context;
|
||||
friend class InputFormat;
|
||||
|
@ -927,10 +927,10 @@ class SR_API InputDevice :
|
|||
public Device
|
||||
{
|
||||
private:
|
||||
InputDevice(shared_ptr<Input> input, struct sr_dev_inst *sdi);
|
||||
InputDevice(std::shared_ptr<Input> input, struct sr_dev_inst *sdi);
|
||||
~InputDevice();
|
||||
shared_ptr<Device> get_shared_from_this();
|
||||
shared_ptr<Input> _input;
|
||||
std::shared_ptr<Device> get_shared_from_this();
|
||||
std::shared_ptr<Input> _input;
|
||||
friend class Input;
|
||||
friend struct std::default_delete<InputDevice>;
|
||||
};
|
||||
|
@ -940,23 +940,23 @@ class SR_API Option : public UserOwned<Option>
|
|||
{
|
||||
public:
|
||||
/** Short name of this option suitable for command line usage. */
|
||||
string id() const;
|
||||
std::string id() const;
|
||||
/** Short name of this option suitable for GUI usage. */
|
||||
string name() const;
|
||||
std::string name() const;
|
||||
/** Description of this option in a sentence. */
|
||||
string description() const;
|
||||
std::string description() const;
|
||||
/** Default value for this option. */
|
||||
Glib::VariantBase default_value() const;
|
||||
/** Possible values for this option, if a limited set. */
|
||||
vector<Glib::VariantBase> values() const;
|
||||
std::vector<Glib::VariantBase> values() const;
|
||||
/** Parse a string argument into the appropriate type for this option. */
|
||||
Glib::VariantBase parse_string(string value);
|
||||
Glib::VariantBase parse_string(std::string value);
|
||||
private:
|
||||
Option(const struct sr_option *structure,
|
||||
shared_ptr<const struct sr_option *> structure_array);
|
||||
std::shared_ptr<const struct sr_option *> structure_array);
|
||||
~Option();
|
||||
const struct sr_option *_structure;
|
||||
shared_ptr<const struct sr_option *> _structure_array;
|
||||
std::shared_ptr<const struct sr_option *> _structure_array;
|
||||
|
||||
friend class InputFormat;
|
||||
friend class OutputFormat;
|
||||
|
@ -969,26 +969,26 @@ class SR_API OutputFormat :
|
|||
{
|
||||
public:
|
||||
/** Name of this output format. */
|
||||
string name() const;
|
||||
std::string name() const;
|
||||
/** Description of this output format. */
|
||||
string description() const;
|
||||
std::string description() const;
|
||||
/** A list of preferred file name extensions for this file format.
|
||||
* @note This list is a recommendation only. */
|
||||
vector<string> extensions() const;
|
||||
std::vector<std::string> extensions() const;
|
||||
/** Options supported by this output format. */
|
||||
map<string, shared_ptr<Option> > options();
|
||||
std::map<std::string, std::shared_ptr<Option> > options();
|
||||
/** Create an output using this format.
|
||||
* @param device Device to output for.
|
||||
* @param options Mapping of (option name, value) pairs. */
|
||||
shared_ptr<Output> create_output(shared_ptr<Device> device,
|
||||
map<string, Glib::VariantBase> options = map<string, Glib::VariantBase>());
|
||||
std::shared_ptr<Output> create_output(std::shared_ptr<Device> device,
|
||||
std::map<std::string, Glib::VariantBase> options = std::map<std::string, Glib::VariantBase>());
|
||||
/** Create an output using this format.
|
||||
* @param filename Name of destination file.
|
||||
* @param device Device to output for.
|
||||
* @param options Mapping of (option name, value) pairs. */
|
||||
shared_ptr<Output> create_output(string filename,
|
||||
shared_ptr<Device> device,
|
||||
map<string, Glib::VariantBase> options = map<string, Glib::VariantBase>());
|
||||
std::shared_ptr<Output> create_output(std::string filename,
|
||||
std::shared_ptr<Device> device,
|
||||
std::map<std::string, Glib::VariantBase> options = std::map<std::string, Glib::VariantBase>());
|
||||
/**
|
||||
* Checks whether a given flag is set.
|
||||
* @param flag Flag to check
|
||||
|
@ -1013,19 +1013,21 @@ class SR_API Output : public UserOwned<Output>
|
|||
public:
|
||||
/** Update output with data from the given packet.
|
||||
* @param packet Packet to handle. */
|
||||
string receive(shared_ptr<Packet> packet);
|
||||
std::string receive(std::shared_ptr<Packet> packet);
|
||||
/** Output format in use for this output */
|
||||
std::shared_ptr<OutputFormat> format();
|
||||
private:
|
||||
Output(shared_ptr<OutputFormat> format, shared_ptr<Device> device);
|
||||
Output(shared_ptr<OutputFormat> format,
|
||||
shared_ptr<Device> device, map<string, Glib::VariantBase> options);
|
||||
Output(string filename, shared_ptr<OutputFormat> format,
|
||||
shared_ptr<Device> device, map<string, Glib::VariantBase> options);
|
||||
Output(std::shared_ptr<OutputFormat> format, std::shared_ptr<Device> device);
|
||||
Output(std::shared_ptr<OutputFormat> format,
|
||||
std::shared_ptr<Device> device, std::map<std::string, Glib::VariantBase> options);
|
||||
Output(std::string filename, std::shared_ptr<OutputFormat> format,
|
||||
std::shared_ptr<Device> device, std::map<std::string, Glib::VariantBase> options);
|
||||
~Output();
|
||||
|
||||
const struct sr_output *_structure;
|
||||
const shared_ptr<OutputFormat> _format;
|
||||
const shared_ptr<Device> _device;
|
||||
const map<string, Glib::VariantBase> _options;
|
||||
const std::shared_ptr<OutputFormat> _format;
|
||||
const std::shared_ptr<Device> _device;
|
||||
const std::map<std::string, Glib::VariantBase> _options;
|
||||
|
||||
friend class OutputFormat;
|
||||
friend struct std::default_delete<Output>;
|
||||
|
@ -1041,7 +1043,7 @@ public:
|
|||
return static_cast<int>(_id);
|
||||
}
|
||||
/** The name associated with this value. */
|
||||
string name() const
|
||||
std::string name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
@ -1071,7 +1073,7 @@ protected:
|
|||
private:
|
||||
static const std::map<const Enum, const Class * const> _values;
|
||||
const Enum _id;
|
||||
const string _name;
|
||||
const std::string _name;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -743,7 +743,7 @@ WARN_LOGFILE =
|
|||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = org/sigrok/core $(BUILDDIR)org/sigrok/core
|
||||
INPUT = $(SRCDIR)org/sigrok/core $(BUILDDIR)org/sigrok/core
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
|
|
@ -390,6 +390,7 @@ std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
|
|||
|
||||
/* Ignore these methods, we will override them below. */
|
||||
%ignore sigrok::Analog::data;
|
||||
%ignore sigrok::Logic::data;
|
||||
%ignore sigrok::Driver::scan;
|
||||
%ignore sigrok::InputFormat::create_input;
|
||||
%ignore sigrok::OutputFormat::create_output;
|
||||
|
@ -548,4 +549,42 @@ std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
|
|||
}
|
||||
}
|
||||
|
||||
/* Return NumPy array from Logic::data(). */
|
||||
%extend sigrok::Logic
|
||||
{
|
||||
PyObject * _data()
|
||||
{
|
||||
npy_intp dims[2];
|
||||
dims[0] = $self->data_length() / $self->unit_size();
|
||||
dims[1] = $self->unit_size();
|
||||
int typenum = NPY_UINT8;
|
||||
void *data = $self->data_pointer();
|
||||
return PyArray_SimpleNewFromData(2, dims, typenum, data);
|
||||
}
|
||||
|
||||
%pythoncode
|
||||
{
|
||||
data = property(_data)
|
||||
}
|
||||
}
|
||||
|
||||
/* Create logic packet from Python buffer. */
|
||||
%extend sigrok::Context
|
||||
{
|
||||
std::shared_ptr<Packet> _create_logic_packet_buf(PyObject *buf, unsigned int unit_size)
|
||||
{
|
||||
Py_buffer view;
|
||||
PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE);
|
||||
return $self->create_logic_packet(view.buf, view.len, unit_size);
|
||||
}
|
||||
}
|
||||
|
||||
%pythoncode
|
||||
{
|
||||
def _Context_create_logic_packet(self, buf, unit_size):
|
||||
return self._create_logic_packet_buf(buf, unit_size)
|
||||
|
||||
Context.create_logic_packet = _Context_create_logic_packet
|
||||
}
|
||||
|
||||
%include "doc_end.i"
|
||||
|
|
112
configure.ac
112
configure.ac
|
@ -96,11 +96,17 @@ SR_PKGLIBS_RUBY=
|
|||
SR_EXTRA_LIBS=
|
||||
SR_EXTRA_CXX_LIBS=
|
||||
|
||||
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
|
||||
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], ,
|
||||
[libserialport >= 0.1.1])
|
||||
|
||||
SR_ARG_OPT_PKG([libftdi], [LIBFTDI], , [libftdi1 >= 1.0])
|
||||
|
||||
# pkg-config file names: MinGW/MacOSX: hidapi; Linux: hidapi-hidraw/-libusb
|
||||
SR_ARG_OPT_PKG([libhidapi], [LIBHIDAPI], ,
|
||||
[hidapi >= 0.8.0], [hidapi-hidraw >= 0.8.0], [hidapi-libusb >= 0.8.0])
|
||||
|
||||
SR_ARG_OPT_PKG([libbluez], [LIBBLUEZ], , [bluez >= 4.0])
|
||||
|
||||
# FreeBSD comes with an "integrated" libusb-1.0-style USB API.
|
||||
# This means libusb-1.0 is always available; no need to check for it.
|
||||
# On Windows, require the latest version we can get our hands on,
|
||||
|
@ -130,6 +136,25 @@ SR_ARG_OPT_CHECK([libieee1284], [LIBIEEE1284],, [
|
|||
AS_IF([test "x$sr_have_libieee1284" = xyes],
|
||||
[SR_PREPEND([SR_EXTRA_LIBS], [-lieee1284])])
|
||||
|
||||
SR_ARG_OPT_PKG([libgio], [LIBGIO], , [gio-2.0 >= 2.24.0])
|
||||
|
||||
# See if any of the (potentially platform specific) libs are available
|
||||
# which provide some means of Bluetooth communication.
|
||||
AS_IF([test "x$sr_have_libbluez" = xyes],
|
||||
sr_have_bluetooth=yes, sr_have_bluetooth=no)
|
||||
AS_IF([test "x$sr_have_bluetooth" = xyes],
|
||||
[AC_DEFINE([HAVE_BLUETOOTH], [1], [Specifies whether Bluetooth communication is supported.])])
|
||||
AS_IF([test "x$sr_have_bluetooth" = xyes],
|
||||
[SR_APPEND([sr_deps_avail], [bluetooth_comm])])
|
||||
|
||||
AS_IF([test "x$sr_have_libserialport" = xyes -o "x$sr_have_libhidapi" = xyes -o "x$sr_have_bluetooth" = xyes],
|
||||
sr_have_serial_comm=yes, sr_have_serial_comm=no)
|
||||
AS_IF([test "x$sr_have_serial_comm" = xyes],
|
||||
[AC_DEFINE([HAVE_SERIAL_COMM], [1], [Specifies whether serial communication is supported.])])
|
||||
AS_IF([test "x$sr_have_serial_comm" = xyes],
|
||||
[SR_APPEND([sr_deps_avail], [serial_comm])])
|
||||
AM_CONDITIONAL([NEED_SERIAL], [test "x$sr_have_serial_comm" = xyes])
|
||||
|
||||
######################
|
||||
## Feature checks ##
|
||||
######################
|
||||
|
@ -174,6 +199,15 @@ AM_CONDITIONAL([NEED_RPC], [test "x$sr_cv_have_rpc" = xyes])
|
|||
# Check for compiler support of 128 bit integers
|
||||
AC_CHECK_TYPES([__int128_t, __uint128_t], [], [], [])
|
||||
|
||||
# Availability of bt_put_le16() depends on the bluez library version.
|
||||
AC_CACHE_CHECK([for bt_put_le16], [sr_cv_have_btputle16],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[#include <bluetooth/bluetooth.h>]],
|
||||
[[bt_put_le16(0, (void *)0);]])],
|
||||
[sr_cv_have_btputle16=yes], [sr_cv_have_btputle16=no])])
|
||||
AS_IF([test "x$sr_cv_have_btputle16" = xyes],
|
||||
[AC_DEFINE([HAVE_BT_PUT_LE16], [1], [Specifies whether we have bt_put_le16().])])
|
||||
|
||||
########################
|
||||
## Hardware drivers ##
|
||||
########################
|
||||
|
@ -218,30 +252,29 @@ m4_define([_SR_DRIVER], [
|
|||
m4_define([SR_DRIVER],
|
||||
[_SR_DRIVER([$1], [$2], m4_expand([AS_TR_CPP([HW_$2])]), [$3])])
|
||||
|
||||
SR_DRIVER([Agilent DMM], [agilent-dmm], [libserialport])
|
||||
SR_DRIVER([Appa 55II], [appa-55ii], [libserialport])
|
||||
SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [libserialport])
|
||||
SR_DRIVER([Agilent DMM], [agilent-dmm], [serial_comm])
|
||||
SR_DRIVER([Appa 55II], [appa-55ii], [serial_comm])
|
||||
SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [serial_comm])
|
||||
SR_DRIVER([ASIX SIGMA/SIGMA2], [asix-sigma], [libftdi])
|
||||
SR_DRIVER([Atten PPS3xxx], [atten-pps3xxx], [libserialport])
|
||||
SR_DRIVER([Atten PPS3xxx], [atten-pps3xxx], [serial_comm])
|
||||
SR_DRIVER([BayLibre ACME], [baylibre-acme], [sys_timerfd_h])
|
||||
SR_DRIVER([BeagleLogic], [beaglelogic], [sys_mman_h sys_ioctl_h])
|
||||
SR_DRIVER([Brymen BM86x], [brymen-bm86x], [libusb])
|
||||
SR_DRIVER([Brymen DMM], [brymen-dmm], [libserialport])
|
||||
SR_DRIVER([CEM DT-885x], [cem-dt-885x], [libserialport])
|
||||
SR_DRIVER([Center 3xx], [center-3xx], [libserialport])
|
||||
SR_DRIVER([Brymen DMM], [brymen-dmm], [serial_comm])
|
||||
SR_DRIVER([CEM DT-885x], [cem-dt-885x], [serial_comm])
|
||||
SR_DRIVER([Center 3xx], [center-3xx], [serial_comm])
|
||||
SR_DRIVER([ChronoVu LA], [chronovu-la], [libusb libftdi])
|
||||
SR_DRIVER([Colead SLM], [colead-slm], [libserialport])
|
||||
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [libserialport])
|
||||
SR_DRIVER([Colead SLM], [colead-slm], [serial_comm])
|
||||
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [serial_comm])
|
||||
SR_DRIVER([demo], [demo])
|
||||
SR_DRIVER([DreamSourceLab DSLogic], [dreamsourcelab-dslogic], [libusb])
|
||||
SR_DRIVER([Fluke 45], [fluke-45])
|
||||
SR_DRIVER([Fluke DMM], [fluke-dmm], [libserialport])
|
||||
SR_DRIVER([Fluke DMM], [fluke-dmm], [serial_comm])
|
||||
SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi])
|
||||
SR_DRIVER([fx2lafw], [fx2lafw], [libusb])
|
||||
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport])
|
||||
SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [libserialport])
|
||||
SR_DRIVER([GW Instek GPD], [gwinstek-gpd], [libserialport])
|
||||
SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport])
|
||||
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [serial_comm])
|
||||
SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [serial_comm])
|
||||
SR_DRIVER([GW Instek GPD], [gwinstek-gpd], [serial_comm])
|
||||
SR_DRIVER([Hameg HMO], [hameg-hmo], [serial_comm])
|
||||
SR_DRIVER([Hantek 4032L], [hantek-4032l], [libusb])
|
||||
SR_DRIVER([Hantek 6xxx], [hantek-6xxx], [libusb])
|
||||
SR_DRIVER([Hantek DSO], [hantek-dso], [libusb])
|
||||
|
@ -252,38 +285,42 @@ SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])
|
|||
SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
|
||||
SR_DRIVER([IPDBG LA], [ipdbg-la])
|
||||
SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
|
||||
SR_DRIVER([KERN scale], [kern-scale], [libserialport])
|
||||
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [libserialport])
|
||||
SR_DRIVER([KERN scale], [kern-scale], [serial_comm])
|
||||
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [serial_comm])
|
||||
SR_DRIVER([Lascar EL-USB], [lascar-el-usb], [libusb])
|
||||
SR_DRIVER([LeCroy LogicStudio], [lecroy-logicstudio], [libusb])
|
||||
SR_DRIVER([LeCroy X-Stream], [lecroy-xstream])
|
||||
SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [libserialport])
|
||||
SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [serial_comm])
|
||||
SR_DRIVER([Mastech MS6514], [mastech-ms6514], [serial_comm])
|
||||
SR_DRIVER([maynuo-m97], [maynuo-m97])
|
||||
SR_DRIVER([MIC 985xx], [mic-985xx], [libserialport])
|
||||
SR_DRIVER([Motech LPS 30x], [motech-lps-30x], [libserialport])
|
||||
SR_DRIVER([Norma DMM], [norma-dmm], [libserialport])
|
||||
SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [libserialport])
|
||||
SR_DRIVER([PCE PCE-322A], [pce-322a], [libserialport])
|
||||
SR_DRIVER([MIC 985xx], [mic-985xx], [serial_comm])
|
||||
SR_DRIVER([Microchip PICkit2], [microchip-pickit2], [libusb])
|
||||
SR_DRIVER([Mooshimeter DMM], [mooshimeter-dmm], [bluetooth_comm libgio])
|
||||
SR_DRIVER([Motech LPS 30x], [motech-lps-30x], [serial_comm])
|
||||
SR_DRIVER([Norma DMM], [norma-dmm], [serial_comm])
|
||||
SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [serial_comm])
|
||||
SR_DRIVER([PCE PCE-322A], [pce-322a], [serial_comm])
|
||||
SR_DRIVER([Pipistrello-OLS], [pipistrello-ols], [libftdi])
|
||||
SR_DRIVER([RDTech DPSxxxx/DPHxxxx], [rdtech-dps], [libserialport])
|
||||
SR_DRIVER([RDTech DPSxxxx/DPHxxxx], [rdtech-dps], [serial_comm])
|
||||
SR_DRIVER([Rigol DS], [rigol-ds])
|
||||
SR_DRIVER([Rohde&Schwarz SME-0x], [rohde-schwarz-sme-0x], [libserialport])
|
||||
SR_DRIVER([Rohde&Schwarz SME-0x], [rohde-schwarz-sme-0x], [serial_comm])
|
||||
SR_DRIVER([Saleae Logic16], [saleae-logic16], [libusb])
|
||||
SR_DRIVER([Saleae Logic Pro], [saleae-logic-pro], [libusb])
|
||||
SR_DRIVER([SCPI DMM], [scpi-dmm])
|
||||
SR_DRIVER([SCPI PPS], [scpi-pps])
|
||||
SR_DRIVER([serial DMM], [serial-dmm], [libserialport])
|
||||
SR_DRIVER([serial LCR], [serial-lcr], [libserialport])
|
||||
SR_DRIVER([serial DMM], [serial-dmm], [serial_comm])
|
||||
SR_DRIVER([serial LCR], [serial-lcr], [serial_comm])
|
||||
SR_DRIVER([Siglent SDS], [siglent-sds])
|
||||
SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb])
|
||||
SR_DRIVER([Teleinfo], [teleinfo], [libserialport])
|
||||
SR_DRIVER([Sysclk SLA5032], [sysclk-sla5032], [libusb])
|
||||
SR_DRIVER([Teleinfo], [teleinfo], [serial_comm])
|
||||
SR_DRIVER([Testo], [testo], [libusb])
|
||||
SR_DRIVER([Tondaj SL-814], [tondaj-sl-814], [libserialport])
|
||||
SR_DRIVER([Tondaj SL-814], [tondaj-sl-814], [serial_comm])
|
||||
SR_DRIVER([UNI-T DMM], [uni-t-dmm], [libusb])
|
||||
SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [libusb])
|
||||
SR_DRIVER([Victor DMM], [victor-dmm], [libusb])
|
||||
SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [serial_comm])
|
||||
SR_DRIVER([Yokogawa DL/DLM], [yokogawa-dlm])
|
||||
SR_DRIVER([ZEROPLUS Logic Cube], [zeroplus-logic-cube], [libusb])
|
||||
SR_DRIVER([ZKETECH EBD-USB], [zketech-ebd-usb], [libserialport])
|
||||
SR_DRIVER([ZKETECH EBD-USB], [zketech-ebd-usb], [serial_comm])
|
||||
|
||||
###############################
|
||||
## Language bindings setup ##
|
||||
|
@ -598,10 +635,17 @@ Detected libraries (optional):
|
|||
$sr_pkglibs_summary
|
||||
Enabled hardware drivers:
|
||||
$sr_driver_summary
|
||||
Enabled serial communication transports:
|
||||
- serial comm ................... $sr_have_serial_comm
|
||||
- libserialport ................. $sr_have_libserialport
|
||||
- hidapi ........................ $sr_have_libhidapi
|
||||
- bluetooth ..................... $sr_have_bluetooth
|
||||
- bluez ......................... $sr_have_libbluez
|
||||
|
||||
Enabled SCPI backends:
|
||||
- TCP............................. yes
|
||||
- RPC............................. $sr_cv_have_rpc
|
||||
- serial.......................... $sr_have_libserialport
|
||||
- serial.......................... $sr_have_serial_comm
|
||||
- VISA............................ $sr_have_librevisa
|
||||
- GPIB............................ $sr_have_libgpib
|
||||
- USBTMC.......................... $sr_have_libusb
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#
|
||||
|
||||
ACTION!="add|change", GOTO="libsigrok_rules_end"
|
||||
SUBSYSTEM!="usb|usbmisc|usb_device", GOTO="libsigrok_rules_end"
|
||||
SUBSYSTEM!="usb|usbmisc|usb_device|hidraw", GOTO="libsigrok_rules_end"
|
||||
|
||||
# Agilent USBTMC-connected devices
|
||||
# 34405A
|
||||
|
@ -55,9 +55,6 @@ ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0498", ENV{ID_SIGROK}="1"
|
|||
# Brymen BU-86X adapter (e.g. for Brymen BM867/BM869 and possibly others).
|
||||
ATTRS{idVendor}=="0820", ATTRS{idProduct}=="0001", ENV{ID_SIGROK}="1"
|
||||
|
||||
# CEM DT-8852
|
||||
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ENV{ID_SIGROK}="1"
|
||||
|
||||
# ChronoVu LA8 (new VID/PID)
|
||||
# ChronoVu LA16 (new VID/PID)
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8867", ENV{ID_SIGROK}="1"
|
||||
|
@ -158,6 +155,7 @@ ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="4032", ENV{ID_SIGROK}="1"
|
|||
ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4123", ENV{ID_SIGROK}="1"
|
||||
|
||||
# IKALOGIC ScanaPLUS
|
||||
# ftdi-la
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Kecheng KC-330B
|
||||
|
@ -172,6 +170,10 @@ ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="0002", ENV{ID_SIGROK}="1"
|
|||
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a001", ENV{ID_SIGROK}="1"
|
||||
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a002", ENV{ID_SIGROK}="1"
|
||||
|
||||
# LeCroy WaveRunner
|
||||
# 05ff:1023: 625Zi
|
||||
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="1023", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Link Instruments MSO-19
|
||||
ATTRS{idVendor}=="3195", ATTRS{idProduct}=="f190", ENV{ID_SIGROK}="1"
|
||||
|
||||
|
@ -208,7 +210,11 @@ ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0641", ENV{ID_SIGROK}="1"
|
|||
# Rigol DP800 series
|
||||
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0e11", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Rohde&Schwarz HMO1002 Series VCP/USBTMC mode
|
||||
# Rigol MSO5000 series
|
||||
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0515", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Rohde&Schwarz HMO series mixed-signal oscilloscope (previously branded Hameg) VCP/USBTMC mode
|
||||
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0117", ENV{ID_SIGROK}="1"
|
||||
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0118", ENV{ID_SIGROK}="1"
|
||||
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0119", ENV{ID_SIGROK}="1"
|
||||
|
||||
|
@ -232,6 +238,7 @@ ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1006", ENV{ID_SIGROK}="1"
|
|||
|
||||
# Siglent USBTMC devices.
|
||||
# f4ec:ee3a: E.g. SDS1052DL+ scope
|
||||
# f4ec:ee38: E.g. SDS1104X-E scope
|
||||
# f4ed:ee3a: E.g. SDS1202X-E scope or SDG1010 waveform generator
|
||||
ATTRS{idVendor}=="f4ec", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"
|
||||
ATTRS{idVendor}=="f4ed", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"
|
||||
|
@ -249,28 +256,47 @@ ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", ENV{ID_SIGROK}="1"
|
|||
# sigrok usb-c-grok
|
||||
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608f", ENV{ID_SIGROK}="1"
|
||||
|
||||
# SysClk LWLA1016
|
||||
# SiLabs CP210x (USB CDC) UART bridge, used (among others) in:
|
||||
# CEM DT-8852
|
||||
# Manson HCS-3202
|
||||
# MASTECH MS2115B
|
||||
# MASTECH MS5308
|
||||
# MASTECH MS8250D
|
||||
# PeakTech 3330
|
||||
# Voltcraft PPS-11815
|
||||
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ENV{ID_SIGROK}="1"
|
||||
|
||||
# SiLabs CP2110 (USB HID) UART bridge, used (among others) in:
|
||||
# UNI-T UT612
|
||||
# UNI-T UT-D09 multimeter cable (for various UNI-T and rebranded DMMs)
|
||||
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea80", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Sysclk LWLA1016
|
||||
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6688", ENV{ID_SIGROK}="1"
|
||||
|
||||
# SysClk LWLA1034
|
||||
# Sysclk LWLA1034
|
||||
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6689", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Sysclk SLA5032 ("32CH 500M" mode)
|
||||
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="66b0", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Testo 435
|
||||
ATTRS{idVendor}=="128d", ATTRS{idProduct}=="0003", ENV{ID_SIGROK}="1"
|
||||
|
||||
# UNI-T UT-D04 multimeter cable (for various UNI-T and rebranded DMMs)
|
||||
# http://sigrok.org/wiki/Device_cables#UNI-T_UT-D04
|
||||
# UNI-T UT325
|
||||
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="e008", ENV{ID_SIGROK}="1"
|
||||
|
||||
# V&A VA4000 multimeter cable (for various V&A DMMs)
|
||||
# http://sigrok.org/wiki/Device_cables#V.26A_VA4000
|
||||
ATTRS{idVendor}=="04fc", ATTRS{idProduct}=="0201", ENV{ID_SIGROK}="1"
|
||||
|
||||
# Victor 70C
|
||||
# Victor 86C
|
||||
ATTRS{idVendor}=="1244", ATTRS{idProduct}=="d237", ENV{ID_SIGROK}="1"
|
||||
|
||||
# YiXingDianZi MDSO
|
||||
ATTRS{idVendor}=="d4a2", ATTRS{idProduct}=="5660", ENV{ID_SIGROK}="1"
|
||||
|
||||
# ZEROPLUS Logic Cube LAP-C series
|
||||
# There are various devices in the ZEROPLUS Logic Cube series:
|
||||
# 0c12:7002: LAP-16128U
|
||||
|
|
|
@ -956,6 +956,8 @@ enum sr_configkey {
|
|||
* Channel regulation
|
||||
* get: "CV", "CC" or "UR", denoting constant voltage, constant current
|
||||
* or unregulated.
|
||||
* "CC-" denotes a power supply in current sink mode (e.g. HP 66xxB).
|
||||
* "" is used when there is no regulation, e.g. the output is disabled.
|
||||
*/
|
||||
SR_CONF_REGULATION,
|
||||
|
||||
|
@ -995,6 +997,30 @@ enum sr_configkey {
|
|||
*/
|
||||
SR_CONF_EXTERNAL_CLOCK_SOURCE,
|
||||
|
||||
/** Offset of a source without strictly-defined MQ. */
|
||||
SR_CONF_OFFSET,
|
||||
|
||||
/** The device supports setting a pattern for the logic trigger. */
|
||||
SR_CONF_TRIGGER_PATTERN,
|
||||
|
||||
/** High resolution mode. */
|
||||
SR_CONF_HIGH_RESOLUTION,
|
||||
|
||||
/** Peak detection. */
|
||||
SR_CONF_PEAK_DETECTION,
|
||||
|
||||
/** Logic threshold: predefined levels (TTL, ECL, CMOS, etc). */
|
||||
SR_CONF_LOGIC_THRESHOLD,
|
||||
|
||||
/** Logic threshold: custom numerical value. */
|
||||
SR_CONF_LOGIC_THRESHOLD_CUSTOM,
|
||||
|
||||
/** The measurement range of a DMM or the output range of a power supply. */
|
||||
SR_CONF_RANGE,
|
||||
|
||||
/** The number of digits (e.g. for a DMM). */
|
||||
SR_CONF_DIGITS,
|
||||
|
||||
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
|
||||
|
||||
/*--- Special stuff -------------------------------------------------*/
|
||||
|
|
|
@ -4,7 +4,7 @@ libdir=@libdir@
|
|||
includedir=@includedir@
|
||||
|
||||
Name: libsigrok
|
||||
Description: Backend library of the sigrok logic analyzer software
|
||||
Description: Backend library for the sigrok signal analysis software suite
|
||||
URL: http://www.sigrok.org
|
||||
Requires: glib-2.0
|
||||
Requires.private: @SR_PKGLIBS@
|
||||
|
|
|
@ -164,6 +164,16 @@ SR_API GSList *sr_buildinfo_libs_get(void)
|
|||
#endif
|
||||
l = g_slist_append(l, m);
|
||||
#endif
|
||||
#ifdef HAVE_LIBHIDAPI
|
||||
m = g_slist_append(NULL, g_strdup("hidapi"));
|
||||
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBHIDAPI_VERSION));
|
||||
l = g_slist_append(l, m);
|
||||
#endif
|
||||
#ifdef HAVE_LIBBLUEZ
|
||||
m = g_slist_append(NULL, g_strdup("bluez"));
|
||||
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBBLUEZ_VERSION));
|
||||
l = g_slist_append(l, m);
|
||||
#endif
|
||||
#ifdef HAVE_LIBFTDI
|
||||
m = g_slist_append(NULL, g_strdup("libftdi"));
|
||||
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBFTDI_VERSION));
|
||||
|
@ -205,7 +215,7 @@ SR_API char *sr_buildinfo_scpi_backends_get(void)
|
|||
#if HAVE_RPC
|
||||
g_string_append_printf(s, "RPC, ");
|
||||
#endif
|
||||
#ifdef HAVE_LIBSERIALPORT
|
||||
#ifdef HAVE_SERIAL_COMM
|
||||
g_string_append_printf(s, "serial, ");
|
||||
#endif
|
||||
#ifdef HAVE_LIBREVISA
|
||||
|
@ -232,8 +242,7 @@ static void print_versions(void)
|
|||
char *str;
|
||||
const char *lib, *version;
|
||||
|
||||
sr_dbg("libsigrok %s/%s (rt: %s/%s).",
|
||||
SR_PACKAGE_VERSION_STRING, SR_LIB_VERSION_STRING,
|
||||
sr_dbg("libsigrok %s/%s.",
|
||||
sr_package_version_string_get(), sr_lib_version_string_get());
|
||||
|
||||
s = g_string_sized_new(200);
|
||||
|
@ -592,6 +601,20 @@ SR_API int sr_init(struct sr_context **ctx)
|
|||
ret = SR_ERR;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBHIDAPI
|
||||
/*
|
||||
* According to <hidapi.h>, the hid_init() routine just returns
|
||||
* zero or non-zero, and hid_error() appears to relate to calls
|
||||
* for a specific device after hid_open(). Which means that there
|
||||
* is no more detailled information available beyond success/fail
|
||||
* at this point in time.
|
||||
*/
|
||||
if (hid_init() != 0) {
|
||||
sr_err("HIDAPI hid_init() failed.");
|
||||
ret = SR_ERR;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
sr_resource_set_hooks(context, NULL, NULL, NULL, NULL);
|
||||
|
||||
|
@ -627,6 +650,9 @@ SR_API int sr_exit(struct sr_context *ctx)
|
|||
WSACleanup();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBHIDAPI
|
||||
hid_exit();
|
||||
#endif
|
||||
#ifdef HAVE_LIBUSB_1_0
|
||||
libusb_exit(ctx->libusb_ctx);
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
43
src/device.c
43
src/device.c
|
@ -23,6 +23,7 @@
|
|||
#include <string.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
#include "scpi.h"
|
||||
|
||||
/** @cond PRIVATE */
|
||||
#define LOG_PREFIX "device"
|
||||
|
@ -61,7 +62,7 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
|
|||
{
|
||||
struct sr_channel *ch;
|
||||
|
||||
ch = g_malloc0(sizeof(struct sr_channel));
|
||||
ch = g_malloc0(sizeof(*ch));
|
||||
ch->sdi = sdi;
|
||||
ch->index = index;
|
||||
ch->type = type;
|
||||
|
@ -404,7 +405,7 @@ SR_API struct sr_dev_inst *sr_dev_inst_user_new(const char *vendor,
|
|||
{
|
||||
struct sr_dev_inst *sdi;
|
||||
|
||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||
sdi = g_malloc0(sizeof(*sdi));
|
||||
|
||||
sdi->vendor = g_strdup(vendor);
|
||||
sdi->model = g_strdup(model);
|
||||
|
@ -494,7 +495,7 @@ SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
|
|||
{
|
||||
struct sr_usb_dev_inst *udi;
|
||||
|
||||
udi = g_malloc0(sizeof(struct sr_usb_dev_inst));
|
||||
udi = g_malloc0(sizeof(*udi));
|
||||
udi->bus = bus;
|
||||
udi->address = address;
|
||||
udi->devhdl = hdl;
|
||||
|
@ -517,7 +518,7 @@ SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb)
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBSERIALPORT
|
||||
#ifdef HAVE_SERIAL_COMM
|
||||
|
||||
/**
|
||||
* Allocate and init a struct for a serial device instance.
|
||||
|
@ -543,7 +544,7 @@ SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
|
|||
{
|
||||
struct sr_serial_dev_inst *serial;
|
||||
|
||||
serial = g_malloc0(sizeof(struct sr_serial_dev_inst));
|
||||
serial = g_malloc0(sizeof(*serial));
|
||||
serial->port = g_strdup(port);
|
||||
if (serialcomm)
|
||||
serial->serialcomm = g_strdup(serialcomm);
|
||||
|
@ -575,7 +576,7 @@ SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device)
|
|||
{
|
||||
struct sr_usbtmc_dev_inst *usbtmc;
|
||||
|
||||
usbtmc = g_malloc0(sizeof(struct sr_usbtmc_dev_inst));
|
||||
usbtmc = g_malloc0(sizeof(*usbtmc));
|
||||
usbtmc->device = g_strdup(device);
|
||||
usbtmc->fd = -1;
|
||||
|
||||
|
@ -808,19 +809,24 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
|
|||
#ifdef HAVE_LIBUSB_1_0
|
||||
struct drv_context *drvc;
|
||||
int cnt, i, a, b;
|
||||
char connection_id[64];
|
||||
char conn_id_usb[64];
|
||||
struct sr_usb_dev_inst *usb;
|
||||
struct libusb_device **devlist;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SERIAL_COMM
|
||||
struct sr_serial_dev_inst *serial;
|
||||
#endif
|
||||
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
char *conn_id_scpi;
|
||||
|
||||
if (!sdi)
|
||||
return NULL;
|
||||
|
||||
#ifdef HAVE_LIBSERIALPORT
|
||||
struct sr_serial_dev_inst *serial;
|
||||
|
||||
#ifdef HAVE_SERIAL_COMM
|
||||
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SERIAL)) {
|
||||
/* connection_id isn't populated, let's do that here. */
|
||||
/* connection_id isn't populated, let's do that for serial devices. */
|
||||
|
||||
serial = sdi->conn;
|
||||
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(serial->port);
|
||||
|
@ -829,7 +835,7 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
|
|||
|
||||
#ifdef HAVE_LIBUSB_1_0
|
||||
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_USB)) {
|
||||
/* connection_id isn't populated, let's do that here. */
|
||||
/* connection_id isn't populated, let's do that for USB devices. */
|
||||
|
||||
drvc = sdi->driver->context;
|
||||
usb = sdi->conn;
|
||||
|
@ -847,10 +853,10 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
|
|||
if (b != usb->bus || a != usb->address)
|
||||
continue;
|
||||
|
||||
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
|
||||
if (usb_get_port_path(devlist[i], conn_id_usb, sizeof(conn_id_usb)) < 0)
|
||||
continue;
|
||||
|
||||
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
|
||||
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(conn_id_usb);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -858,6 +864,15 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
|
|||
}
|
||||
#endif
|
||||
|
||||
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SCPI)) {
|
||||
/* connection_id isn't populated, let's do that for SCPI devices. */
|
||||
|
||||
scpi = sdi->conn;
|
||||
sr_scpi_connection_id(scpi, &conn_id_scpi);
|
||||
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(conn_id_scpi);
|
||||
g_free(conn_id_scpi);
|
||||
}
|
||||
|
||||
return sdi->connection_id;
|
||||
}
|
||||
|
||||
|
|
|
@ -446,7 +446,7 @@ static gboolean flags_valid(const struct asycii_info *info)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSERIALPORT
|
||||
#ifdef HAVE_SERIAL_COMM
|
||||
/**
|
||||
* Arrange for the reception of another measurement from the DMM.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
|
||||
* Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Brymen BM86x serial protocol parser. The USB protocol (for the cable)
|
||||
* and the packet description (for the meter) were retrieved from:
|
||||
* http://brymen.com/product-html/Download2.html
|
||||
* http://brymen.com/product-html/PD02BM860s_protocolDL.html
|
||||
* http://brymen.com/product-html/images/DownloadList/ProtocolList/BM860-BM860s_List/BM860-BM860s-500000-count-dual-display-DMMs-protocol.pdf
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <math.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
#include <string.h>
|
||||
|
||||
#define LOG_PREFIX "brymen-bm86x"
|
||||
|
||||
#ifdef HAVE_SERIAL_COMM
|
||||
SR_PRIV int sr_brymen_bm86x_packet_request(struct sr_serial_dev_inst *serial)
|
||||
{
|
||||
static const uint8_t request[] = { 0x00, 0x00, 0x86, 0x66, };
|
||||
|
||||
serial_write_nonblocking(serial, request, sizeof(request));
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
SR_PRIV gboolean sr_brymen_bm86x_packet_valid(const uint8_t *buf)
|
||||
{
|
||||
/*
|
||||
* "Model ID3" (3rd HID report, byte 3) is the only documented
|
||||
* fixed value, and must be 0x86. All other positions either depend
|
||||
* on the meter's function, or the measurement's value, or are not
|
||||
* documented by the vendor (are marked as "don't care", no fixed
|
||||
* values are listed). There is nothing else we can check reliably.
|
||||
*/
|
||||
if (buf[19] != 0x86)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data bytes in the DMM packet encode LCD segments in an unusual order
|
||||
* (bgcdafe) and in an unusual position (bits 7:1 within the byte). The
|
||||
* decimal point (bit 0) for one digit resides in the _next_ digit's byte.
|
||||
*
|
||||
* These routines convert LCD segments to characters, and a section of the
|
||||
* DMM packet (which corresponds to the primary or secondary display) to
|
||||
* the text representation of the measurement's value, before regular text
|
||||
* to number conversion is applied. The first byte of the passed in block
|
||||
* contains indicators, the value's digits start at the second byte.
|
||||
*/
|
||||
|
||||
static char brymen_bm86x_parse_digit(uint8_t b)
|
||||
{
|
||||
switch (b >> 1) {
|
||||
/* Sign. */
|
||||
case 0x20: return '-';
|
||||
/* Decimal digits. */
|
||||
case 0x5f: return '0';
|
||||
case 0x50: return '1';
|
||||
case 0x6d: return '2';
|
||||
case 0x7c: return '3';
|
||||
case 0x72: return '4';
|
||||
case 0x3e: return '5';
|
||||
case 0x3f: return '6';
|
||||
case 0x54: return '7';
|
||||
case 0x7f: return '8';
|
||||
case 0x7e: return '9';
|
||||
/* Temperature units. */
|
||||
case 0x0f: return 'C';
|
||||
case 0x27: return 'F';
|
||||
/* OL condition, and diode mode. */
|
||||
case 0x0b: return 'L';
|
||||
case 0x79: return 'd';
|
||||
case 0x10: return 'i';
|
||||
case 0x39: return 'o';
|
||||
/* Blank digit. */
|
||||
case 0x00: return '\0';
|
||||
/* Invalid or unknown segment combination. */
|
||||
default:
|
||||
sr_warn("Unknown encoding for digit: 0x%02x.", b);
|
||||
return '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int brymen_bm86x_parse_digits(const uint8_t *pkt, size_t pktlen,
|
||||
char *txtbuf, float *value, char *temp_unit, int *digits, int signflag)
|
||||
{
|
||||
uint8_t byte;
|
||||
char *txtptr, txtchar;
|
||||
size_t pos;
|
||||
int ret;
|
||||
|
||||
txtptr = txtbuf;
|
||||
if (digits)
|
||||
*digits = INT_MIN;
|
||||
|
||||
if (pkt[0] & signflag)
|
||||
*txtptr++ = '-';
|
||||
for (pos = 0; pos < pktlen; pos++) {
|
||||
byte = pkt[1 + pos];
|
||||
if (pos && pos < 5 && (byte & 0x01)) {
|
||||
*txtptr++ = '.';
|
||||
if (digits)
|
||||
*digits = 0;
|
||||
}
|
||||
txtchar = brymen_bm86x_parse_digit(byte);
|
||||
if (pos == 5 && (txtchar == 'C' || txtchar == 'F')) {
|
||||
if (temp_unit)
|
||||
*temp_unit = txtchar;
|
||||
} else if (txtchar) {
|
||||
*txtptr++ = txtchar;
|
||||
if (digits)
|
||||
(*digits)++;
|
||||
}
|
||||
}
|
||||
*txtptr = '\0';
|
||||
|
||||
if (digits && *digits < 0)
|
||||
*digits = 0;
|
||||
|
||||
ret = value ? sr_atof_ascii(txtbuf, value) : SR_OK;
|
||||
if (ret != SR_OK) {
|
||||
sr_dbg("invalid float string: '%s'", txtbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the measurement value and its properties for one of the
|
||||
* meter's displays from the DMM packet.
|
||||
*/
|
||||
static void brymen_bm86x_parse(const uint8_t *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog, size_t ch_idx)
|
||||
{
|
||||
char txtbuf[16], temp_unit;
|
||||
int ret, digits, is_diode, over_limit, scale;
|
||||
uint8_t ind1, ind15;
|
||||
|
||||
temp_unit = '\0';
|
||||
if (ch_idx == 0) {
|
||||
/*
|
||||
* Main display. Note that _some_ of the second display's
|
||||
* indicators are involved in the inspection of the _first_
|
||||
* display's measurement value. So we have to get the
|
||||
* second display's text buffer here, too.
|
||||
*/
|
||||
(void)brymen_bm86x_parse_digits(&buf[9], 4, txtbuf,
|
||||
NULL, NULL, NULL, 0);
|
||||
is_diode = strcmp(txtbuf, "diod") == 0;
|
||||
ret = brymen_bm86x_parse_digits(&buf[2], 6, txtbuf,
|
||||
floatval, &temp_unit, &digits, 0x80);
|
||||
over_limit = strstr(txtbuf, "0L") || strstr(txtbuf, "0.L");
|
||||
if (ret != SR_OK && !over_limit)
|
||||
return;
|
||||
|
||||
/* SI unit. */
|
||||
if (buf[8] & 0x01) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
if (is_diode) {
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
}
|
||||
} else if (buf[14] & 0x80) {
|
||||
analog->meaning->mq = SR_MQ_CURRENT;
|
||||
analog->meaning->unit = SR_UNIT_AMPERE;
|
||||
} else if (buf[14] & 0x20) {
|
||||
analog->meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog->meaning->unit = SR_UNIT_FARAD;
|
||||
} else if (buf[14] & 0x10) {
|
||||
analog->meaning->mq = SR_MQ_CONDUCTANCE;
|
||||
analog->meaning->unit = SR_UNIT_SIEMENS;
|
||||
} else if (buf[15] & 0x01) {
|
||||
analog->meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog->meaning->unit = SR_UNIT_HERTZ;
|
||||
} else if (buf[10] & 0x01) {
|
||||
analog->meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog->meaning->unit = SR_UNIT_OHM;
|
||||
} else if (buf[15] & 0x10) {
|
||||
analog->meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog->meaning->unit = SR_UNIT_OHM;
|
||||
} else if (buf[15] & 0x02) {
|
||||
analog->meaning->mq = SR_MQ_POWER;
|
||||
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||
} else if (buf[15] & 0x80) {
|
||||
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
analog->meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
} else if ((buf[2] & 0x0a) && temp_unit) {
|
||||
analog->meaning->mq = SR_MQ_TEMPERATURE;
|
||||
if (temp_unit == 'F')
|
||||
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
else
|
||||
analog->meaning->unit = SR_UNIT_CELSIUS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the MIN/MAX/AVG indicators when all of them
|
||||
* are shown at the same time.
|
||||
*/
|
||||
ind1 = buf[1];
|
||||
if ((ind1 & 0xe0) == 0xe0)
|
||||
ind1 &= ~0xe0;
|
||||
|
||||
/* AC/DC/Auto flags. */
|
||||
if (buf[1] & 0x10)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
if (buf[2] & 0x01)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
||||
if (buf[1] & 0x01)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||
if (buf[1] & 0x08)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||
if (ind1 & 0x20)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_MAX;
|
||||
if (ind1 & 0x40)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_MIN;
|
||||
if (ind1 & 0x80)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AVG;
|
||||
if (buf[3] & 0x01)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
|
||||
|
||||
/*
|
||||
* Remove the "dBm" indication's "m" indicator before the
|
||||
* SI unit's prefixes get inspected. To avoid an interaction
|
||||
* with the "milli" prefix.
|
||||
*/
|
||||
ind15 = buf[15];
|
||||
if (ind15 & 0x02)
|
||||
ind15 &= ~0x04;
|
||||
|
||||
/* SI prefix. */
|
||||
scale = 0;
|
||||
if (buf[14] & 0x40) /* n */
|
||||
scale = -9;
|
||||
if (buf[15] & 0x08) /* u */
|
||||
scale = -6;
|
||||
if (ind15 & 0x04) /* m */
|
||||
scale = -3;
|
||||
if (buf[15] & 0x40) /* k */
|
||||
scale = +3;
|
||||
if (buf[15] & 0x20) /* M */
|
||||
scale = +6;
|
||||
if (scale) {
|
||||
*floatval *= pow(10, scale);
|
||||
digits += -scale;
|
||||
}
|
||||
|
||||
if (over_limit)
|
||||
*floatval = INFINITY;
|
||||
|
||||
analog->encoding->digits = digits;
|
||||
analog->spec->spec_digits = digits;
|
||||
} else if (ch_idx == 1) {
|
||||
/*
|
||||
* Secondary display. Also inspect _some_ primary display
|
||||
* data, to determine the secondary display's validity.
|
||||
*/
|
||||
(void)brymen_bm86x_parse_digits(&buf[2], 6, txtbuf,
|
||||
NULL, &temp_unit, NULL, 0x80);
|
||||
ret = brymen_bm86x_parse_digits(&buf[9], 4, txtbuf,
|
||||
floatval, NULL, &digits, 0x10);
|
||||
|
||||
/* SI unit. */
|
||||
if (buf[14] & 0x08) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
} else if (buf[9] & 0x04) {
|
||||
analog->meaning->mq = SR_MQ_CURRENT;
|
||||
analog->meaning->unit = SR_UNIT_AMPERE;
|
||||
} else if (buf[9] & 0x08) {
|
||||
analog->meaning->mq = SR_MQ_CURRENT;
|
||||
analog->meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
} else if (buf[14] & 0x04) {
|
||||
analog->meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog->meaning->unit = SR_UNIT_HERTZ;
|
||||
} else if ((buf[9] & 0x40) && temp_unit) {
|
||||
analog->meaning->mq = SR_MQ_TEMPERATURE;
|
||||
if (temp_unit == 'F')
|
||||
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
else
|
||||
analog->meaning->unit = SR_UNIT_CELSIUS;
|
||||
}
|
||||
|
||||
/* AC flag. */
|
||||
if (buf[9] & 0x20)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
||||
|
||||
/* SI prefix. */
|
||||
scale = 0;
|
||||
if (buf[ 9] & 0x01) /* u */
|
||||
scale = -6;
|
||||
if (buf[ 9] & 0x02) /* m */
|
||||
scale = -3;
|
||||
if (buf[14] & 0x02) /* k */
|
||||
scale = +3;
|
||||
if (buf[14] & 0x01) /* M */
|
||||
scale = +6;
|
||||
if (scale) {
|
||||
*floatval *= pow(10, scale);
|
||||
digits += -scale;
|
||||
}
|
||||
|
||||
analog->encoding->digits = digits;
|
||||
analog->spec->spec_digits = digits;
|
||||
}
|
||||
|
||||
if (buf[9] & 0x80)
|
||||
sr_warn("Battery is low.");
|
||||
}
|
||||
|
||||
SR_PRIV int sr_brymen_bm86x_parse(const uint8_t *buf, float *val,
|
||||
struct sr_datafeed_analog *analog, void *info)
|
||||
{
|
||||
struct brymen_bm86x_info *info_local;
|
||||
size_t ch_idx;
|
||||
|
||||
/*
|
||||
* Scan a portion of the received DMM packet which corresponds
|
||||
* to the caller's specified display. Then prepare to scan a
|
||||
* different portion of the packet for another display. This
|
||||
* routine gets called multiple times for one received packet.
|
||||
*/
|
||||
info_local = info;
|
||||
ch_idx = info_local->ch_idx;
|
||||
brymen_bm86x_parse(buf, val, analog, ch_idx);
|
||||
info_local->ch_idx = ch_idx + 1;
|
||||
|
||||
return SR_OK;
|
||||
}
|
|
@ -523,55 +523,63 @@ static const struct mode_range_items *mode_ranges_main[] = {
|
|||
static const struct mode_range_items mode_ranges_temp_sub = {
|
||||
.range_count = 2,
|
||||
.ranges = {
|
||||
[1] = { .desc = "sub 100.0C", .digits = 1, .factor = 1, },
|
||||
[1] = { .desc = "100.0C", .digits = 1, .factor = 1, },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mode_range_items mode_ranges_freq_sub = {
|
||||
.range_count = 4,
|
||||
.ranges = {
|
||||
[1] = { .desc = "999.9Hz", .digits = 1, .factor = 1, },
|
||||
[2] = { .desc = "99.99Hz", .digits = 2, .factor = 2, },
|
||||
[3] = { .desc = "9.999kHz", .digits = 3, .factor = 3, },
|
||||
[1] = { .desc = "999.9Hz", .digits = 1, .factor = 1, },
|
||||
[2] = { .desc = "99.99Hz", .digits = 2, .factor = 2, },
|
||||
[3] = { .desc = "9.999kHz", .digits = 3, .factor = 3, },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mode_range_items mode_ranges_batt_sub = {
|
||||
.range_count = 2,
|
||||
.ranges = {
|
||||
[1] = { .desc = "sub 10.0V", .digits = 1, .factor = 1, },
|
||||
[1] = { .desc = "10.0V", .digits = 1, .factor = 1, },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mode_range_items mode_ranges_gain_sub = {
|
||||
.range_count = 4,
|
||||
.ranges = {
|
||||
[1] = { .desc = "dbm 5000.0dBm", .digits = 1, .factor = 1, },
|
||||
[2] = { .desc = "dbm 500.00dBm", .digits = 2, .factor = 2, },
|
||||
[3] = { .desc = "dbm 50.000dBm", .digits = 3, .factor = 3, },
|
||||
[1] = { .desc = "5000.0dBm", .digits = 1, .factor = 1, },
|
||||
[2] = { .desc = "500.00dBm", .digits = 2, .factor = 2, },
|
||||
[3] = { .desc = "50.000dBm", .digits = 3, .factor = 3, },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mode_range_items mode_ranges_diode_sub = {
|
||||
.range_count = 1,
|
||||
.ranges = {
|
||||
[0] = { .desc = "diode 15.0V", .digits = 0, .factor = 0, },
|
||||
[0] = { .desc = "15.0V", .digits = 0, .factor = 0, },
|
||||
},
|
||||
};
|
||||
|
||||
/* TODO: Complete the list of ranges. Only tested with low voltages so far. */
|
||||
static const struct mode_range_items mode_ranges_volts_sub = {
|
||||
.range_count = 5,
|
||||
.ranges = {
|
||||
[3] = { .desc = "50.000V", .digits = 3, .factor = 3, },
|
||||
[4] = { .desc = "5.0000V", .digits = 4, .factor = 4, },
|
||||
},
|
||||
};
|
||||
|
||||
/* TODO: Complete the list of ranges. Only tested with low voltages so far. */
|
||||
static const struct mode_range_items mode_ranges_mamps_sub = {
|
||||
.range_count = 3,
|
||||
.range_count = 5,
|
||||
.ranges = {
|
||||
[2] = { .desc = "500.00mA", .digits = 5, .factor = 5, },
|
||||
[3] = { .desc = "50.000mA", .digits = 6, .factor = 6, },
|
||||
[4] = { .desc = "5.0000mA", .digits = 7, .factor = 7, },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mode_range_items mode_ranges_uamps_sub = {
|
||||
.range_count = 5,
|
||||
.ranges = {
|
||||
[4] = { .desc = "5.0000mA", .digits = 7, .factor = 7, },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -580,6 +588,10 @@ static const struct mode_range_items *mode_ranges_sub[] = {
|
|||
[MODE_AC_V] = &mode_ranges_volts_sub,
|
||||
[MODE_DC_A] = &mode_ranges_mamps_sub,
|
||||
[MODE_AC_A] = &mode_ranges_mamps_sub,
|
||||
[MODE_DC_MA] = &mode_ranges_mamps_sub,
|
||||
[MODE_AC_MA] = &mode_ranges_mamps_sub,
|
||||
[MODE_DC_UA] = &mode_ranges_uamps_sub,
|
||||
[MODE_AC_UA] = &mode_ranges_uamps_sub,
|
||||
[MODE_FREQ] = &mode_ranges_freq_sub,
|
||||
[MODE_DIODE] = &mode_ranges_diode_sub,
|
||||
[MODE_SUB_TEMPC] = &mode_ranges_temp_sub,
|
||||
|
@ -679,7 +691,7 @@ SR_PRIV gboolean sr_eev121gw_packet_valid(const uint8_t *buf)
|
|||
* @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
|
||||
* 'analog' variable contents are undefined and should not be used.
|
||||
*/
|
||||
SR_PRIV int sr_eev121gw_parse(const uint8_t *buf, float *floatval,
|
||||
static int sr_eev121gw_parse(const uint8_t *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog, void *info)
|
||||
{
|
||||
struct eev121gw_info *info_local;
|
||||
|
@ -1015,7 +1027,7 @@ SR_PRIV int sr_eev121gw_parse(const uint8_t *buf, float *floatval,
|
|||
/*
|
||||
* Get those fields which correspond to the secondary
|
||||
* display. The value's mantissa has 16 bits. The sign
|
||||
* is separate is only applies to some of the modes.
|
||||
* is separate and only applies to some of the modes.
|
||||
* Scaling and precision also depend on the mode. The
|
||||
* interpretation of the secondary display is different
|
||||
* from the main display: The 'range' is not an index
|
||||
|
@ -1057,36 +1069,6 @@ SR_PRIV int sr_eev121gw_parse(const uint8_t *buf, float *floatval,
|
|||
}
|
||||
is_k = FIELD_NB(raw_sub_range, SUB_RANGE_K);
|
||||
|
||||
/*
|
||||
* TODO: Re-check the power mode display as more data becomes
|
||||
* available.
|
||||
*
|
||||
* The interpretation of the secondary display in power (VA)
|
||||
* modes is uncertain. The mode suggests A or uA units but the
|
||||
* value is supposed to be mA without a reliable condition
|
||||
* for us to check...
|
||||
*
|
||||
* f2 17 84 21 21 18 02 00 00 01 04 00 0b 00 00 0a 40 00 3f
|
||||
* f2 17 84 21 21 18 02 00 00 15 03 00 00 00 00 0a 40 00 27
|
||||
* DC VA DC V / DC A
|
||||
* 25.000VA dot 4 / dot 3
|
||||
*
|
||||
* f2 17 84 21 21 18 00 00 26 01 04 4c 57 00 00 0e 40 00 0f
|
||||
* f2 17 84 21 21 18 00 00 26 15 02 00 c7 00 00 0e 40 00 c1
|
||||
* 3.8mVA DC 1.9543V
|
||||
* 1.98mA (!) DC A + dot 2 -> milli(!) amps?
|
||||
*
|
||||
* f2 17 84 21 21 17 00 07 85 01 04 4c 5a 00 00 0e 40 00 a9
|
||||
* f2 17 84 21 21 17 00 07 85 13 04 26 7b 00 00 0e 40 00 f0
|
||||
* 1.925mVA DC 1.9546V
|
||||
* 0.9852mA
|
||||
*
|
||||
* f2 17 84 21 21 16 02 11 e0 01 04 26 39 00 02 0e 40 00 d2
|
||||
* f2 17 84 21 21 16 02 11 e0 11 04 12 44 00 02 0e 40 00 8b
|
||||
* 457.6uVA DC 0.9785V
|
||||
* 0.4676mA (!) DC uA + dot 4 -> milli(!) amps?
|
||||
*/
|
||||
|
||||
switch (sub_mode) {
|
||||
case MODE_DC_V:
|
||||
info_local->is_voltage = TRUE;
|
||||
|
|
|
@ -329,7 +329,7 @@ static gboolean flags_valid(const struct metex14_info *info)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSERIALPORT
|
||||
#ifdef HAVE_SERIAL_COMM
|
||||
SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial)
|
||||
{
|
||||
const uint8_t wbuf = 'D';
|
||||
|
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2019 Vitaliy Vorobyov
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MASTECH MS2115B protocol parser.
|
||||
*
|
||||
* Sends 9 bytes.
|
||||
* D0 D1 D2 D3 D4 D5 D6 D7 D8 D9
|
||||
*
|
||||
* D0 = 0x55 - sync byte
|
||||
*
|
||||
* D1 - mode:
|
||||
* bits:
|
||||
* B7..B4 ??
|
||||
* B3 - func
|
||||
* B2..B0:
|
||||
* 0 - A 600/1000 (func=0 AC, func=1 DC), signed
|
||||
* 1 - A 60 (func=0 AC, func=1 DC), signed
|
||||
* 2 - V (func=0 AC, func=1 DC), signed
|
||||
* 3 - diode/beep (func=0 buz, func=1 diode)
|
||||
* 4 - resistance
|
||||
* 5 - capacitance
|
||||
* 6 - hz
|
||||
*
|
||||
* D2 - range
|
||||
*
|
||||
* D3 - frq range
|
||||
*
|
||||
* D4 main value LSB
|
||||
* D5 main value MSB
|
||||
*
|
||||
* (secondary value, hz, min/max, rel)
|
||||
* D6 secondary value LSB
|
||||
* D7 secondary value MSB
|
||||
*
|
||||
* D8 - flags
|
||||
* bits:
|
||||
* B7..B1:??
|
||||
* B0 - 0 - auto, 1 - manual
|
||||
*
|
||||
* resistance:
|
||||
* 55 04 00 00 9B 18 00 00 01 (0.L, manual) 600.0 Ohm (x 0.1)
|
||||
* 55 04 01 00 9B 18 00 00 01 (0.L, manual) 6.000 kOhm (x 0.001)
|
||||
* 55 04 02 00 9B 18 00 00 01 (0.L, manual) 60.00 kOhm (x 0.01)
|
||||
* 55 04 03 00 9B 18 00 00 01 (0.L, manual) 600.0 kOhm (x 0.1)
|
||||
* 55 04 04 00 9B 18 00 00 01 (0.L, manual) 6.000 MOhm (x 0.001)
|
||||
* 55 04 05 00 9B 18 00 00 00 (0.L, auto) 60.00 MOhm (x 0.01)
|
||||
*
|
||||
* capacitance:
|
||||
* 55 05 00 00 04 00 00 00 00 (4nF, auto)
|
||||
* 55 05 00 00 05 00 00 00 01 (5nF, manual) 6.000 nF (x 0.001)
|
||||
* 55 05 01 00 03 19 00 00 01 (0.L nF, manual) 60.00 nF (x 0.01)
|
||||
* 55 05 02 00 D4 03 00 00 01 (980.0 nF, manual) 600.0 nF (x 0.1)
|
||||
* 55 05 03 00 63 00 00 00 01 (0.099 uF, manual) 6.000 uF (x 0.001)
|
||||
* 55 05 04 00 40 18 00 00 01 (0.L uF, manual)
|
||||
* 55 05 04 00 F0 00 00 00 01 (2.40 uF, manual) 60.00 uF (x 0.01)
|
||||
* 55 05 05 00 17 00 00 00 01 (2.3 uF, manual) 600.0 uF (x 0.1)
|
||||
* 55 05 06 00 02 00 00 00 01 (0.002 mF, manual) 6.000 mF (x 0.001)
|
||||
* 55 05 07 00 2F 00 00 00 01 (0.47 mF, manual) 60.00 mF (x 0.01)
|
||||
*
|
||||
* voltage:
|
||||
* 55 02 00 00 00 00 00 00 01 (0.0mV, manual) 600.0 mV (x 0.1)
|
||||
* 55 02 01 00 00 00 00 00 00 (0.000V, auto)
|
||||
* 55 02 01 00 00 00 00 00 01 (0.000V, manual) 6.000 V (x 0.001)
|
||||
* 55 02 02 00 00 00 00 00 01 (0.00V, manual) 60.00 V (x 0.01)
|
||||
* 55 02 03 00 00 00 00 00 01 (0.0V, manual) 600.0 V (x 0.1)
|
||||
* 55 02 04 00 00 00 00 00 01 (0V, manual) 1000 V (x 1)
|
||||
*
|
||||
* - Communication parameters: Unidirectional, 1200/8n1
|
||||
* - CP2102 USB to UART bridge controller
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <glib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "ms2115b"
|
||||
|
||||
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||
const struct ms2115b_info *info)
|
||||
{
|
||||
/* Measurement modes */
|
||||
if (info->is_volt) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
}
|
||||
if (info->is_ampere) {
|
||||
analog->meaning->mq = SR_MQ_CURRENT;
|
||||
analog->meaning->unit = SR_UNIT_AMPERE;
|
||||
}
|
||||
if (info->is_ohm) {
|
||||
analog->meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog->meaning->unit = SR_UNIT_OHM;
|
||||
}
|
||||
if (info->is_hz) {
|
||||
analog->meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog->meaning->unit = SR_UNIT_HERTZ;
|
||||
}
|
||||
if (info->is_farad) {
|
||||
analog->meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog->meaning->unit = SR_UNIT_FARAD;
|
||||
}
|
||||
if (info->is_beep) {
|
||||
analog->meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog->meaning->unit = SR_UNIT_BOOLEAN;
|
||||
*floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
|
||||
}
|
||||
if (info->is_diode) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
}
|
||||
|
||||
if (info->is_duty_cycle)
|
||||
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
|
||||
if (info->is_percent)
|
||||
analog->meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
|
||||
/* Measurement related flags */
|
||||
if (info->is_ac)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
||||
if (info->is_dc)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
if (info->is_auto)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||
if (info->is_diode)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||
}
|
||||
|
||||
SR_PRIV gboolean sr_ms2115b_packet_valid(const uint8_t *buf)
|
||||
{
|
||||
sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
|
||||
buf[7], buf[8]);
|
||||
|
||||
if (buf[0] == 0x55)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Mode values equal to received data */
|
||||
enum {
|
||||
MODE_A600_1000 = 0,
|
||||
MODE_A60 = 1,
|
||||
MODE_V = 2,
|
||||
MODE_DIODE_BEEP = 3,
|
||||
MODE_OHM = 4,
|
||||
MODE_CAP = 5,
|
||||
MODE_HZ = 6,
|
||||
};
|
||||
|
||||
static const int res_exp[] = {
|
||||
-1, /* 600.0 Ohm (x 0.1) */
|
||||
-3 + 3, /* 6.000 kOhm (x 0.001) */
|
||||
-2 + 3, /* 60.00 kOhm (x 0.01) */
|
||||
-1 + 3, /* 600.0 kOhm (x 0.1) */
|
||||
-3 + 6, /* 6.000 MOhm (x 0.001) */
|
||||
-2 + 6, /* 60.00 MOhm (x 0.01) */
|
||||
};
|
||||
|
||||
static const int cap_exp[] = {
|
||||
-3 - 9, /* 6.000 nF (x 0.001) */
|
||||
-2 - 9, /* 60.00 nF (x 0.01) */
|
||||
-1 - 9, /* 600.0 nF (x 0.1) */
|
||||
-3 - 6, /* 6.000 uF (x 0.001) */
|
||||
-2 - 6, /* 60.00 uF (x 0.01) */
|
||||
-1 - 6, /* 600.0 uF (x 0.1) */
|
||||
-3 - 3, /* 6.000 mF (x 0.001) */
|
||||
-2 - 3, /* 60.00 mF (x 0.01) */
|
||||
};
|
||||
|
||||
static const int hz_exp[] = {
|
||||
-2, /* 60.00 Hz (x 0.01) */
|
||||
-1, /* 600.0 Hz (x 0.1) */
|
||||
-3 + 3, /* 6.000 kHz (x 0.001) */
|
||||
-2 + 3, /* 60.00 kHz (x 0.01) */
|
||||
-1 + 3, /* 600.0 kHz (x 0.1) */
|
||||
-3 + 6, /* 6.000 MHz (x 0.001) */
|
||||
-2 + 6, /* 60.00 MHz (x 0.01) */
|
||||
};
|
||||
|
||||
static const int v_exp[] = {
|
||||
-1 - 3, /* 600.0 mV (x 0.1) */
|
||||
-3, /* 6.000 V (x 0.001) */
|
||||
-2, /* 60.00 V (x 0.01) */
|
||||
-1, /* 600.0 V (x 0.1) */
|
||||
0, /* 1000 V (x 1) */
|
||||
};
|
||||
|
||||
SR_PRIV const char *ms2115b_channel_formats[MS2115B_DISPLAY_COUNT] = {
|
||||
"main", "sub",
|
||||
};
|
||||
|
||||
static int ms2115b_parse(const uint8_t *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog, void *info)
|
||||
{
|
||||
int exponent = 0;
|
||||
float up_limit = 6000.0;
|
||||
gboolean sign = FALSE;
|
||||
|
||||
uint32_t mode = (buf[1] & 7);
|
||||
gboolean func = (buf[1] & 8) ? TRUE : FALSE;
|
||||
uint32_t range = (buf[2] & 7);
|
||||
|
||||
struct ms2115b_info *info_local = info;
|
||||
|
||||
enum eev121gw_display display = info_local->ch_idx;
|
||||
memset(info_local, 0, sizeof(*info_local));
|
||||
info_local->ch_idx = display;
|
||||
|
||||
switch (display) {
|
||||
case MS2115B_DISPLAY_MAIN:
|
||||
switch (mode) {
|
||||
case MODE_A600_1000:
|
||||
exponent = -1;
|
||||
sign = TRUE;
|
||||
info_local->is_ampere = TRUE;
|
||||
if (func)
|
||||
info_local->is_dc = TRUE;
|
||||
else
|
||||
info_local->is_ac = TRUE;
|
||||
break;
|
||||
case MODE_A60:
|
||||
exponent = -2;
|
||||
sign = TRUE;
|
||||
info_local->is_ampere = TRUE;
|
||||
if (func)
|
||||
info_local->is_dc = TRUE;
|
||||
else
|
||||
info_local->is_ac = TRUE;
|
||||
break;
|
||||
case MODE_V:
|
||||
if (range >= ARRAY_SIZE(v_exp))
|
||||
return SR_ERR;
|
||||
exponent = v_exp[range];
|
||||
sign = TRUE;
|
||||
info_local->is_volt = TRUE;
|
||||
if (func)
|
||||
info_local->is_dc = TRUE;
|
||||
else
|
||||
info_local->is_ac = TRUE;
|
||||
break;
|
||||
case MODE_DIODE_BEEP:
|
||||
if (func) {
|
||||
exponent = -3;
|
||||
up_limit = 2500.0;
|
||||
info_local->is_diode = TRUE;
|
||||
} else {
|
||||
info_local->is_beep = TRUE;
|
||||
}
|
||||
break;
|
||||
case MODE_OHM:
|
||||
if (range >= ARRAY_SIZE(res_exp))
|
||||
return SR_ERR;
|
||||
exponent = res_exp[range];
|
||||
info_local->is_ohm = TRUE;
|
||||
break;
|
||||
case MODE_CAP:
|
||||
if (range >= ARRAY_SIZE(cap_exp))
|
||||
return SR_ERR;
|
||||
exponent = cap_exp[range];
|
||||
info_local->is_farad = TRUE;
|
||||
break;
|
||||
case MODE_HZ:
|
||||
range = (buf[3] & 7);
|
||||
if (range >= ARRAY_SIZE(hz_exp))
|
||||
return SR_ERR;
|
||||
exponent = hz_exp[range];
|
||||
info_local->is_hz = TRUE;
|
||||
break;
|
||||
default:
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
*floatval = RL16S(buf + 4); /* signed 16bit value */
|
||||
} else {
|
||||
*floatval = RL16(buf + 4); /* unsigned 16bit value */
|
||||
}
|
||||
|
||||
info_local->is_auto = (buf[8] & 1) ? FALSE : TRUE;
|
||||
break;
|
||||
case MS2115B_DISPLAY_SUB:
|
||||
switch (mode) {
|
||||
case MODE_A600_1000:
|
||||
case MODE_A60:
|
||||
case MODE_V:
|
||||
if (func) /* DC */
|
||||
return SR_ERR_NA;
|
||||
|
||||
/* AC */
|
||||
info_local->is_hz = TRUE;
|
||||
exponent = -2;
|
||||
break;
|
||||
case MODE_HZ:
|
||||
info_local->is_duty_cycle = TRUE;
|
||||
info_local->is_percent = TRUE;
|
||||
exponent = -1;
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
||||
*floatval = RL16(buf + 6); /* unsigned 16bit value */
|
||||
break;
|
||||
default:
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if (fabsf(*floatval) > up_limit) {
|
||||
sr_spew("Over limit.");
|
||||
*floatval = INFINITY;
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
*floatval *= powf(10, exponent);
|
||||
|
||||
handle_flags(analog, floatval, info_local);
|
||||
|
||||
analog->encoding->digits = -exponent;
|
||||
analog->spec->spec_digits = -exponent;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a protocol packet.
|
||||
*
|
||||
* @param buf Buffer containing the 9-byte protocol packet. Must not be NULL.
|
||||
* @param floatval Pointer to a float variable. That variable will contain the
|
||||
* result value upon parsing success. Must not be NULL.
|
||||
* @param analog Pointer to a struct sr_datafeed_analog. The struct will be
|
||||
* filled with data according to the protocol packet.
|
||||
* Must not be NULL.
|
||||
* @param info Pointer to a struct ms2115b_info. The struct will be filled
|
||||
* with data according to the protocol packet. Must not be NULL.
|
||||
*
|
||||
* @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
|
||||
* 'analog' variable contents are undefined and should not be used.
|
||||
*/
|
||||
SR_PRIV int sr_ms2115b_parse(const uint8_t *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog, void *info)
|
||||
{
|
||||
int ret;
|
||||
int ch_idx;
|
||||
struct ms2115b_info *info_local = info;
|
||||
|
||||
ch_idx = info_local->ch_idx;
|
||||
ret = ms2115b_parse(buf, floatval, analog, info);
|
||||
info_local->ch_idx = ch_idx + 1;
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -20,8 +20,9 @@
|
|||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#ifndef HAVE_LIBSERIALPORT
|
||||
#ifndef HAVE_SERIAL_COMM
|
||||
|
||||
SR_API GSList *sr_serial_list(const struct sr_dev_driver *driver)
|
||||
{
|
||||
|
|
|
@ -60,6 +60,7 @@ extern const struct agdmm_recv agdmm_recvs_u123x[];
|
|||
extern const struct agdmm_recv agdmm_recvs_u124x[];
|
||||
extern const struct agdmm_recv agdmm_recvs_u124xc[];
|
||||
extern const struct agdmm_recv agdmm_recvs_u125x[];
|
||||
extern const struct agdmm_recv agdmm_recvs_u127x[];
|
||||
extern const struct agdmm_recv agdmm_recvs_u128x[];
|
||||
|
||||
/* This works on all the Agilent U12xxA series, although the
|
||||
|
@ -86,6 +87,10 @@ static const struct agdmm_profile supported_agdmm[] = {
|
|||
{ AGILENT_U1252, "U1252B", 3, agdmm_jobs_live, NULL, agdmm_recvs_u125x },
|
||||
{ AGILENT_U1253, "U1253B", 3, agdmm_jobs_live, NULL, agdmm_recvs_u125x },
|
||||
|
||||
{ AGILENT_U1271, "U1271A", 3, agdmm_jobs_live, NULL, agdmm_recvs_u127x },
|
||||
{ AGILENT_U1272, "U1272A", 3, agdmm_jobs_live, NULL, agdmm_recvs_u127x },
|
||||
{ AGILENT_U1273, "U1273A", 3, agdmm_jobs_live, NULL, agdmm_recvs_u127x },
|
||||
|
||||
{ KEYSIGHT_U1281, "U1281A", 3, agdmm_jobs_live, agdmm_jobs_log, agdmm_recvs_u128x },
|
||||
{ KEYSIGHT_U1282, "U1282A", 3, agdmm_jobs_live, agdmm_jobs_log, agdmm_recvs_u128x },
|
||||
ALL_ZERO
|
||||
|
|
|
@ -574,6 +574,12 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
|
|||
devc->cur_mqflags[i] = 0;
|
||||
devc->cur_exponent[i] = 0;
|
||||
devc->cur_digits[i] = 3 - resolution;
|
||||
} else if (!strcmp(mstr, "MA")) {
|
||||
devc->cur_mq[i] = SR_MQ_CURRENT;
|
||||
devc->cur_unit[i] = SR_UNIT_AMPERE;
|
||||
devc->cur_mqflags[i] = 0;
|
||||
devc->cur_exponent[i] = -3;
|
||||
devc->cur_digits[i] = 8 - resolution;
|
||||
} else if (!strcmp(mstr, "UA")) {
|
||||
devc->cur_mq[i] = SR_MQ_CURRENT;
|
||||
devc->cur_unit[i] = SR_UNIT_AMPERE;
|
||||
|
@ -603,6 +609,12 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
|
|||
devc->cur_mqflags[i] = SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||
devc->cur_exponent[i] = 0;
|
||||
devc->cur_digits[i] = 3;
|
||||
} else if (!strcmp(mstr, "TEMP")) {
|
||||
devc->cur_mq[i] = SR_MQ_TEMPERATURE;
|
||||
devc->cur_unit[i] = SR_UNIT_CELSIUS;
|
||||
devc->cur_mqflags[i] = 0;
|
||||
devc->cur_exponent[i] = 0;
|
||||
devc->cur_digits[i] = 1;
|
||||
} else if (!strcmp(mstr, "CAP")) {
|
||||
devc->cur_mq[i] = SR_MQ_CAPACITANCE;
|
||||
devc->cur_unit[i] = SR_UNIT_FARAD;
|
||||
|
@ -625,6 +637,8 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
|
|||
devc->cur_mqflags[i] |= SR_MQFLAG_RMS;
|
||||
} else if (!strcmp(mstr, "DC")) {
|
||||
devc->cur_mqflags[i] |= SR_MQFLAG_DC;
|
||||
} else if (!strcmp(mstr, "ACDC")) {
|
||||
devc->cur_mqflags[i] |= SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS;
|
||||
} else {
|
||||
sr_dbg("Unknown first argument '%s'.", mstr);
|
||||
}
|
||||
|
@ -632,7 +646,14 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
|
|||
} else
|
||||
devc->cur_mqflags[i] &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
|
||||
|
||||
return JOB_CONF;
|
||||
struct sr_channel *prev_conf = devc->cur_conf;
|
||||
devc->cur_conf = sr_next_enabled_channel(sdi, devc->cur_conf);
|
||||
if (devc->cur_conf->index >= MIN(devc->profile->nb_channels, 2))
|
||||
devc->cur_conf = sr_next_enabled_channel(sdi, devc->cur_conf);
|
||||
if (devc->cur_conf->index > prev_conf->index)
|
||||
return JOB_AGAIN;
|
||||
else
|
||||
return JOB_CONF;
|
||||
}
|
||||
|
||||
static int recv_conf_u124x_5x(const struct sr_dev_inst *sdi, GMatchInfo *match)
|
||||
|
@ -1017,12 +1038,24 @@ SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
|
|||
{ "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
|
||||
{ "^\\*([0-9])$", recv_switch },
|
||||
{ "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
|
||||
{ "^\"(VOLT|CURR|RES|CAP|FREQ) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(CURR:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(CPER:[40]-20mA) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(VOLT|CURR|RES|CONT|COND|CAP|FREQ) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(CURR:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(CPER:[40]-20mA) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(PULS:PWID|PULS:PWID:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(TEMP:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(T[0-9]:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(DIOD)\"$", recv_conf_u124x_5x },
|
||||
{ "^\"(DIOD|PULS:[PN]DUT)\"$", recv_conf_u124x_5x },
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
SR_PRIV const struct agdmm_recv agdmm_recvs_u127x[] = {
|
||||
{ "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u123x },
|
||||
{ "^\\*([0-9])$", recv_switch },
|
||||
{ "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
|
||||
{ "^\"(V|MV|A|MA|UA|FREQ),(\\d),(AC|DC|ACDC)\"$", recv_conf_u123x },
|
||||
{ "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x},
|
||||
{ "^\"(DIOD|TEMP)\"$", recv_conf_u123x },
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
|
|
|
@ -54,6 +54,10 @@ enum {
|
|||
AGILENT_U1252,
|
||||
AGILENT_U1253,
|
||||
|
||||
AGILENT_U1271,
|
||||
AGILENT_U1272,
|
||||
AGILENT_U1273,
|
||||
|
||||
KEYSIGHT_U1281,
|
||||
KEYSIGHT_U1282,
|
||||
};
|
||||
|
|
|
@ -83,7 +83,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
|
||||
/* Let's get a bit of data and see if we can find a packet. */
|
||||
if (serial_stream_detect(serial, buf, &len, 25,
|
||||
appa_55ii_packet_valid, 500, 9600) != SR_OK)
|
||||
appa_55ii_packet_valid, 500) != SR_OK)
|
||||
goto scan_cleanup;
|
||||
|
||||
sr_info("Found device on port %s.", conn);
|
||||
|
|
|
@ -265,31 +265,6 @@ SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
static int send_config_update_key(const struct sr_dev_inst *sdi,
|
||||
uint32_t key, GVariant *var)
|
||||
{
|
||||
struct sr_config *cfg;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_meta meta;
|
||||
int ret;
|
||||
|
||||
cfg = sr_config_new(key, var);
|
||||
if (!cfg)
|
||||
return SR_ERR;
|
||||
|
||||
memset(&meta, 0, sizeof(meta));
|
||||
|
||||
packet.type = SR_DF_META;
|
||||
packet.payload = &meta;
|
||||
|
||||
meta.config = g_slist_append(meta.config, cfg);
|
||||
|
||||
ret = sr_session_send(sdi, &packet);
|
||||
sr_config_free(cfg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handle_packet(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_datafeed_packet packet;
|
||||
|
@ -306,7 +281,7 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
|||
if (g_str_has_prefix((const char *)devc->buf, "overtemp")) {
|
||||
sr_warn("Overtemperature condition!");
|
||||
devc->otp_active = TRUE;
|
||||
send_config_update_key(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(TRUE));
|
||||
return;
|
||||
}
|
||||
|
@ -314,7 +289,7 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
|||
if (g_str_has_prefix((const char *)devc->buf, "undervolt")) {
|
||||
sr_warn("Undervoltage condition!");
|
||||
devc->uvc_active = TRUE;
|
||||
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE,
|
||||
sr_session_send_meta(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE,
|
||||
g_variant_new_boolean(TRUE));
|
||||
return;
|
||||
}
|
||||
|
@ -329,7 +304,7 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
|||
devc->current_limit = g_ascii_strtod(tokens[1], NULL) / 1000;
|
||||
g_strfreev(tokens);
|
||||
g_cond_signal(&devc->current_limit_cond);
|
||||
send_config_update_key(sdi, SR_CONF_CURRENT_LIMIT,
|
||||
sr_session_send_meta(sdi, SR_CONF_CURRENT_LIMIT,
|
||||
g_variant_new_double(devc->current_limit));
|
||||
return;
|
||||
}
|
||||
|
@ -340,12 +315,12 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
|||
g_strfreev(tokens);
|
||||
g_cond_signal(&devc->uvc_threshold_cond);
|
||||
if (devc->uvc_threshold == .0) {
|
||||
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
|
||||
sr_session_send_meta(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
|
||||
g_variant_new_boolean(FALSE));
|
||||
} else {
|
||||
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
|
||||
sr_session_send_meta(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
|
||||
g_variant_new_boolean(TRUE));
|
||||
send_config_update_key(sdi,
|
||||
sr_session_send_meta(sdi,
|
||||
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD,
|
||||
g_variant_new_double(devc->uvc_threshold));
|
||||
}
|
||||
|
|
|
@ -168,11 +168,17 @@ static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
|
|||
*triggerpos = result[0] | (result[1] << 8) | (result[2] << 16);
|
||||
*stoppos = result[3] | (result[4] << 8) | (result[5] << 16);
|
||||
|
||||
/* Not really sure why this must be done, but according to spec. */
|
||||
/*
|
||||
* These "position" values point to after the event (end of
|
||||
* capture data, trigger condition matched). This is why they
|
||||
* get decremented here. Sample memory consists of 512-byte
|
||||
* chunks with meta data in the upper 64 bytes. Thus when the
|
||||
* decrements takes us into this upper part of the chunk, then
|
||||
* further move backwards to the end of the chunk's data part.
|
||||
*/
|
||||
if ((--*stoppos & 0x1ff) == 0x1ff)
|
||||
*stoppos -= 64;
|
||||
|
||||
if ((*--triggerpos & 0x1ff) == 0x1ff)
|
||||
if ((--*triggerpos & 0x1ff) == 0x1ff)
|
||||
*triggerpos -= 64;
|
||||
|
||||
return 1;
|
||||
|
@ -1009,8 +1015,6 @@ static int download_capture(struct sr_dev_inst *sdi)
|
|||
|
||||
devc = sdi->priv;
|
||||
dl_events_in_line = 64 * 7;
|
||||
trg_line = ~0;
|
||||
trg_event = ~0;
|
||||
|
||||
dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line));
|
||||
if (!dram_line)
|
||||
|
@ -1038,6 +1042,8 @@ static int download_capture(struct sr_dev_inst *sdi)
|
|||
|
||||
/* Check if trigger has fired. */
|
||||
modestatus = sigma_get_register(READ_MODE, devc);
|
||||
trg_line = ~0;
|
||||
trg_event = ~0;
|
||||
if (modestatus & RMR_TRIGGERED) {
|
||||
trg_line = triggerpos >> 9;
|
||||
trg_event = triggerpos & 0x1ff;
|
||||
|
|
|
@ -272,7 +272,7 @@ static int beaglelogic_set_buffersize(struct dev_context *devc)
|
|||
int ret;
|
||||
char *resp;
|
||||
|
||||
beaglelogic_tcp_send_cmd(devc, "memalloc %lu", devc->buffersize);
|
||||
beaglelogic_tcp_send_cmd(devc, "memalloc %" PRIu32, devc->buffersize);
|
||||
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||
ret = SR_OK;
|
||||
|
@ -301,7 +301,7 @@ static int beaglelogic_set_samplerate(struct dev_context *devc)
|
|||
int ret;
|
||||
char *resp;
|
||||
|
||||
beaglelogic_tcp_send_cmd(devc, "samplerate %lu",
|
||||
beaglelogic_tcp_send_cmd(devc, "samplerate %" PRIu32,
|
||||
(uint32_t)devc->cur_samplerate);
|
||||
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||
|
@ -325,7 +325,7 @@ static int beaglelogic_set_sampleunit(struct dev_context *devc)
|
|||
int ret;
|
||||
char *resp;
|
||||
|
||||
beaglelogic_tcp_send_cmd(devc, "sampleunit %lu", devc->sampleunit);
|
||||
beaglelogic_tcp_send_cmd(devc, "sampleunit %" PRIu32, devc->sampleunit);
|
||||
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||
ret = SR_OK;
|
||||
|
@ -348,7 +348,7 @@ static int beaglelogic_set_triggerflags(struct dev_context *devc)
|
|||
int ret;
|
||||
char *resp;
|
||||
|
||||
beaglelogic_tcp_send_cmd(devc, "triggerflags %lu", devc->triggerflags);
|
||||
beaglelogic_tcp_send_cmd(devc, "triggerflags %" PRIu32, devc->triggerflags);
|
||||
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||
ret = SR_OK;
|
||||
|
@ -390,7 +390,7 @@ static int beaglelogic_set_bufunitsize(struct dev_context *devc)
|
|||
int ret;
|
||||
char *resp;
|
||||
|
||||
beaglelogic_tcp_send_cmd(devc, "bufunitsize %ld", devc->bufunitsize);
|
||||
beaglelogic_tcp_send_cmd(devc, "bufunitsize %" PRIu32, devc->bufunitsize);
|
||||
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||
ret = SR_OK;
|
||||
|
|
|
@ -1,222 +0,0 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "protocol.h"
|
||||
|
||||
#define BRYMEN_BC86X "0820.0001"
|
||||
|
||||
static const uint32_t scanopts[] = {
|
||||
SR_CONF_CONN,
|
||||
};
|
||||
|
||||
static const uint32_t drvopts[] = {
|
||||
SR_CONF_MULTIMETER,
|
||||
};
|
||||
|
||||
static const uint32_t devopts[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||
};
|
||||
|
||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||
{
|
||||
GSList *usb_devices, *devices, *l;
|
||||
struct drv_context *drvc;
|
||||
struct dev_context *devc;
|
||||
struct sr_dev_inst *sdi;
|
||||
struct sr_usb_dev_inst *usb;
|
||||
struct sr_config *src;
|
||||
const char *conn;
|
||||
|
||||
drvc = di->context;
|
||||
|
||||
conn = BRYMEN_BC86X;
|
||||
for (l = options; l; l = l->next) {
|
||||
src = l->data;
|
||||
switch (src->key) {
|
||||
case SR_CONF_CONN:
|
||||
conn = g_variant_get_string(src->data, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
devices = NULL;
|
||||
if (!(usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
|
||||
g_slist_free_full(usb_devices, g_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (l = usb_devices; l; l = l->next) {
|
||||
usb = l->data;
|
||||
|
||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||
sdi->status = SR_ST_INACTIVE;
|
||||
sdi->vendor = g_strdup("Brymen");
|
||||
sdi->model = g_strdup("BM869");
|
||||
devc = g_malloc0(sizeof(struct dev_context));
|
||||
sdi->priv = devc;
|
||||
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P1");
|
||||
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P2");
|
||||
|
||||
sdi->inst_type = SR_INST_USB;
|
||||
sdi->conn = usb;
|
||||
|
||||
sr_sw_limits_init(&devc->sw_limits);
|
||||
|
||||
devices = g_slist_append(devices, sdi);
|
||||
}
|
||||
|
||||
return std_scan_complete(di, devices);
|
||||
}
|
||||
|
||||
static int dev_open(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_dev_driver *di = sdi->driver;
|
||||
struct drv_context *drvc = di->context;
|
||||
struct sr_usb_dev_inst *usb;
|
||||
struct dev_context *devc;
|
||||
int ret;
|
||||
|
||||
usb = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) < 0)
|
||||
return SR_ERR;
|
||||
|
||||
if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
|
||||
ret = libusb_detach_kernel_driver(usb->devhdl, 0);
|
||||
if (ret < 0) {
|
||||
sr_err("Failed to detach kernel driver: %s.",
|
||||
libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
devc->detached_kernel_driver = 1;
|
||||
}
|
||||
|
||||
if ((ret = libusb_claim_interface(usb->devhdl, 0)) < 0) {
|
||||
sr_err("Failed to claim interface 0: %s.",
|
||||
libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_close(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_usb_dev_inst *usb;
|
||||
struct dev_context *devc;
|
||||
int ret;
|
||||
|
||||
usb = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
if (!usb->devhdl)
|
||||
return SR_OK;
|
||||
|
||||
if ((ret = libusb_release_interface(usb->devhdl, 0)))
|
||||
sr_err("Failed to release interface 0: %s.\n", libusb_error_name(ret));
|
||||
|
||||
if (!ret && devc->detached_kernel_driver) {
|
||||
if ((ret = libusb_attach_kernel_driver(usb->devhdl, 0)))
|
||||
sr_err("Failed to attach kernel driver: %s.\n",
|
||||
libusb_error_name(ret));
|
||||
else
|
||||
devc->detached_kernel_driver = 0;
|
||||
}
|
||||
|
||||
libusb_close(usb->devhdl);
|
||||
|
||||
return (ret == 0) ? SR_OK : SR_ERR;
|
||||
}
|
||||
|
||||
static int config_get(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc = sdi->priv;
|
||||
|
||||
(void)cg;
|
||||
|
||||
return sr_sw_limits_config_get(&devc->sw_limits, key, data);
|
||||
}
|
||||
|
||||
static int config_set(uint32_t key, GVariant *data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
|
||||
(void)cg;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
|
||||
}
|
||||
|
||||
static int config_list(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||
}
|
||||
|
||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
sr_sw_limits_acquisition_start(&devc->sw_limits);
|
||||
|
||||
std_session_send_df_header(sdi);
|
||||
|
||||
sr_session_source_add(sdi->session, -1, 0, 10,
|
||||
brymen_bm86x_receive_data, (void *)sdi);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||
{
|
||||
std_session_send_df_end(sdi);
|
||||
|
||||
sr_session_source_remove(sdi->session, -1);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static struct sr_dev_driver brymen_bm86x_driver_info = {
|
||||
.name = "brymen-bm86x",
|
||||
.longname = "Brymen BM86X",
|
||||
.api_version = 1,
|
||||
.init = std_init,
|
||||
.cleanup = std_cleanup,
|
||||
.scan = scan,
|
||||
.dev_list = std_dev_list,
|
||||
.dev_clear = std_dev_clear,
|
||||
.config_get = config_get,
|
||||
.config_set = config_set,
|
||||
.config_list = config_list,
|
||||
.dev_open = dev_open,
|
||||
.dev_close = dev_close,
|
||||
.dev_acquisition_start = dev_acquisition_start,
|
||||
.dev_acquisition_stop = dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
SR_REGISTER_DEV_DRIVER(brymen_bm86x_driver_info);
|
|
@ -1,359 +0,0 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "protocol.h"
|
||||
|
||||
#define USB_TIMEOUT 500
|
||||
|
||||
static const char char_map[128] = {
|
||||
[0x20] = '-',
|
||||
[0x5F] = '0',
|
||||
[0x50] = '1',
|
||||
[0x6D] = '2',
|
||||
[0x7C] = '3',
|
||||
[0x72] = '4',
|
||||
[0x3E] = '5',
|
||||
[0x3F] = '6',
|
||||
[0x54] = '7',
|
||||
[0x7F] = '8',
|
||||
[0x7E] = '9',
|
||||
[0x0F] = 'C',
|
||||
[0x27] = 'F',
|
||||
[0x0B] = 'L',
|
||||
[0x79] = 'd',
|
||||
[0x10] = 'i',
|
||||
[0x39] = 'o',
|
||||
};
|
||||
|
||||
static int brymen_bm86x_parse_digits(const unsigned char *buf, int length,
|
||||
char *str, float *floatval,
|
||||
char *temp_unit, int *digits, int flag)
|
||||
{
|
||||
char c, *p = str;
|
||||
int i, ret;
|
||||
|
||||
*digits = INT_MIN;
|
||||
|
||||
if (buf[0] & flag)
|
||||
*p++ = '-';
|
||||
for (i = 0; i < length; i++) {
|
||||
if (i && i < 5 && buf[i+1] & 0x01) {
|
||||
*p++ = '.';
|
||||
*digits = 0;
|
||||
}
|
||||
c = char_map[buf[i+1] >> 1];
|
||||
if (i == 5 && (c == 'C' || c == 'F'))
|
||||
*temp_unit = c;
|
||||
else if (c) {
|
||||
*p++ = c;
|
||||
(*digits)++;
|
||||
}
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
if (*digits < 0)
|
||||
*digits = 0;
|
||||
|
||||
if ((ret = sr_atof_ascii(str, floatval))) {
|
||||
sr_dbg("invalid float string: '%s'", str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static void brymen_bm86x_parse(unsigned char *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog)
|
||||
{
|
||||
char str[16], temp_unit;
|
||||
int ret1, ret2, digits[2], over_limit;
|
||||
|
||||
ret1 = brymen_bm86x_parse_digits(buf+2, 6, str, &floatval[0],
|
||||
&temp_unit, &digits[0], 0x80);
|
||||
over_limit = strstr(str, "0L") || strstr(str, "0.L");
|
||||
ret2 = brymen_bm86x_parse_digits(buf+9, 4, str, &floatval[1],
|
||||
&temp_unit, &digits[1], 0x10);
|
||||
|
||||
/* main display */
|
||||
if (ret1 == SR_OK || over_limit) {
|
||||
/* SI unit */
|
||||
if (buf[8] & 0x01) {
|
||||
analog[0].meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog[0].meaning->unit = SR_UNIT_VOLT;
|
||||
if (!strcmp(str, "diod")) {
|
||||
analog[0].meaning->mqflags |= SR_MQFLAG_DIODE;
|
||||
analog[0].meaning->mqflags |= SR_MQFLAG_DC;
|
||||
}
|
||||
} else if (buf[14] & 0x80) {
|
||||
analog[0].meaning->mq = SR_MQ_CURRENT;
|
||||
analog[0].meaning->unit = SR_UNIT_AMPERE;
|
||||
} else if (buf[14] & 0x20) {
|
||||
analog[0].meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog[0].meaning->unit = SR_UNIT_FARAD;
|
||||
} else if (buf[14] & 0x10) {
|
||||
analog[0].meaning->mq = SR_MQ_CONDUCTANCE;
|
||||
analog[0].meaning->unit = SR_UNIT_SIEMENS;
|
||||
} else if (buf[15] & 0x01) {
|
||||
analog[0].meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog[0].meaning->unit = SR_UNIT_HERTZ;
|
||||
} else if (buf[10] & 0x01) {
|
||||
analog[0].meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog[0].meaning->unit = SR_UNIT_OHM;
|
||||
} else if (buf[15] & 0x10) {
|
||||
analog[0].meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog[0].meaning->unit = SR_UNIT_OHM;
|
||||
} else if (buf[15] & 0x02) {
|
||||
analog[0].meaning->mq = SR_MQ_POWER;
|
||||
analog[0].meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||
} else if (buf[15] & 0x80) {
|
||||
analog[0].meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
analog[0].meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
} else if (buf[ 2] & 0x0A) {
|
||||
analog[0].meaning->mq = SR_MQ_TEMPERATURE;
|
||||
if (temp_unit == 'F')
|
||||
analog[0].meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
else
|
||||
analog[0].meaning->unit = SR_UNIT_CELSIUS;
|
||||
}
|
||||
|
||||
/* when MIN MAX and AVG are displayed at the same time, remove them */
|
||||
if ((buf[1] & 0xE0) == 0xE0)
|
||||
buf[1] &= ~0xE0;
|
||||
|
||||
/* AC/DC/Auto flags */
|
||||
if (buf[1] & 0x10) analog[0].meaning->mqflags |= SR_MQFLAG_DC;
|
||||
if (buf[2] & 0x01) analog[0].meaning->mqflags |= SR_MQFLAG_AC;
|
||||
if (buf[1] & 0x01) analog[0].meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||
if (buf[1] & 0x08) analog[0].meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||
if (buf[1] & 0x20) analog[0].meaning->mqflags |= SR_MQFLAG_MAX;
|
||||
if (buf[1] & 0x40) analog[0].meaning->mqflags |= SR_MQFLAG_MIN;
|
||||
if (buf[1] & 0x80) analog[0].meaning->mqflags |= SR_MQFLAG_AVG;
|
||||
if (buf[3] & 0x01) analog[0].meaning->mqflags |= SR_MQFLAG_RELATIVE;
|
||||
|
||||
/* when dBm is displayed, remove the m suffix so that it is
|
||||
not considered as the 10e-3 SI prefix */
|
||||
if (buf[15] & 0x02)
|
||||
buf[15] &= ~0x04;
|
||||
|
||||
/* SI prefix */
|
||||
if (buf[14] & 0x40) { floatval[0] *= 1e-9; digits[0] += 9; } /* n */
|
||||
if (buf[15] & 0x08) { floatval[0] *= 1e-6; digits[0] += 6; } /* µ */
|
||||
if (buf[15] & 0x04) { floatval[0] *= 1e-3; digits[0] += 3; } /* m */
|
||||
if (buf[15] & 0x40) { floatval[0] *= 1e3; digits[0] -= 3; } /* k */
|
||||
if (buf[15] & 0x20) { floatval[0] *= 1e6; digits[0] -= 6; } /* M */
|
||||
|
||||
if (over_limit) floatval[0] = INFINITY;
|
||||
|
||||
analog[0].encoding->digits = digits[0];
|
||||
analog[0].spec->spec_digits = digits[0];
|
||||
}
|
||||
|
||||
/* secondary display */
|
||||
if (ret2 == SR_OK) {
|
||||
/* SI unit */
|
||||
if (buf[14] & 0x08) {
|
||||
analog[1].meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog[1].meaning->unit = SR_UNIT_VOLT;
|
||||
} else if (buf[9] & 0x04) {
|
||||
analog[1].meaning->mq = SR_MQ_CURRENT;
|
||||
analog[1].meaning->unit = SR_UNIT_AMPERE;
|
||||
} else if (buf[9] & 0x08) {
|
||||
analog[1].meaning->mq = SR_MQ_CURRENT;
|
||||
analog[1].meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
} else if (buf[14] & 0x04) {
|
||||
analog[1].meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog[1].meaning->unit = SR_UNIT_HERTZ;
|
||||
} else if (buf[9] & 0x40) {
|
||||
analog[1].meaning->mq = SR_MQ_TEMPERATURE;
|
||||
if (temp_unit == 'F')
|
||||
analog[1].meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
else
|
||||
analog[1].meaning->unit = SR_UNIT_CELSIUS;
|
||||
}
|
||||
|
||||
/* AC flag */
|
||||
if (buf[9] & 0x20) analog[1].meaning->mqflags |= SR_MQFLAG_AC;
|
||||
|
||||
/* SI prefix */
|
||||
if (buf[ 9] & 0x01) { floatval[1] *= 1e-6; digits[1] += 6; } /* µ */
|
||||
if (buf[ 9] & 0x02) { floatval[1] *= 1e-3; digits[1] += 3; } /* m */
|
||||
if (buf[14] & 0x02) { floatval[1] *= 1e3; digits[1] -= 3; } /* k */
|
||||
if (buf[14] & 0x01) { floatval[1] *= 1e6; digits[1] -= 6; } /* M */
|
||||
|
||||
analog[1].encoding->digits = digits[1];
|
||||
analog[1].spec->spec_digits = digits[1];
|
||||
}
|
||||
|
||||
if (buf[9] & 0x80)
|
||||
sr_spew("Battery is low.");
|
||||
}
|
||||
|
||||
static void brymen_bm86x_handle_packet(const struct sr_dev_inst *sdi,
|
||||
unsigned char *buf)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog analog[2];
|
||||
struct sr_analog_encoding encoding[2];
|
||||
struct sr_analog_meaning meaning[2];
|
||||
struct sr_analog_spec spec[2];
|
||||
struct sr_channel *channel;
|
||||
int sent_ch1, sent_ch2;
|
||||
float floatval[2];
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
/* Note: digits/spec_digits will be overridden later. */
|
||||
sr_analog_init(&analog[0], &encoding[0], &meaning[0], &spec[0], 0);
|
||||
sr_analog_init(&analog[1], &encoding[1], &meaning[1], &spec[1], 0);
|
||||
|
||||
brymen_bm86x_parse(buf, floatval, analog);
|
||||
sent_ch1 = sent_ch2 = 0;
|
||||
|
||||
channel = sdi->channels->data;
|
||||
if (analog[0].meaning->mq != 0 && channel->enabled) {
|
||||
/* Got a measurement. */
|
||||
sent_ch1 = 1;
|
||||
analog[0].num_samples = 1;
|
||||
analog[0].data = &floatval[0];
|
||||
analog[0].meaning->channels = g_slist_append(NULL, channel);
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &analog[0];
|
||||
sr_session_send(sdi, &packet);
|
||||
g_slist_free(analog[0].meaning->channels);
|
||||
}
|
||||
|
||||
channel = sdi->channels->next->data;
|
||||
if (analog[1].meaning->mq != 0 && channel->enabled) {
|
||||
/* Got a measurement. */
|
||||
sent_ch2 = 1;
|
||||
analog[1].num_samples = 1;
|
||||
analog[1].data = &floatval[1];
|
||||
analog[1].meaning->channels = g_slist_append(NULL, channel);
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &analog[1];
|
||||
sr_session_send(sdi, &packet);
|
||||
g_slist_free(analog[1].meaning->channels);
|
||||
}
|
||||
|
||||
if (sent_ch1 || sent_ch2)
|
||||
sr_sw_limits_update_samples_read(&devc->sw_limits, 1);
|
||||
}
|
||||
|
||||
static int brymen_bm86x_send_command(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_usb_dev_inst *usb;
|
||||
unsigned char buf[] = { 0x00, 0x86, 0x66 };
|
||||
int ret;
|
||||
|
||||
usb = sdi->conn;
|
||||
|
||||
sr_dbg("Sending HID set report.");
|
||||
ret = libusb_control_transfer(usb->devhdl,
|
||||
LIBUSB_REQUEST_TYPE_CLASS |
|
||||
LIBUSB_RECIPIENT_INTERFACE |
|
||||
LIBUSB_ENDPOINT_OUT,
|
||||
9, /* bRequest: HID set_report */
|
||||
0x300, /* wValue: HID feature, report num 0 */
|
||||
0, /* wIndex: interface 0 */
|
||||
buf, sizeof(buf), USB_TIMEOUT);
|
||||
|
||||
if (ret < 0) {
|
||||
sr_err("HID feature report error: %s.", libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if (ret != sizeof(buf)) {
|
||||
sr_err("Short packet: sent %d/%zu bytes.", ret, sizeof(buf));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int brymen_bm86x_read_interrupt(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_usb_dev_inst *usb;
|
||||
unsigned char buf[24];
|
||||
int ret, transferred;
|
||||
|
||||
devc = sdi->priv;
|
||||
usb = sdi->conn;
|
||||
|
||||
sr_dbg("Reading HID interrupt report.");
|
||||
/* Get data from EP1 using an interrupt transfer. */
|
||||
ret = libusb_interrupt_transfer(usb->devhdl,
|
||||
LIBUSB_ENDPOINT_IN | 1, /* EP1, IN */
|
||||
buf, sizeof(buf),
|
||||
&transferred, USB_TIMEOUT);
|
||||
|
||||
if (ret == LIBUSB_ERROR_TIMEOUT) {
|
||||
if (++devc->interrupt_pending > 3)
|
||||
devc->interrupt_pending = 0;
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
sr_err("USB receive error: %s.", libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if (transferred != sizeof(buf)) {
|
||||
sr_err("Short packet: received %d/%zu bytes.", transferred, sizeof(buf));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
devc->interrupt_pending = 0;
|
||||
brymen_bm86x_handle_packet(sdi, buf);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data)
|
||||
{
|
||||
struct sr_dev_inst *sdi;
|
||||
struct dev_context *devc;
|
||||
|
||||
(void)fd;
|
||||
(void)revents;
|
||||
|
||||
if (!(sdi = cb_data))
|
||||
return TRUE;
|
||||
|
||||
if (!(devc = sdi->priv))
|
||||
return TRUE;
|
||||
|
||||
if (!devc->interrupt_pending) {
|
||||
if (brymen_bm86x_send_command(sdi))
|
||||
return FALSE;
|
||||
devc->interrupt_pending = 1;
|
||||
}
|
||||
|
||||
if (brymen_bm86x_read_interrupt(sdi))
|
||||
return FALSE;
|
||||
|
||||
if (sr_sw_limits_check(&devc->sw_limits))
|
||||
sr_dev_acquisition_stop(sdi);
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
|
||||
#define LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "brymen-bm86x"
|
||||
|
||||
struct dev_context {
|
||||
struct sr_sw_limits sw_limits;
|
||||
int detached_kernel_driver; /**< Whether kernel driver was detached or not */
|
||||
int interrupt_pending;
|
||||
};
|
||||
|
||||
SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data);
|
||||
|
||||
#endif
|
|
@ -346,7 +346,8 @@ static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
|
|||
g_variant_new_uint64(devc->buf[7] * 1000));
|
||||
meta.config = g_slist_append(NULL, src);
|
||||
sr_session_send(sdi, &packet);
|
||||
g_free(src);
|
||||
g_slist_free(meta.config);
|
||||
sr_config_free(src);
|
||||
devc->buf_len = 0;
|
||||
}
|
||||
} else if (devc->state == ST_GET_LOG_RECORD_DATA) {
|
||||
|
|
|
@ -300,6 +300,11 @@ SR_PRIV int cv_convert_trigger(const struct sr_dev_inst *sdi)
|
|||
|| match->match == SR_TRIGGER_RISING)
|
||||
devc->trigger_pattern |= channel_bit;
|
||||
|
||||
/* LA8 and LA16 support state triggering. */
|
||||
if (match->match == SR_TRIGGER_ONE
|
||||
|| match->match == SR_TRIGGER_ZERO)
|
||||
devc->trigger_mask |= channel_bit;
|
||||
|
||||
/* LA16 (but not LA8) supports edge triggering. */
|
||||
if ((devc->prof->model == CHRONOVU_LA16)) {
|
||||
if (match->match == SR_TRIGGER_RISING
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
|
||||
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||
* Copyright (C) 2015 Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -28,11 +29,10 @@
|
|||
#include "libsigrok-internal.h"
|
||||
#include "protocol.h"
|
||||
|
||||
#define DEFAULT_NUM_LOGIC_CHANNELS 8
|
||||
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
|
||||
#define DEFAULT_NUM_LOGIC_CHANNELS 8
|
||||
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
|
||||
|
||||
#define DEFAULT_NUM_ANALOG_CHANNELS 4
|
||||
#define DEFAULT_ANALOG_AMPLITUDE 10
|
||||
#define DEFAULT_NUM_ANALOG_CHANNELS 5
|
||||
|
||||
/* Note: No spaces allowed because of sigrok-cli. */
|
||||
static const char *logic_pattern_str[] = {
|
||||
|
@ -77,11 +77,14 @@ static const uint32_t devopts_cg_logic[] = {
|
|||
|
||||
static const uint32_t devopts_cg_analog_group[] = {
|
||||
SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_OFFSET | SR_CONF_GET | SR_CONF_SET,
|
||||
};
|
||||
|
||||
static const uint32_t devopts_cg_analog_channel[] = {
|
||||
SR_CONF_MEASURED_QUANTITY | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_OFFSET | SR_CONF_GET | SR_CONF_SET,
|
||||
};
|
||||
|
||||
static const int32_t trigger_matches[] = {
|
||||
|
@ -161,6 +164,13 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
/* Analog channels, channel groups and pattern generators. */
|
||||
devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
if (num_analog_channels > 0) {
|
||||
/*
|
||||
* Have the waveform for analog patterns pre-generated. It's
|
||||
* supposed to be periodic, so the generator just needs to
|
||||
* access the prepared sample data (DDS style).
|
||||
*/
|
||||
demo_generate_analog_pattern(devc);
|
||||
|
||||
pattern = 0;
|
||||
/* An "Analog" channel group with all analog channels in it. */
|
||||
acg = g_malloc0(sizeof(struct sr_channel_group));
|
||||
|
@ -182,13 +192,19 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
/* Every channel gets a generator struct. */
|
||||
ag = g_malloc(sizeof(struct analog_gen));
|
||||
ag->ch = ch;
|
||||
ag->mq = SR_MQ_VOLTAGE;
|
||||
ag->mq_flags = SR_MQFLAG_DC;
|
||||
ag->unit = SR_UNIT_VOLT;
|
||||
ag->amplitude = DEFAULT_ANALOG_AMPLITUDE;
|
||||
ag->offset = DEFAULT_ANALOG_OFFSET;
|
||||
sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2);
|
||||
ag->packet.meaning->channels = cg->channels;
|
||||
ag->packet.meaning->mq = 0;
|
||||
ag->packet.meaning->mqflags = 0;
|
||||
ag->packet.meaning->unit = SR_UNIT_VOLT;
|
||||
ag->packet.data = ag->pattern_data;
|
||||
ag->packet.meaning->mq = ag->mq;
|
||||
ag->packet.meaning->mqflags = ag->mq_flags;
|
||||
ag->packet.meaning->unit = ag->unit;
|
||||
ag->packet.encoding->digits = DEFAULT_ANALOG_ENCODING_DIGITS;
|
||||
ag->packet.spec->spec_digits = DEFAULT_ANALOG_SPEC_DIGITS;
|
||||
ag->packet.data = devc->analog_patterns[pattern];
|
||||
ag->pattern = pattern;
|
||||
ag->avg_val = 0.0f;
|
||||
ag->num_avgs = 0;
|
||||
|
@ -209,6 +225,8 @@ static void clear_helper(struct dev_context *devc)
|
|||
GHashTableIter iter;
|
||||
void *value;
|
||||
|
||||
demo_free_analog_pattern(devc);
|
||||
|
||||
/* Analog generators. */
|
||||
g_hash_table_iter_init(&iter, devc->ch_ag);
|
||||
while (g_hash_table_iter_next(&iter, NULL, &value))
|
||||
|
@ -227,6 +245,7 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
struct dev_context *devc;
|
||||
struct sr_channel *ch;
|
||||
struct analog_gen *ag;
|
||||
GVariant *mq_arr[2];
|
||||
int pattern;
|
||||
|
||||
if (!sdi)
|
||||
|
@ -252,6 +271,18 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
case SR_CONF_AVG_SAMPLES:
|
||||
*data = g_variant_new_uint64(devc->avg_samples);
|
||||
break;
|
||||
case SR_CONF_MEASURED_QUANTITY:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
/* Any channel in the group will do. */
|
||||
ch = cg->channels->data;
|
||||
if (ch->type != SR_CHANNEL_ANALOG)
|
||||
return SR_ERR_ARG;
|
||||
ag = g_hash_table_lookup(devc->ch_ag, ch);
|
||||
mq_arr[0] = g_variant_new_uint32(ag->mq);
|
||||
mq_arr[1] = g_variant_new_uint64(ag->mq_flags);
|
||||
*data = g_variant_new_tuple(mq_arr, 2);
|
||||
break;
|
||||
case SR_CONF_PATTERN_MODE:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
|
@ -277,6 +308,16 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
ag = g_hash_table_lookup(devc->ch_ag, ch);
|
||||
*data = g_variant_new_double(ag->amplitude);
|
||||
break;
|
||||
case SR_CONF_OFFSET:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
/* Any channel in the group will do. */
|
||||
ch = cg->channels->data;
|
||||
if (ch->type != SR_CHANNEL_ANALOG)
|
||||
return SR_ERR_ARG;
|
||||
ag = g_hash_table_lookup(devc->ch_ag, ch);
|
||||
*data = g_variant_new_double(ag->offset);
|
||||
break;
|
||||
case SR_CONF_CAPTURE_RATIO:
|
||||
*data = g_variant_new_uint64(devc->capture_ratio);
|
||||
break;
|
||||
|
@ -293,6 +334,7 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
struct dev_context *devc;
|
||||
struct analog_gen *ag;
|
||||
struct sr_channel *ch;
|
||||
GVariant *mq_tuple_child;
|
||||
GSList *l;
|
||||
int logic_pattern, analog_pattern;
|
||||
|
||||
|
@ -321,6 +363,21 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
devc->avg_samples = g_variant_get_uint64(data);
|
||||
sr_dbg("Setting averaging rate to %" PRIu64, devc->avg_samples);
|
||||
break;
|
||||
case SR_CONF_MEASURED_QUANTITY:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
for (l = cg->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_ANALOG)
|
||||
return SR_ERR_ARG;
|
||||
ag = g_hash_table_lookup(devc->ch_ag, ch);
|
||||
mq_tuple_child = g_variant_get_child_value(data, 0);
|
||||
ag->mq = g_variant_get_uint32(mq_tuple_child);
|
||||
mq_tuple_child = g_variant_get_child_value(data, 1);
|
||||
ag->mq_flags = g_variant_get_uint64(mq_tuple_child);
|
||||
g_variant_unref(mq_tuple_child);
|
||||
}
|
||||
break;
|
||||
case SR_CONF_PATTERN_MODE:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
|
@ -363,6 +420,17 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
ag->amplitude = g_variant_get_double(data);
|
||||
}
|
||||
break;
|
||||
case SR_CONF_OFFSET:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
for (l = cg->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_ANALOG)
|
||||
return SR_ERR_ARG;
|
||||
ag = g_hash_table_lookup(devc->ch_ag, ch);
|
||||
ag->offset = g_variant_get_double(data);
|
||||
}
|
||||
break;
|
||||
case SR_CONF_CAPTURE_RATIO:
|
||||
devc->capture_ratio = g_variant_get_uint64(data);
|
||||
break;
|
||||
|
@ -434,8 +502,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
struct sr_channel *ch;
|
||||
int bitpos;
|
||||
uint8_t mask;
|
||||
GHashTableIter iter;
|
||||
void *value;
|
||||
struct sr_trigger *trigger;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
@ -501,15 +567,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
devc->first_partial_logic_index,
|
||||
devc->first_partial_logic_mask);
|
||||
|
||||
/*
|
||||
* Have the waveform for analog patterns pre-generated. It's
|
||||
* supposed to be periodic, so the generator just needs to
|
||||
* access the prepared sample data (DDS style).
|
||||
*/
|
||||
g_hash_table_iter_init(&iter, devc->ch_ag);
|
||||
while (g_hash_table_iter_next(&iter, NULL, &value))
|
||||
demo_generate_analog_pattern(value, devc->cur_samplerate);
|
||||
|
||||
sr_session_source_add(sdi->session, -1, 0, 100,
|
||||
demo_prepare_data, (struct sr_dev_inst *)sdi);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
|
||||
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||
* Copyright (C) 2015 Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -172,77 +173,92 @@ static const uint8_t pattern_squid[128][128 / 8] = {
|
|||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
};
|
||||
|
||||
SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample_rate)
|
||||
SR_PRIV void demo_generate_analog_pattern(struct dev_context *devc)
|
||||
{
|
||||
double t, frequency;
|
||||
float value;
|
||||
float amplitude, offset;
|
||||
struct analog_pattern *pattern;
|
||||
unsigned int num_samples, i;
|
||||
float value;
|
||||
int last_end;
|
||||
|
||||
sr_dbg("Generating %s pattern.", analog_pattern_str[ag->pattern]);
|
||||
|
||||
num_samples = ANALOG_BUFSIZE / sizeof(float);
|
||||
frequency = (double) devc->cur_samplerate / ANALOG_SAMPLES_PER_PERIOD;
|
||||
amplitude = DEFAULT_ANALOG_AMPLITUDE;
|
||||
offset = DEFAULT_ANALOG_OFFSET;
|
||||
|
||||
switch (ag->pattern) {
|
||||
case PATTERN_SQUARE:
|
||||
value = ag->amplitude;
|
||||
last_end = 0;
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
if (i % 5 == 0)
|
||||
value = -value;
|
||||
if (i % 10 == 0)
|
||||
last_end = i;
|
||||
ag->pattern_data[i] = value;
|
||||
}
|
||||
ag->num_samples = last_end;
|
||||
break;
|
||||
case PATTERN_SINE:
|
||||
frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
|
||||
/*
|
||||
* FIXME: We actually need only one period. A ringbuffer would be
|
||||
* useful here.
|
||||
* Make sure the number of samples we put out is an integer
|
||||
* multiple of our period size.
|
||||
*/
|
||||
|
||||
/* Make sure the number of samples we put out is an integer
|
||||
* multiple of our period size */
|
||||
/* FIXME we actually need only one period. A ringbuffer would be
|
||||
* useful here. */
|
||||
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
|
||||
num_samples--;
|
||||
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
t = (double) i / (double) sample_rate;
|
||||
ag->pattern_data[i] = ag->amplitude *
|
||||
sin(2 * G_PI * frequency * t);
|
||||
}
|
||||
|
||||
ag->num_samples = num_samples;
|
||||
break;
|
||||
case PATTERN_TRIANGLE:
|
||||
frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
|
||||
|
||||
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
|
||||
num_samples--;
|
||||
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
t = (double) i / (double) sample_rate;
|
||||
ag->pattern_data[i] = (2 * ag->amplitude / G_PI) *
|
||||
asin(sin(2 * G_PI * frequency * t));
|
||||
}
|
||||
|
||||
ag->num_samples = num_samples;
|
||||
break;
|
||||
case PATTERN_SAWTOOTH:
|
||||
frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
|
||||
|
||||
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
|
||||
num_samples--;
|
||||
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
t = (double) i / (double) sample_rate;
|
||||
ag->pattern_data[i] = 2 * ag->amplitude *
|
||||
((t * frequency) - floor(0.5f + t * frequency));
|
||||
}
|
||||
|
||||
ag->num_samples = num_samples;
|
||||
break;
|
||||
/* PATTERN_SQUARE: */
|
||||
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SQUARE]);
|
||||
pattern = g_malloc(sizeof(struct analog_pattern));
|
||||
value = amplitude;
|
||||
last_end = 0;
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
if (i % 5 == 0)
|
||||
value = -value;
|
||||
if (i % 10 == 0)
|
||||
last_end = i;
|
||||
pattern->data[i] = value + offset;
|
||||
}
|
||||
pattern->num_samples = last_end;
|
||||
devc->analog_patterns[PATTERN_SQUARE] = pattern;
|
||||
|
||||
/* Readjusting num_samples for all other patterns. */
|
||||
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
|
||||
num_samples--;
|
||||
|
||||
/* PATTERN_SINE: */
|
||||
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SINE]);
|
||||
pattern = g_malloc(sizeof(struct analog_pattern));
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
t = (double) i / (double) devc->cur_samplerate;
|
||||
pattern->data[i] = sin(2 * G_PI * frequency * t) * amplitude + offset;
|
||||
}
|
||||
pattern->num_samples = last_end;
|
||||
devc->analog_patterns[PATTERN_SINE] = pattern;
|
||||
|
||||
/* PATTERN_TRIANGLE: */
|
||||
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_TRIANGLE]);
|
||||
pattern = g_malloc(sizeof(struct analog_pattern));
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
t = (double) i / (double) devc->cur_samplerate;
|
||||
pattern->data[i] = (2 / G_PI) * asin(sin(2 * G_PI * frequency * t)) *
|
||||
amplitude + offset;
|
||||
}
|
||||
pattern->num_samples = last_end;
|
||||
devc->analog_patterns[PATTERN_TRIANGLE] = pattern;
|
||||
|
||||
/* PATTERN_SAWTOOTH: */
|
||||
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SAWTOOTH]);
|
||||
pattern = g_malloc(sizeof(struct analog_pattern));
|
||||
for (i = 0; i < num_samples; i++) {
|
||||
t = (double) i / (double) devc->cur_samplerate;
|
||||
pattern->data[i] = 2 * ((t * frequency) - floor(0.5f + t * frequency)) *
|
||||
amplitude + offset;
|
||||
}
|
||||
pattern->num_samples = last_end;
|
||||
devc->analog_patterns[PATTERN_SAWTOOTH] = pattern;
|
||||
|
||||
/* PATTERN_ANALOG_RANDOM */
|
||||
/* Data not filled here, will be generated in send_analog_packet(). */
|
||||
pattern = g_malloc(sizeof(struct analog_pattern));
|
||||
pattern->num_samples = last_end;
|
||||
devc->analog_patterns[PATTERN_ANALOG_RANDOM] = pattern;
|
||||
}
|
||||
|
||||
SR_PRIV void demo_free_analog_pattern(struct dev_context *devc)
|
||||
{
|
||||
g_free(devc->analog_patterns[PATTERN_SQUARE]);
|
||||
g_free(devc->analog_patterns[PATTERN_SINE]);
|
||||
g_free(devc->analog_patterns[PATTERN_TRIANGLE]);
|
||||
g_free(devc->analog_patterns[PATTERN_SAWTOOTH]);
|
||||
g_free(devc->analog_patterns[PATTERN_ANALOG_RANDOM]);
|
||||
}
|
||||
|
||||
static uint64_t encode_number_to_gray(uint64_t nr)
|
||||
|
@ -389,9 +405,12 @@ static void send_analog_packet(struct analog_gen *ag,
|
|||
{
|
||||
struct sr_datafeed_packet packet;
|
||||
struct dev_context *devc;
|
||||
struct analog_pattern *pattern;
|
||||
uint64_t sending_now, to_avg;
|
||||
int ag_pattern_pos;
|
||||
unsigned int i;
|
||||
float amplitude, offset, value;
|
||||
float *data;
|
||||
|
||||
if (!ag->ch || !ag->ch->enabled)
|
||||
return;
|
||||
|
@ -400,23 +419,132 @@ static void send_analog_packet(struct analog_gen *ag,
|
|||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &ag->packet;
|
||||
|
||||
pattern = devc->analog_patterns[ag->pattern];
|
||||
|
||||
ag->packet.meaning->channels = g_slist_append(NULL, ag->ch);
|
||||
ag->packet.meaning->mq = ag->mq;
|
||||
ag->packet.meaning->mqflags = ag->mq_flags;
|
||||
|
||||
/* Set a unit for the given quantity. */
|
||||
if (ag->mq == SR_MQ_VOLTAGE)
|
||||
ag->packet.meaning->unit = SR_UNIT_VOLT;
|
||||
else if (ag->mq == SR_MQ_CURRENT)
|
||||
ag->packet.meaning->unit = SR_UNIT_AMPERE;
|
||||
else if (ag->mq == SR_MQ_RESISTANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_OHM;
|
||||
else if (ag->mq == SR_MQ_CAPACITANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_FARAD;
|
||||
else if (ag->mq == SR_MQ_TEMPERATURE)
|
||||
ag->packet.meaning->unit = SR_UNIT_CELSIUS;
|
||||
else if (ag->mq == SR_MQ_FREQUENCY)
|
||||
ag->packet.meaning->unit = SR_UNIT_HERTZ;
|
||||
else if (ag->mq == SR_MQ_DUTY_CYCLE)
|
||||
ag->packet.meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
else if (ag->mq == SR_MQ_CONTINUITY)
|
||||
ag->packet.meaning->unit = SR_UNIT_OHM;
|
||||
else if (ag->mq == SR_MQ_PULSE_WIDTH)
|
||||
ag->packet.meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
else if (ag->mq == SR_MQ_CONDUCTANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_SIEMENS;
|
||||
else if (ag->mq == SR_MQ_POWER)
|
||||
ag->packet.meaning->unit = SR_UNIT_WATT;
|
||||
else if (ag->mq == SR_MQ_GAIN)
|
||||
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
|
||||
else if (ag->mq == SR_MQ_SOUND_PRESSURE_LEVEL)
|
||||
ag->packet.meaning->unit = SR_UNIT_DECIBEL_SPL;
|
||||
else if (ag->mq == SR_MQ_CARBON_MONOXIDE)
|
||||
ag->packet.meaning->unit = SR_UNIT_CONCENTRATION;
|
||||
else if (ag->mq == SR_MQ_RELATIVE_HUMIDITY)
|
||||
ag->packet.meaning->unit = SR_UNIT_HUMIDITY_293K;
|
||||
else if (ag->mq == SR_MQ_TIME)
|
||||
ag->packet.meaning->unit = SR_UNIT_SECOND;
|
||||
else if (ag->mq == SR_MQ_WIND_SPEED)
|
||||
ag->packet.meaning->unit = SR_UNIT_METER_SECOND;
|
||||
else if (ag->mq == SR_MQ_PRESSURE)
|
||||
ag->packet.meaning->unit = SR_UNIT_HECTOPASCAL;
|
||||
else if (ag->mq == SR_MQ_PARALLEL_INDUCTANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_HENRY;
|
||||
else if (ag->mq == SR_MQ_PARALLEL_CAPACITANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_FARAD;
|
||||
else if (ag->mq == SR_MQ_PARALLEL_RESISTANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_OHM;
|
||||
else if (ag->mq == SR_MQ_SERIES_INDUCTANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_HENRY;
|
||||
else if (ag->mq == SR_MQ_SERIES_CAPACITANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_FARAD;
|
||||
else if (ag->mq == SR_MQ_SERIES_RESISTANCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_OHM;
|
||||
else if (ag->mq == SR_MQ_DISSIPATION_FACTOR)
|
||||
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
|
||||
else if (ag->mq == SR_MQ_QUALITY_FACTOR)
|
||||
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
|
||||
else if (ag->mq == SR_MQ_PHASE_ANGLE)
|
||||
ag->packet.meaning->unit = SR_UNIT_DEGREE;
|
||||
else if (ag->mq == SR_MQ_DIFFERENCE)
|
||||
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
|
||||
else if (ag->mq == SR_MQ_COUNT)
|
||||
ag->packet.meaning->unit = SR_UNIT_PIECE;
|
||||
else if (ag->mq == SR_MQ_POWER_FACTOR)
|
||||
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
|
||||
else if (ag->mq == SR_MQ_APPARENT_POWER)
|
||||
ag->packet.meaning->unit = SR_UNIT_VOLT_AMPERE;
|
||||
else if (ag->mq == SR_MQ_MASS)
|
||||
ag->packet.meaning->unit = SR_UNIT_GRAM;
|
||||
else if (ag->mq == SR_MQ_HARMONIC_RATIO)
|
||||
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
|
||||
else
|
||||
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
|
||||
|
||||
if (!devc->avg) {
|
||||
ag_pattern_pos = analog_pos % ag->num_samples;
|
||||
sending_now = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
|
||||
ag->packet.data = ag->pattern_data + ag_pattern_pos;
|
||||
ag_pattern_pos = analog_pos % pattern->num_samples;
|
||||
sending_now = MIN(analog_todo, pattern->num_samples - ag_pattern_pos);
|
||||
if (ag->amplitude != DEFAULT_ANALOG_AMPLITUDE ||
|
||||
ag->offset != DEFAULT_ANALOG_OFFSET ||
|
||||
ag->pattern == PATTERN_ANALOG_RANDOM) {
|
||||
/*
|
||||
* Amplitude or offset changed (or we are generating
|
||||
* random data), modify each sample.
|
||||
*/
|
||||
if (ag->pattern == PATTERN_ANALOG_RANDOM) {
|
||||
amplitude = ag->amplitude / 500.0;
|
||||
offset = ag->offset - DEFAULT_ANALOG_OFFSET - ag->amplitude;
|
||||
} else {
|
||||
amplitude = ag->amplitude / DEFAULT_ANALOG_AMPLITUDE;
|
||||
offset = ag->offset - DEFAULT_ANALOG_OFFSET;
|
||||
}
|
||||
data = ag->packet.data;
|
||||
for (i = 0; i < sending_now; i++) {
|
||||
if (ag->pattern == PATTERN_ANALOG_RANDOM)
|
||||
data[i] = (rand() % 1000) * amplitude + offset;
|
||||
else
|
||||
data[i] = pattern->data[ag_pattern_pos + i] * amplitude + offset;
|
||||
}
|
||||
} else {
|
||||
/* Amplitude and offset unchanged, use the fast way. */
|
||||
ag->packet.data = pattern->data + ag_pattern_pos;
|
||||
}
|
||||
ag->packet.num_samples = sending_now;
|
||||
sr_session_send(sdi, &packet);
|
||||
|
||||
/* Whichever channel group gets there first. */
|
||||
*analog_sent = MAX(*analog_sent, sending_now);
|
||||
} else {
|
||||
ag_pattern_pos = analog_pos % ag->num_samples;
|
||||
to_avg = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
|
||||
ag_pattern_pos = analog_pos % pattern->num_samples;
|
||||
to_avg = MIN(analog_todo, pattern->num_samples - ag_pattern_pos);
|
||||
if (ag->pattern == PATTERN_ANALOG_RANDOM) {
|
||||
amplitude = ag->amplitude / 500.0;
|
||||
offset = ag->offset - DEFAULT_ANALOG_OFFSET - ag->amplitude;
|
||||
} else {
|
||||
amplitude = ag->amplitude / DEFAULT_ANALOG_AMPLITUDE;
|
||||
offset = ag->offset - DEFAULT_ANALOG_OFFSET;
|
||||
}
|
||||
|
||||
for (i = 0; i < to_avg; i++) {
|
||||
ag->avg_val = (ag->avg_val +
|
||||
*(ag->pattern_data +
|
||||
ag_pattern_pos + i)) / 2;
|
||||
if (ag->pattern == PATTERN_ANALOG_RANDOM)
|
||||
value = (rand() % 1000) * amplitude + offset;
|
||||
else
|
||||
value = *(pattern->data + ag_pattern_pos + i) * amplitude + offset;
|
||||
ag->avg_val = (ag->avg_val + value) / 2;
|
||||
ag->num_avgs++;
|
||||
/* Time to send averaged data? */
|
||||
if ((devc->avg_samples > 0) && (ag->num_avgs >= devc->avg_samples))
|
||||
|
@ -424,7 +552,8 @@ static void send_analog_packet(struct analog_gen *ag,
|
|||
}
|
||||
|
||||
if (devc->avg_samples == 0) {
|
||||
/* We're averaging all the samples, so wait with
|
||||
/*
|
||||
* We're averaging all the samples, so wait with
|
||||
* sending until the very end.
|
||||
*/
|
||||
*analog_sent = ag->num_avgs;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
|
||||
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||
* Copyright (C) 2015 Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -37,6 +38,11 @@
|
|||
#define SAMPLES_PER_FRAME 1000UL
|
||||
#define DEFAULT_LIMIT_FRAMES 0
|
||||
|
||||
#define DEFAULT_ANALOG_ENCODING_DIGITS 4
|
||||
#define DEFAULT_ANALOG_SPEC_DIGITS 4
|
||||
#define DEFAULT_ANALOG_AMPLITUDE 10
|
||||
#define DEFAULT_ANALOG_OFFSET 0.
|
||||
|
||||
/* Logic patterns we can generate. */
|
||||
enum logic_pattern_type {
|
||||
/**
|
||||
|
@ -89,6 +95,20 @@ enum analog_pattern_type {
|
|||
PATTERN_SINE,
|
||||
PATTERN_TRIANGLE,
|
||||
PATTERN_SAWTOOTH,
|
||||
PATTERN_ANALOG_RANDOM,
|
||||
};
|
||||
|
||||
static const char *analog_pattern_str[] = {
|
||||
"square",
|
||||
"sine",
|
||||
"triangle",
|
||||
"sawtooth",
|
||||
"random",
|
||||
};
|
||||
|
||||
struct analog_pattern {
|
||||
float data[ANALOG_BUFSIZE];
|
||||
unsigned int num_samples;
|
||||
};
|
||||
|
||||
struct dev_context {
|
||||
|
@ -109,6 +129,7 @@ struct dev_context {
|
|||
enum logic_pattern_type logic_pattern;
|
||||
uint8_t logic_data[LOGIC_BUFSIZE];
|
||||
/* Analog */
|
||||
struct analog_pattern *analog_patterns[ARRAY_SIZE(analog_pattern_str)];
|
||||
int32_t num_analog_channels;
|
||||
GHashTable *ch_ag;
|
||||
gboolean avg; /* True if averaging is enabled */
|
||||
|
@ -123,19 +144,14 @@ struct dev_context {
|
|||
struct soft_trigger_logic *stl;
|
||||
};
|
||||
|
||||
static const char *analog_pattern_str[] = {
|
||||
"square",
|
||||
"sine",
|
||||
"triangle",
|
||||
"sawtooth",
|
||||
};
|
||||
|
||||
struct analog_gen {
|
||||
struct sr_channel *ch;
|
||||
enum sr_mq mq;
|
||||
enum sr_mqflag mq_flags;
|
||||
enum sr_unit unit;
|
||||
enum analog_pattern_type pattern;
|
||||
float amplitude;
|
||||
float pattern_data[ANALOG_BUFSIZE];
|
||||
unsigned int num_samples;
|
||||
float offset;
|
||||
struct sr_datafeed_analog packet;
|
||||
struct sr_analog_encoding encoding;
|
||||
struct sr_analog_meaning meaning;
|
||||
|
@ -144,7 +160,8 @@ struct analog_gen {
|
|||
unsigned int num_avgs; /* Number of samples averaged */
|
||||
};
|
||||
|
||||
SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample_rate);
|
||||
SR_PRIV void demo_generate_analog_pattern(struct dev_context *devc);
|
||||
SR_PRIV void demo_free_analog_pattern(struct dev_context *devc);
|
||||
SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
#include "scpi.h"
|
||||
#include "protocol.h"
|
||||
|
||||
/*
|
||||
* This test violates the SCPI protocol, and confuses other devices.
|
||||
* Disable it for now, until a better location was found.
|
||||
*/
|
||||
#define ECHO_TEST 0
|
||||
|
||||
static const uint32_t scanopts[] = {
|
||||
SR_CONF_CONN,
|
||||
SR_CONF_SERIALCOMM,
|
||||
|
@ -62,17 +68,19 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
|||
unsigned int i;
|
||||
const struct fluke_scpi_dmm_model *model = NULL;
|
||||
gchar *channel_name;
|
||||
#if ECHO_TEST
|
||||
char *response;
|
||||
#endif
|
||||
|
||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||
sdi->conn = scpi;
|
||||
|
||||
#if ECHO_TEST
|
||||
/* Test for serial port ECHO enabled. */
|
||||
response = NULL;
|
||||
sr_scpi_get_string(scpi, "ECHO-TEST", &response);
|
||||
if (strcmp(response, "ECHO-TEST") == 0) {
|
||||
if (response && strcmp(response, "ECHO-TEST") == 0) {
|
||||
sr_err("Serial port ECHO is ON. Please turn it OFF!");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get device IDN. */
|
||||
if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
|
||||
|
@ -100,6 +108,7 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
|||
}
|
||||
|
||||
/* Set up device parameters. */
|
||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||
sdi->vendor = g_strdup(model->vendor);
|
||||
sdi->model = g_strdup(model->model);
|
||||
sdi->version = g_strdup(hw_info->firmware_version);
|
||||
|
@ -107,10 +116,12 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
|||
sdi->conn = scpi;
|
||||
sdi->driver = &fluke_45_driver_info;
|
||||
sdi->inst_type = SR_INST_SCPI;
|
||||
sr_scpi_hw_info_free(hw_info);
|
||||
|
||||
devc = g_malloc0(sizeof(struct dev_context));
|
||||
devc->num_channels = model->num_channels;
|
||||
devc->cmdset = cmdset;
|
||||
sdi->priv = devc;
|
||||
|
||||
/* Create channels. */
|
||||
for (i = 0; i < devc->num_channels; i++) {
|
||||
|
@ -118,8 +129,6 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
|||
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, channel_name);
|
||||
}
|
||||
|
||||
sdi->priv = devc;
|
||||
|
||||
return sdi;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,11 @@
|
|||
#include "libsigrok-internal.h"
|
||||
#include "protocol.h"
|
||||
|
||||
static struct sr_datafeed_analog *handle_qm_18x(const struct sr_dev_inst *sdi,
|
||||
char **tokens)
|
||||
static void handle_qm_18x(const struct sr_dev_inst *sdi, char **tokens)
|
||||
{
|
||||
struct sr_datafeed_analog *analog;
|
||||
struct dev_context *devc;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog analog;
|
||||
struct sr_analog_encoding encoding;
|
||||
struct sr_analog_meaning meaning;
|
||||
struct sr_analog_spec spec;
|
||||
|
@ -37,8 +38,10 @@ static struct sr_datafeed_analog *handle_qm_18x(const struct sr_dev_inst *sdi,
|
|||
char *e, *u;
|
||||
gboolean is_oor;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
if (strcmp(tokens[0], "QM") || !tokens[1])
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
if ((e = strstr(tokens[1], "Out of range"))) {
|
||||
is_oor = TRUE;
|
||||
|
@ -56,220 +59,216 @@ static struct sr_datafeed_analog *handle_qm_18x(const struct sr_dev_inst *sdi,
|
|||
if (sr_atof_ascii(tokens[1], &fvalue) != SR_OK || fvalue == 0.0) {
|
||||
/* Happens all the time, when switching modes. */
|
||||
sr_dbg("Invalid float.");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (*e && *e == ' ')
|
||||
e++;
|
||||
|
||||
analog = g_malloc0(sizeof(struct sr_datafeed_analog));
|
||||
/* TODO: Use proper 'digits' value for this device (and its modes). */
|
||||
sr_analog_init(analog, &encoding, &meaning, &spec, 2);
|
||||
analog->data = g_malloc(sizeof(float));
|
||||
analog->meaning->channels = sdi->channels;
|
||||
analog->num_samples = 1;
|
||||
sr_analog_init(&analog, &encoding, &meaning, &spec, 2);
|
||||
analog.data = &fvalue;
|
||||
analog.meaning->channels = sdi->channels;
|
||||
analog.num_samples = 1;
|
||||
if (is_oor)
|
||||
*((float *)analog->data) = NAN;
|
||||
else
|
||||
*((float *)analog->data) = fvalue;
|
||||
analog->meaning->mq = 0;
|
||||
fvalue = NAN;
|
||||
analog.meaning->mq = 0;
|
||||
|
||||
if ((u = strstr(e, "V DC")) || (u = strstr(e, "V AC"))) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
analog.meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog.meaning->unit = SR_UNIT_VOLT;
|
||||
if (!is_oor && e[0] == 'm')
|
||||
*((float *)analog->data) /= 1000;
|
||||
fvalue /= 1000;
|
||||
/* This catches "V AC", "V DC" and "V AC+DC". */
|
||||
if (strstr(u, "AC"))
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
if (strstr(u, "DC"))
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_DC;
|
||||
} else if ((u = strstr(e, "dBV")) || (u = strstr(e, "dBm"))) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog.meaning->mq = SR_MQ_VOLTAGE;
|
||||
if (u[2] == 'm')
|
||||
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||
analog.meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||
else
|
||||
analog->meaning->unit = SR_UNIT_DECIBEL_VOLT;
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
analog.meaning->unit = SR_UNIT_DECIBEL_VOLT;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
} else if ((u = strstr(e, "Ohms"))) {
|
||||
analog->meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog->meaning->unit = SR_UNIT_OHM;
|
||||
analog.meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog.meaning->unit = SR_UNIT_OHM;
|
||||
if (is_oor)
|
||||
*((float *)analog->data) = INFINITY;
|
||||
fvalue = INFINITY;
|
||||
else if (e[0] == 'k')
|
||||
*((float *)analog->data) *= 1000;
|
||||
fvalue *= 1000;
|
||||
else if (e[0] == 'M')
|
||||
*((float *)analog->data) *= 1000000;
|
||||
fvalue *= 1000000;
|
||||
} else if (!strcmp(e, "nS")) {
|
||||
analog->meaning->mq = SR_MQ_CONDUCTANCE;
|
||||
analog->meaning->unit = SR_UNIT_SIEMENS;
|
||||
*((float *)analog->data) /= 1e+9;
|
||||
analog.meaning->mq = SR_MQ_CONDUCTANCE;
|
||||
analog.meaning->unit = SR_UNIT_SIEMENS;
|
||||
*((float *)analog.data) /= 1e+9;
|
||||
} else if ((u = strstr(e, "Farads"))) {
|
||||
analog->meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog->meaning->unit = SR_UNIT_FARAD;
|
||||
analog.meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog.meaning->unit = SR_UNIT_FARAD;
|
||||
if (!is_oor) {
|
||||
if (e[0] == 'm')
|
||||
*((float *)analog->data) /= 1e+3;
|
||||
fvalue /= 1e+3;
|
||||
else if (e[0] == 'u')
|
||||
*((float *)analog->data) /= 1e+6;
|
||||
fvalue /= 1e+6;
|
||||
else if (e[0] == 'n')
|
||||
*((float *)analog->data) /= 1e+9;
|
||||
fvalue /= 1e+9;
|
||||
}
|
||||
} else if ((u = strstr(e, "Deg C")) || (u = strstr(e, "Deg F"))) {
|
||||
analog->meaning->mq = SR_MQ_TEMPERATURE;
|
||||
analog.meaning->mq = SR_MQ_TEMPERATURE;
|
||||
if (u[4] == 'C')
|
||||
analog->meaning->unit = SR_UNIT_CELSIUS;
|
||||
analog.meaning->unit = SR_UNIT_CELSIUS;
|
||||
else
|
||||
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
analog.meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
} else if ((u = strstr(e, "A AC")) || (u = strstr(e, "A DC"))) {
|
||||
analog->meaning->mq = SR_MQ_CURRENT;
|
||||
analog->meaning->unit = SR_UNIT_AMPERE;
|
||||
analog.meaning->mq = SR_MQ_CURRENT;
|
||||
analog.meaning->unit = SR_UNIT_AMPERE;
|
||||
/* This catches "A AC", "A DC" and "A AC+DC". */
|
||||
if (strstr(u, "AC"))
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
if (strstr(u, "DC"))
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_DC;
|
||||
if (!is_oor) {
|
||||
if (e[0] == 'm')
|
||||
*((float *)analog->data) /= 1e+3;
|
||||
fvalue /= 1e+3;
|
||||
else if (e[0] == 'u')
|
||||
*((float *)analog->data) /= 1e+6;
|
||||
fvalue /= 1e+6;
|
||||
}
|
||||
} else if ((u = strstr(e, "Hz"))) {
|
||||
analog->meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog->meaning->unit = SR_UNIT_HERTZ;
|
||||
analog.meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog.meaning->unit = SR_UNIT_HERTZ;
|
||||
if (e[0] == 'k')
|
||||
*((float *)analog->data) *= 1e+3;
|
||||
fvalue *= 1e+3;
|
||||
} else if (!strcmp(e, "%")) {
|
||||
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
analog->meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
analog.meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
analog.meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
} else if ((u = strstr(e, "ms"))) {
|
||||
analog->meaning->mq = SR_MQ_PULSE_WIDTH;
|
||||
analog->meaning->unit = SR_UNIT_SECOND;
|
||||
*((float *)analog->data) /= 1e+3;
|
||||
analog.meaning->mq = SR_MQ_PULSE_WIDTH;
|
||||
analog.meaning->unit = SR_UNIT_SECOND;
|
||||
fvalue /= 1e+3;
|
||||
}
|
||||
|
||||
if (analog->meaning->mq == 0) {
|
||||
/* Not a valid measurement. */
|
||||
g_free(analog->data);
|
||||
g_free(analog);
|
||||
analog = NULL;
|
||||
if (analog.meaning->mq != 0) {
|
||||
/* Got a measurement. */
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &analog;
|
||||
sr_session_send(sdi, &packet);
|
||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||
}
|
||||
|
||||
return analog;
|
||||
}
|
||||
|
||||
static struct sr_datafeed_analog *handle_qm_28x(const struct sr_dev_inst *sdi,
|
||||
char **tokens)
|
||||
static void handle_qm_28x(const struct sr_dev_inst *sdi, char **tokens)
|
||||
{
|
||||
struct sr_datafeed_analog *analog;
|
||||
struct dev_context *devc;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog analog;
|
||||
struct sr_analog_encoding encoding;
|
||||
struct sr_analog_meaning meaning;
|
||||
struct sr_analog_spec spec;
|
||||
float fvalue;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
if (!tokens[1])
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
|
||||
sr_err("Invalid float '%s'.", tokens[0]);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
analog = g_malloc0(sizeof(struct sr_datafeed_analog));
|
||||
/* TODO: Use proper 'digits' value for this device (and its modes). */
|
||||
sr_analog_init(analog, &encoding, &meaning, &spec, 2);
|
||||
analog->data = g_malloc(sizeof(float));
|
||||
analog->meaning->channels = sdi->channels;
|
||||
analog->num_samples = 1;
|
||||
*((float *)analog->data) = fvalue;
|
||||
analog->meaning->mq = 0;
|
||||
sr_analog_init(&analog, &encoding, &meaning, &spec, 2);
|
||||
analog.data = &fvalue;
|
||||
analog.meaning->channels = sdi->channels;
|
||||
analog.num_samples = 1;
|
||||
analog.meaning->mq = 0;
|
||||
|
||||
if (!strcmp(tokens[1], "VAC") || !strcmp(tokens[1], "VDC")) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
analog.meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog.meaning->unit = SR_UNIT_VOLT;
|
||||
if (!strcmp(tokens[2], "NORMAL")) {
|
||||
if (tokens[1][1] == 'A') {
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
||||
analog->meaning->mqflags |= SR_MQFLAG_RMS;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_AC;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_RMS;
|
||||
} else
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_DC;
|
||||
} else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
|
||||
*((float *)analog->data) = NAN;
|
||||
fvalue = NAN;
|
||||
} else
|
||||
analog->meaning->mq = 0;
|
||||
analog.meaning->mq = 0;
|
||||
} else if (!strcmp(tokens[1], "dBV") || !strcmp(tokens[1], "dBm")) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog.meaning->mq = SR_MQ_VOLTAGE;
|
||||
if (tokens[1][2] == 'm')
|
||||
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||
analog.meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||
else
|
||||
analog->meaning->unit = SR_UNIT_DECIBEL_VOLT;
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
analog.meaning->unit = SR_UNIT_DECIBEL_VOLT;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
} else if (!strcmp(tokens[1], "CEL") || !strcmp(tokens[1], "FAR")) {
|
||||
if (!strcmp(tokens[2], "NORMAL")) {
|
||||
analog->meaning->mq = SR_MQ_TEMPERATURE;
|
||||
analog.meaning->mq = SR_MQ_TEMPERATURE;
|
||||
if (tokens[1][0] == 'C')
|
||||
analog->meaning->unit = SR_UNIT_CELSIUS;
|
||||
analog.meaning->unit = SR_UNIT_CELSIUS;
|
||||
else
|
||||
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
analog.meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||
}
|
||||
} else if (!strcmp(tokens[1], "OHM")) {
|
||||
if (!strcmp(tokens[3], "NONE")) {
|
||||
analog->meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog->meaning->unit = SR_UNIT_OHM;
|
||||
analog.meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog.meaning->unit = SR_UNIT_OHM;
|
||||
if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
|
||||
*((float *)analog->data) = INFINITY;
|
||||
fvalue = INFINITY;
|
||||
} else if (strcmp(tokens[2], "NORMAL"))
|
||||
analog->meaning->mq = 0;
|
||||
analog.meaning->mq = 0;
|
||||
} else if (!strcmp(tokens[3], "OPEN_CIRCUIT")) {
|
||||
analog->meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog->meaning->unit = SR_UNIT_BOOLEAN;
|
||||
*((float *)analog->data) = 0.0;
|
||||
analog.meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog.meaning->unit = SR_UNIT_BOOLEAN;
|
||||
fvalue = 0.0;
|
||||
} else if (!strcmp(tokens[3], "SHORT_CIRCUIT")) {
|
||||
analog->meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog->meaning->unit = SR_UNIT_BOOLEAN;
|
||||
*((float *)analog->data) = 1.0;
|
||||
analog.meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog.meaning->unit = SR_UNIT_BOOLEAN;
|
||||
fvalue = 1.0;
|
||||
}
|
||||
} else if (!strcmp(tokens[1], "F")
|
||||
&& !strcmp(tokens[2], "NORMAL")
|
||||
&& !strcmp(tokens[3], "NONE")) {
|
||||
analog->meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog->meaning->unit = SR_UNIT_FARAD;
|
||||
analog.meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog.meaning->unit = SR_UNIT_FARAD;
|
||||
} else if (!strcmp(tokens[1], "AAC") || !strcmp(tokens[1], "ADC")) {
|
||||
analog->meaning->mq = SR_MQ_CURRENT;
|
||||
analog->meaning->unit = SR_UNIT_AMPERE;
|
||||
analog.meaning->mq = SR_MQ_CURRENT;
|
||||
analog.meaning->unit = SR_UNIT_AMPERE;
|
||||
if (!strcmp(tokens[2], "NORMAL")) {
|
||||
if (tokens[1][1] == 'A') {
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
||||
analog->meaning->mqflags |= SR_MQFLAG_RMS;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_AC;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_RMS;
|
||||
} else
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
analog.meaning->mqflags |= SR_MQFLAG_DC;
|
||||
} else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
|
||||
*((float *)analog->data) = NAN;
|
||||
fvalue = NAN;
|
||||
} else
|
||||
analog->meaning->mq = 0;
|
||||
} if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) {
|
||||
analog->meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog->meaning->unit = SR_UNIT_HERTZ;
|
||||
analog.meaning->mq = 0;
|
||||
} else if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) {
|
||||
analog.meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog.meaning->unit = SR_UNIT_HERTZ;
|
||||
} else if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) {
|
||||
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
analog->meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
analog.meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
analog.meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
} else if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) {
|
||||
analog->meaning->mq = SR_MQ_PULSE_WIDTH;
|
||||
analog->meaning->unit = SR_UNIT_SECOND;
|
||||
analog.meaning->mq = SR_MQ_PULSE_WIDTH;
|
||||
analog.meaning->unit = SR_UNIT_SECOND;
|
||||
} else if (!strcmp(tokens[1], "SIE") && !strcmp(tokens[2], "NORMAL")) {
|
||||
analog->meaning->mq = SR_MQ_CONDUCTANCE;
|
||||
analog->meaning->unit = SR_UNIT_SIEMENS;
|
||||
analog.meaning->mq = SR_MQ_CONDUCTANCE;
|
||||
analog.meaning->unit = SR_UNIT_SIEMENS;
|
||||
}
|
||||
|
||||
if (analog->meaning->mq == 0) {
|
||||
/* Not a valid measurement. */
|
||||
g_free(analog->data);
|
||||
g_free(analog);
|
||||
analog = NULL;
|
||||
if (analog.meaning->mq != 0) {
|
||||
/* Got a measurement. */
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &analog;
|
||||
sr_session_send(sdi, &packet);
|
||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||
}
|
||||
|
||||
return analog;
|
||||
}
|
||||
|
||||
static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens)
|
||||
|
@ -425,8 +424,6 @@ static void handle_line(const struct sr_dev_inst *sdi)
|
|||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_serial_dev_inst *serial;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog *analog;
|
||||
int num_tokens, n, i;
|
||||
char cmd[16], **tokens;
|
||||
|
||||
|
@ -444,15 +441,14 @@ static void handle_line(const struct sr_dev_inst *sdi)
|
|||
return;
|
||||
}
|
||||
|
||||
analog = NULL;
|
||||
tokens = g_strsplit(devc->buf, ",", 0);
|
||||
if (tokens[0]) {
|
||||
if (devc->profile->model == FLUKE_187 || devc->profile->model == FLUKE_189) {
|
||||
devc->expect_response = FALSE;
|
||||
analog = handle_qm_18x(sdi, tokens);
|
||||
handle_qm_18x(sdi, tokens);
|
||||
} else if (devc->profile->model == FLUKE_287 || devc->profile->model == FLUKE_289) {
|
||||
devc->expect_response = FALSE;
|
||||
analog = handle_qm_28x(sdi, tokens);
|
||||
handle_qm_28x(sdi, tokens);
|
||||
} else if (devc->profile->model == FLUKE_190) {
|
||||
devc->expect_response = FALSE;
|
||||
for (num_tokens = 0; tokens[num_tokens]; num_tokens++);
|
||||
|
@ -479,17 +475,6 @@ static void handle_line(const struct sr_dev_inst *sdi)
|
|||
}
|
||||
g_strfreev(tokens);
|
||||
devc->buflen = 0;
|
||||
|
||||
if (analog) {
|
||||
/* Got a measurement. */
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = analog;
|
||||
sr_session_send(sdi, &packet);
|
||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||
g_free(analog->data);
|
||||
g_free(analog);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data)
|
||||
|
|
|
@ -67,9 +67,21 @@ static const struct ftdi_chip_desc ft232r_desc = {
|
|||
}
|
||||
};
|
||||
|
||||
static const struct ftdi_chip_desc ft232h_desc = {
|
||||
.vendor = 0x0403,
|
||||
.product = 0x6014,
|
||||
.samplerate_div = 30,
|
||||
.channel_names = {
|
||||
"ADBUS0", "ADBUS1", "ADBUS2", "ADBUS3", "ADBUS4", "ADBUS5", "ADBUS6", "ADBUS7",
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ftdi_chip_desc *chip_descs[] = {
|
||||
&ft2232h_desc,
|
||||
&ft232r_desc,
|
||||
&ft232h_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void scan_device(struct ftdi_context *ftdic,
|
||||
|
@ -87,13 +99,15 @@ static void scan_device(struct ftdi_context *ftdic,
|
|||
desc = NULL;
|
||||
for (unsigned long i = 0; i < ARRAY_SIZE(chip_descs); i++) {
|
||||
desc = chip_descs[i];
|
||||
if (!desc)
|
||||
break;
|
||||
if (desc->vendor == usb_desc.idVendor &&
|
||||
desc->product == usb_desc.idProduct)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!desc) {
|
||||
sr_spew("Unsupported FTDI device 0x%4x:0x%4x.",
|
||||
sr_spew("Unsupported FTDI device 0x%04x:0x%04x.",
|
||||
usb_desc.idVendor, usb_desc.idProduct);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -157,6 +157,7 @@ static const uint64_t samplerates[] = {
|
|||
SR_MHZ(12),
|
||||
SR_MHZ(16),
|
||||
SR_MHZ(24),
|
||||
SR_MHZ(48),
|
||||
};
|
||||
|
||||
static gboolean is_plausible(const struct libusb_device_descriptor *des)
|
||||
|
|
|
@ -112,7 +112,7 @@ static int command_start_acquisition(const struct sr_dev_inst *sdi)
|
|||
sr_dbg("GPIF delay = %d, clocksource = %sMHz.", delay,
|
||||
(cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30");
|
||||
|
||||
if (delay <= 0 || delay > MAX_SAMPLE_DELAY) {
|
||||
if (delay < 0 || delay > MAX_SAMPLE_DELAY) {
|
||||
sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
|
||||
return SR_ERR;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ SR_PRIV int gpd_receive_reply(struct sr_serial_dev_inst *serial, char *buf,
|
|||
gint64 start, remaining;
|
||||
const int timeout_ms = 100;
|
||||
|
||||
if (!serial || (lines <= 0) || !buf || (buflen <= 0))
|
||||
if (!serial || !buf || (buflen <= 0))
|
||||
return SR_ERR_ARG;
|
||||
|
||||
start = g_get_monotonic_time();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
|
||||
* Copyright (C) 2018 Guido Trentalancia <guido@trentalancia.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,8 +23,6 @@
|
|||
#include "scpi.h"
|
||||
#include "protocol.h"
|
||||
|
||||
#define SERIALCOMM "115200/8n1/flow=1"
|
||||
|
||||
static struct sr_dev_driver hameg_hmo_driver_info;
|
||||
|
||||
static const char *manufacturers[] = {
|
||||
|
@ -38,6 +37,7 @@ static const uint32_t scanopts[] = {
|
|||
|
||||
static const uint32_t drvopts[] = {
|
||||
SR_CONF_OSCILLOSCOPE,
|
||||
SR_CONF_LOGIC_ANALYZER,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -151,7 +151,7 @@ static int check_channel_group(struct dev_context *devc,
|
|||
static int config_get(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
int cg_type, idx;
|
||||
int cg_type, idx, i;
|
||||
struct dev_context *devc;
|
||||
const struct scope_config *model;
|
||||
struct scope_state *state;
|
||||
|
@ -201,6 +201,15 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
case SR_CONF_TRIGGER_SLOPE:
|
||||
*data = g_variant_new_string((*model->trigger_slopes)[state->trigger_slope]);
|
||||
break;
|
||||
case SR_CONF_TRIGGER_PATTERN:
|
||||
*data = g_variant_new_string(state->trigger_pattern);
|
||||
break;
|
||||
case SR_CONF_HIGH_RESOLUTION:
|
||||
*data = g_variant_new_boolean(state->high_resolution);
|
||||
break;
|
||||
case SR_CONF_PEAK_DETECTION:
|
||||
*data = g_variant_new_boolean(state->peak_detection);
|
||||
break;
|
||||
case SR_CONF_HORIZ_TRIGGERPOS:
|
||||
*data = g_variant_new_double(state->horiz_triggerpos);
|
||||
break;
|
||||
|
@ -216,6 +225,40 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
case SR_CONF_SAMPLERATE:
|
||||
*data = g_variant_new_uint64(state->sample_rate);
|
||||
break;
|
||||
case SR_CONF_LOGIC_THRESHOLD:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
if (cg_type != CG_DIGITAL)
|
||||
return SR_ERR_NA;
|
||||
if (!model)
|
||||
return SR_ERR_ARG;
|
||||
if ((idx = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
*data = g_variant_new_string((*model->logic_threshold)[state->digital_pods[idx].threshold]);
|
||||
break;
|
||||
case SR_CONF_LOGIC_THRESHOLD_CUSTOM:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
if (cg_type != CG_DIGITAL)
|
||||
return SR_ERR_NA;
|
||||
if (!model)
|
||||
return SR_ERR_ARG;
|
||||
if ((idx = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
/* Check if the oscilloscope is currently in custom threshold mode. */
|
||||
for (i = 0; i < model->num_logic_threshold; i++) {
|
||||
if (!strcmp("USER2", (*model->logic_threshold)[i]))
|
||||
if (strcmp("USER2", (*model->logic_threshold)[state->digital_pods[idx].threshold]))
|
||||
return SR_ERR_NA;
|
||||
if (!strcmp("USER", (*model->logic_threshold)[i]))
|
||||
if (strcmp("USER", (*model->logic_threshold)[state->digital_pods[idx].threshold]))
|
||||
return SR_ERR_NA;
|
||||
if (!strcmp("MAN", (*model->logic_threshold)[i]))
|
||||
if (strcmp("MAN", (*model->logic_threshold)[state->digital_pods[idx].threshold]))
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
*data = g_variant_new_double(state->digital_pods[idx].user_threshold);
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -226,13 +269,14 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
static int config_set(uint32_t key, GVariant *data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
int ret, cg_type, idx, j;
|
||||
char command[MAX_COMMAND_SIZE], float_str[30];
|
||||
int ret, cg_type, idx, i, j;
|
||||
char command[MAX_COMMAND_SIZE], command2[MAX_COMMAND_SIZE];
|
||||
char float_str[30], *tmp_str;
|
||||
struct dev_context *devc;
|
||||
const struct scope_config *model;
|
||||
struct scope_state *state;
|
||||
double tmp_d;
|
||||
gboolean update_sample_rate;
|
||||
double tmp_d, tmp_d2;
|
||||
gboolean update_sample_rate, tmp_bool;
|
||||
|
||||
if (!sdi)
|
||||
return SR_ERR_ARG;
|
||||
|
@ -247,19 +291,14 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
update_sample_rate = FALSE;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
devc->samples_limit = g_variant_get_uint64(data);
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_LIMIT_FRAMES:
|
||||
devc->frame_limit = g_variant_get_uint64(data);
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_TRIGGER_SOURCE:
|
||||
if ((idx = std_str_idx(data, *model->trigger_sources, model->num_trigger_sources)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
state->trigger_source = idx;
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SOURCE],
|
||||
(*model->trigger_sources)[idx]);
|
||||
ret = sr_scpi_send(sdi->conn, command);
|
||||
break;
|
||||
case SR_CONF_VDIV:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
|
@ -267,52 +306,131 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
return SR_ERR_ARG;
|
||||
if ((j = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
state->analog_channels[j].vdiv = idx;
|
||||
g_ascii_formatd(float_str, sizeof(float_str), "%E",
|
||||
(float) (*model->vdivs)[idx][0] / (*model->vdivs)[idx][1]);
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_VERTICAL_DIV],
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_VERTICAL_SCALE],
|
||||
j + 1, float_str);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->analog_channels[j].vdiv = idx;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_TIMEBASE:
|
||||
if ((idx = std_u64_tuple_idx(data, *model->timebases, model->num_timebases)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
state->timebase = idx;
|
||||
g_ascii_formatd(float_str, sizeof(float_str), "%E",
|
||||
(float) (*model->timebases)[idx][0] / (*model->timebases)[idx][1]);
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_TIMEBASE],
|
||||
float_str);
|
||||
ret = sr_scpi_send(sdi->conn, command);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->timebase = idx;
|
||||
ret = SR_OK;
|
||||
update_sample_rate = TRUE;
|
||||
break;
|
||||
case SR_CONF_HORIZ_TRIGGERPOS:
|
||||
tmp_d = g_variant_get_double(data);
|
||||
if (tmp_d < 0.0 || tmp_d > 1.0)
|
||||
return SR_ERR;
|
||||
state->horiz_triggerpos = tmp_d;
|
||||
tmp_d = -(tmp_d - 0.5) *
|
||||
tmp_d2 = -(tmp_d - 0.5) *
|
||||
((double) (*model->timebases)[state->timebase][0] /
|
||||
(*model->timebases)[state->timebase][1])
|
||||
* model->num_xdivs;
|
||||
g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d);
|
||||
g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d2);
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_HORIZ_TRIGGERPOS],
|
||||
float_str);
|
||||
ret = sr_scpi_send(sdi->conn, command);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->horiz_triggerpos = tmp_d;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_TRIGGER_SOURCE:
|
||||
if ((idx = std_str_idx(data, *model->trigger_sources, model->num_trigger_sources)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SOURCE],
|
||||
(*model->trigger_sources)[idx]);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->trigger_source = idx;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_TRIGGER_SLOPE:
|
||||
if ((idx = std_str_idx(data, *model->trigger_slopes, model->num_trigger_slopes)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
state->trigger_slope = idx;
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SLOPE],
|
||||
(*model->trigger_slopes)[idx]);
|
||||
ret = sr_scpi_send(sdi->conn, command);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->trigger_slope = idx;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_TRIGGER_PATTERN:
|
||||
tmp_str = (char *)g_variant_get_string(data, 0);
|
||||
idx = strlen(tmp_str);
|
||||
if (idx == 0 || idx > model->analog_channels + model->digital_channels)
|
||||
return SR_ERR_ARG;
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_PATTERN],
|
||||
tmp_str);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
strncpy(state->trigger_pattern,
|
||||
tmp_str,
|
||||
MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT);
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_HIGH_RESOLUTION:
|
||||
tmp_bool = g_variant_get_boolean(data);
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_HIGH_RESOLUTION],
|
||||
tmp_bool ? "AUTO" : "OFF");
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
/* High Resolution mode automatically switches off Peak Detection. */
|
||||
if (tmp_bool) {
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_PEAK_DETECTION],
|
||||
"OFF");
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->peak_detection = FALSE;
|
||||
}
|
||||
state->high_resolution = tmp_bool;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_PEAK_DETECTION:
|
||||
tmp_bool = g_variant_get_boolean(data);
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_PEAK_DETECTION],
|
||||
tmp_bool ? "AUTO" : "OFF");
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
/* Peak Detection automatically switches off High Resolution mode. */
|
||||
if (tmp_bool) {
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_HIGH_RESOLUTION],
|
||||
"OFF");
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->high_resolution = FALSE;
|
||||
}
|
||||
state->peak_detection = tmp_bool;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_COUPLING:
|
||||
if (!cg)
|
||||
|
@ -321,13 +439,95 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
return SR_ERR_ARG;
|
||||
if ((j = std_cg_idx(cg, devc->analog_groups, model->analog_channels)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
state->analog_channels[j].coupling = idx;
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_COUPLING],
|
||||
j + 1, (*model->coupling_options)[idx]);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->analog_channels[j].coupling = idx;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_LOGIC_THRESHOLD:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
if (cg_type != CG_DIGITAL)
|
||||
return SR_ERR_NA;
|
||||
if (!model)
|
||||
return SR_ERR_ARG;
|
||||
if ((idx = std_str_idx(data, *model->logic_threshold, model->num_logic_threshold)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
if ((j = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
/* Check if the threshold command is based on the POD or digital channel index. */
|
||||
if (model->logic_threshold_for_pod)
|
||||
i = j + 1;
|
||||
else
|
||||
i = j * DIGITAL_CHANNELS_PER_POD;
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
|
||||
i, (*model->logic_threshold)[idx]);
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->digital_pods[j].threshold = idx;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
case SR_CONF_LOGIC_THRESHOLD_CUSTOM:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
if (cg_type != CG_DIGITAL)
|
||||
return SR_ERR_NA;
|
||||
if (!model)
|
||||
return SR_ERR_ARG;
|
||||
if ((j = std_cg_idx(cg, devc->digital_groups, model->digital_pods)) < 0)
|
||||
return SR_ERR_ARG;
|
||||
tmp_d = g_variant_get_double(data);
|
||||
if (tmp_d < -2.0 || tmp_d > 8.0)
|
||||
return SR_ERR;
|
||||
g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d);
|
||||
/* Check if the threshold command is based on the POD or digital channel index. */
|
||||
if (model->logic_threshold_for_pod)
|
||||
idx = j + 1;
|
||||
else
|
||||
idx = j * DIGITAL_CHANNELS_PER_POD;
|
||||
/* Try to support different dialects exhaustively. */
|
||||
for (i = 0; i < model->num_logic_threshold; i++) {
|
||||
if (!strcmp("USER2", (*model->logic_threshold)[i])) {
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
|
||||
idx, 2, float_str); /* USER2 */
|
||||
g_snprintf(command2, sizeof(command2),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
|
||||
idx, "USER2");
|
||||
break;
|
||||
}
|
||||
if (!strcmp("USER", (*model->logic_threshold)[i])) {
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
|
||||
idx, float_str);
|
||||
g_snprintf(command2, sizeof(command2),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
|
||||
idx, "USER");
|
||||
break;
|
||||
}
|
||||
if (!strcmp("MAN", (*model->logic_threshold)[i])) {
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_USER_THRESHOLD],
|
||||
idx, float_str);
|
||||
g_snprintf(command2, sizeof(command2),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_THRESHOLD],
|
||||
idx, "MAN");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sr_scpi_send(sdi->conn, command) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
if (sr_scpi_send(sdi->conn, command2) != SR_OK ||
|
||||
sr_scpi_get_opc(sdi->conn) != SR_OK)
|
||||
return SR_ERR;
|
||||
state->digital_pods[j].user_threshold = tmp_d;
|
||||
ret = SR_OK;
|
||||
break;
|
||||
default:
|
||||
|
@ -335,9 +535,6 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
break;
|
||||
}
|
||||
|
||||
if (ret == SR_OK)
|
||||
ret = sr_scpi_get_opc(sdi->conn);
|
||||
|
||||
if (ret == SR_OK && update_sample_rate)
|
||||
ret = hmo_update_sample_rate(sdi);
|
||||
|
||||
|
@ -371,6 +568,8 @@ static int config_list(uint32_t key, GVariant **data,
|
|||
*data = std_gvar_array_u32(ARRAY_AND_SIZE(drvopts));
|
||||
} else if (cg_type == CG_ANALOG) {
|
||||
*data = std_gvar_array_u32(*model->devopts_cg_analog, model->num_devopts_cg_analog);
|
||||
} else if (cg_type == CG_DIGITAL) {
|
||||
*data = std_gvar_array_u32(*model->devopts_cg_digital, model->num_devopts_cg_digital);
|
||||
} else {
|
||||
*data = std_gvar_array_u32(NULL, 0);
|
||||
}
|
||||
|
@ -404,6 +603,13 @@ static int config_list(uint32_t key, GVariant **data,
|
|||
return SR_ERR_ARG;
|
||||
*data = std_gvar_tuple_array(*model->vdivs, model->num_vdivs);
|
||||
break;
|
||||
case SR_CONF_LOGIC_THRESHOLD:
|
||||
if (!cg)
|
||||
return SR_ERR_CHANNEL_GROUP;
|
||||
if (!model)
|
||||
return SR_ERR_ARG;
|
||||
*data = g_variant_new_strv(*model->logic_threshold, model->num_logic_threshold);
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -437,7 +643,7 @@ SR_PRIV int hmo_request_data(const struct sr_dev_inst *sdi)
|
|||
case SR_CHANNEL_LOGIC:
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_GET_DIG_DATA],
|
||||
ch->index < 8 ? 1 : 2);
|
||||
ch->index / DIGITAL_CHANNELS_PER_POD + 1);
|
||||
break;
|
||||
default:
|
||||
sr_err("Invalid channel type.");
|
||||
|
@ -474,7 +680,7 @@ static int hmo_check_channels(GSList *channels)
|
|||
enabled_chan[idx] = TRUE;
|
||||
break;
|
||||
case SR_CHANNEL_LOGIC:
|
||||
idx = ch->index / 8;
|
||||
idx = ch->index / DIGITAL_CHANNELS_PER_POD;
|
||||
if (idx < ARRAY_SIZE(enabled_pod))
|
||||
enabled_pod[idx] = TRUE;
|
||||
break;
|
||||
|
@ -539,10 +745,10 @@ static int hmo_setup_channels(const struct sr_dev_inst *sdi)
|
|||
case SR_CHANNEL_LOGIC:
|
||||
/*
|
||||
* A digital POD needs to be enabled for every group of
|
||||
* 8 channels.
|
||||
* DIGITAL_CHANNELS_PER_POD channels.
|
||||
*/
|
||||
if (ch->enabled)
|
||||
pod_enabled[ch->index < 8 ? 0 : 1] = TRUE;
|
||||
pod_enabled[ch->index / DIGITAL_CHANNELS_PER_POD] = TRUE;
|
||||
|
||||
if (ch->enabled == state->digital_channels[ch->index])
|
||||
break;
|
||||
|
@ -566,7 +772,7 @@ static int hmo_setup_channels(const struct sr_dev_inst *sdi)
|
|||
|
||||
ret = SR_OK;
|
||||
for (i = 0; i < model->digital_pods; i++) {
|
||||
if (state->digital_pods[i] == pod_enabled[i])
|
||||
if (state->digital_pods[i].state == pod_enabled[i])
|
||||
continue;
|
||||
g_snprintf(command, sizeof(command),
|
||||
(*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_STATE],
|
||||
|
@ -575,7 +781,7 @@ static int hmo_setup_channels(const struct sr_dev_inst *sdi)
|
|||
ret = SR_ERR;
|
||||
break;
|
||||
}
|
||||
state->digital_pods[i] = pod_enabled[i];
|
||||
state->digital_pods[i].state = pod_enabled[i];
|
||||
setup_changed = TRUE;
|
||||
}
|
||||
g_free(pod_enabled);
|
||||
|
@ -601,6 +807,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
scpi = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
devc->num_samples = 0;
|
||||
devc->num_frames = 0;
|
||||
|
||||
/* Preset empty results. */
|
||||
for (group = 0; group < ARRAY_SIZE(digital_added); group++)
|
||||
digital_added[group] = FALSE;
|
||||
|
@ -617,7 +826,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
if (!ch->enabled)
|
||||
continue;
|
||||
/* Only add a single digital channel per group (pod). */
|
||||
group = ch->index / 8;
|
||||
group = ch->index / DIGITAL_CHANNELS_PER_POD;
|
||||
if (ch->type != SR_CHANNEL_LOGIC || !digital_added[group]) {
|
||||
devc->enabled_channels = g_slist_append(
|
||||
devc->enabled_channels, ch);
|
||||
|
@ -681,6 +890,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
|
||||
devc = sdi->priv;
|
||||
|
||||
devc->num_samples = 0;
|
||||
devc->num_frames = 0;
|
||||
g_slist_free(devc->enabled_channels);
|
||||
devc->enabled_channels = NULL;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,17 +28,19 @@
|
|||
|
||||
#define LOG_PREFIX "hameg-hmo"
|
||||
|
||||
#define MAX_INSTRUMENT_VERSIONS 10
|
||||
#define MAX_COMMAND_SIZE 48
|
||||
#define MAX_ANALOG_CHANNEL_COUNT 4
|
||||
#define MAX_DIGITAL_CHANNEL_COUNT 16
|
||||
#define MAX_DIGITAL_GROUP_COUNT 2
|
||||
#define DIGITAL_CHANNELS_PER_POD 8
|
||||
|
||||
#define MAX_INSTRUMENT_VERSIONS 10
|
||||
#define MAX_COMMAND_SIZE 128
|
||||
#define MAX_ANALOG_CHANNEL_COUNT 4
|
||||
#define MAX_DIGITAL_CHANNEL_COUNT 16
|
||||
#define MAX_DIGITAL_GROUP_COUNT 2
|
||||
|
||||
struct scope_config {
|
||||
const char *name[MAX_INSTRUMENT_VERSIONS];
|
||||
const uint8_t analog_channels;
|
||||
const uint8_t digital_channels;
|
||||
const uint8_t digital_pods;
|
||||
uint8_t digital_pods;
|
||||
|
||||
const char *(*analog_names)[];
|
||||
const char *(*digital_names)[];
|
||||
|
@ -49,9 +51,16 @@ struct scope_config {
|
|||
const uint32_t (*devopts_cg_analog)[];
|
||||
const uint8_t num_devopts_cg_analog;
|
||||
|
||||
const uint32_t (*devopts_cg_digital)[];
|
||||
const uint8_t num_devopts_cg_digital;
|
||||
|
||||
const char *(*coupling_options)[];
|
||||
const uint8_t num_coupling_options;
|
||||
|
||||
const char *(*logic_threshold)[];
|
||||
const uint8_t num_logic_threshold;
|
||||
const gboolean logic_threshold_for_pod;
|
||||
|
||||
const char *(*trigger_sources)[];
|
||||
const uint8_t num_trigger_sources;
|
||||
|
||||
|
@ -64,8 +73,8 @@ struct scope_config {
|
|||
const uint64_t (*vdivs)[][2];
|
||||
const uint8_t num_vdivs;
|
||||
|
||||
const uint8_t num_xdivs;
|
||||
const uint8_t num_ydivs;
|
||||
unsigned int num_xdivs;
|
||||
const unsigned int num_ydivs;
|
||||
|
||||
const char *(*scpi_dialect)[];
|
||||
};
|
||||
|
@ -80,16 +89,28 @@ struct analog_channel_state {
|
|||
char probe_unit;
|
||||
};
|
||||
|
||||
struct digital_pod_state {
|
||||
gboolean state;
|
||||
|
||||
int threshold;
|
||||
float user_threshold;
|
||||
};
|
||||
|
||||
struct scope_state {
|
||||
struct analog_channel_state *analog_channels;
|
||||
gboolean *digital_channels;
|
||||
gboolean *digital_pods;
|
||||
struct digital_pod_state *digital_pods;
|
||||
|
||||
int timebase;
|
||||
float horiz_triggerpos;
|
||||
|
||||
int trigger_source;
|
||||
int trigger_slope;
|
||||
char trigger_pattern[MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT + 1];
|
||||
|
||||
gboolean high_resolution;
|
||||
gboolean peak_detection;
|
||||
|
||||
uint64_t sample_rate;
|
||||
};
|
||||
|
||||
|
@ -102,8 +123,10 @@ struct dev_context {
|
|||
|
||||
GSList *enabled_channels;
|
||||
GSList *current_channel;
|
||||
uint64_t num_samples;
|
||||
uint64_t num_frames;
|
||||
|
||||
uint64_t samples_limit;
|
||||
uint64_t frame_limit;
|
||||
|
||||
size_t pod_count;
|
||||
|
|
|
@ -167,7 +167,7 @@ static const uint64_t samplerates_hw[] = {
|
|||
SR_MHZ(320),
|
||||
};
|
||||
|
||||
SR_PRIV struct sr_dev_driver hantek_4032l_driver_info;
|
||||
static struct sr_dev_driver hantek_4032l_driver_info;
|
||||
|
||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||
{
|
||||
|
@ -515,7 +515,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
else
|
||||
cmd_pkt->sample_rate = devc->sample_rate;
|
||||
|
||||
/* Set pwm channel values. */
|
||||
/* Set PWM channel values. */
|
||||
devc->cmd_pkt.pwm_a = h4032l_voltage2pwm(devc->cur_threshold[0]);
|
||||
devc->cmd_pkt.pwm_b = h4032l_voltage2pwm(devc->cur_threshold[1]);
|
||||
|
||||
|
@ -587,25 +587,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
channel = channel->next;
|
||||
}
|
||||
|
||||
/* Compress range mask value and apply range settings. */
|
||||
if (range_mask) {
|
||||
cmd_pkt->trigger[0].flags.data_range_enabled = 1;
|
||||
cmd_pkt->trigger[0].data_range_mask |= (range_mask);
|
||||
|
||||
uint32_t new_range_value = 0;
|
||||
uint32_t bit_mask = 1;
|
||||
while (range_mask) {
|
||||
if ((range_mask & 1) != 0) {
|
||||
new_range_value <<= 1;
|
||||
if ((range_value & 1) != 0)
|
||||
new_range_value |= bit_mask;
|
||||
bit_mask <<= 1;
|
||||
}
|
||||
range_mask >>= 1;
|
||||
range_value >>= 1;
|
||||
}
|
||||
cmd_pkt->trigger[0].data_range_max |= range_value;
|
||||
}
|
||||
cmd_pkt->trigger[0].flags.data_range_enabled = 1;
|
||||
cmd_pkt->trigger[0].data_range_mask |= range_mask;
|
||||
cmd_pkt->trigger[0].data_range_max = range_value;
|
||||
}
|
||||
|
||||
usb_source_add(sdi->session, drvc->sr_ctx, 1000,
|
||||
|
@ -621,7 +605,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
return h4032l_stop(sdi);
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_dev_driver hantek_4032l_driver_info = {
|
||||
static struct sr_dev_driver hantek_4032l_driver_info = {
|
||||
.name = "hantek-4032l",
|
||||
.longname = "Hantek 4032L",
|
||||
.api_version = 1,
|
||||
|
|
|
@ -132,7 +132,7 @@ static void send_data(struct sr_dev_inst *sdi,
|
|||
sr_session_send(sdi, &trig);
|
||||
|
||||
/* Send rest of data. */
|
||||
logic.length = (sample_count-trigger_offset) * sizeof(uint32_t);
|
||||
logic.length = (sample_count - trigger_offset) * sizeof(uint32_t);
|
||||
logic.data = data + trigger_offset;
|
||||
if (logic.length)
|
||||
sr_session_send(sdi, &packet);
|
||||
|
|
|
@ -89,6 +89,11 @@ static const struct hantek_6xxx_profile dev_profiles[] = {
|
|||
"Hantek", "6022BL", "fx2lafw-hantek-6022bl.fw",
|
||||
ARRAY_AND_SIZE(dc_coupling), FALSE,
|
||||
},
|
||||
{
|
||||
0xd4a2, 0x5660, 0x1d50, 0x608e, 0x0004,
|
||||
"YiXingDianZi", "MDSO", "fx2lafw-yixingdianzi-mdso.fw",
|
||||
ARRAY_AND_SIZE(dc_coupling), FALSE,
|
||||
},
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ static const uint32_t devopts[] = {
|
|||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_MEASURED_QUANTITY | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_RANGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_DIGITS | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -41,20 +43,71 @@ static const struct {
|
|||
enum sr_mqflag mqflag;
|
||||
} mqopts[] = {
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC | SR_MQFLAG_AUTORANGE},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC | SR_MQFLAG_RMS},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC | SR_MQFLAG_RMS | SR_MQFLAG_AUTORANGE},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_DC},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_DC | SR_MQFLAG_AUTORANGE},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_AC | SR_MQFLAG_RMS},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_AC | SR_MQFLAG_RMS | SR_MQFLAG_AUTORANGE},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_AC},
|
||||
{SR_MQ_RESISTANCE, 0},
|
||||
{SR_MQ_RESISTANCE, 0 | SR_MQFLAG_AUTORANGE},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE | SR_MQFLAG_AUTORANGE},
|
||||
};
|
||||
|
||||
SR_PRIV struct sr_dev_driver hp_3478a_driver_info;
|
||||
static const struct {
|
||||
enum sr_mq mq;
|
||||
enum sr_mqflag mqflag;
|
||||
int range_exp;
|
||||
const char *range_str;
|
||||
} rangeopts[] = {
|
||||
/* -99 is a dummy exponent for auto ranging. */
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC, -99, "Auto"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC, -2, "30mV"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC, -1, "300mV"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC, 0, "3V"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC, 1, "30V"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_DC, 2, "300V"},
|
||||
/* -99 is a dummy exponent for auto ranging. */
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC, -99, "Auto"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC, -1, "300mV"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC, 0, "3V"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC, 1, "30V"},
|
||||
{SR_MQ_VOLTAGE, SR_MQFLAG_AC, 2, "300V"},
|
||||
/* -99 is a dummy exponent for auto ranging. */
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_DC, -99, "Auto"},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_DC, -1, "300mV"},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_DC, 0, "3V"},
|
||||
/* -99 is a dummy exponent for auto ranging. */
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_AC, -99, "Auto"},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_AC, -1, "300mV"},
|
||||
{SR_MQ_CURRENT, SR_MQFLAG_AC, 0, "3V"},
|
||||
/* -99 is a dummy exponent for auto ranging. */
|
||||
{SR_MQ_RESISTANCE, 0, -99, "Auto"},
|
||||
{SR_MQ_RESISTANCE, 0, 1, "30"},
|
||||
{SR_MQ_RESISTANCE, 0, 2, "300"},
|
||||
{SR_MQ_RESISTANCE, 0, 3, "3k"},
|
||||
{SR_MQ_RESISTANCE, 0, 4, "30k"},
|
||||
{SR_MQ_RESISTANCE, 0, 5, "300k"},
|
||||
{SR_MQ_RESISTANCE, 0, 6, "3M"},
|
||||
{SR_MQ_RESISTANCE, 0, 7, "30M"},
|
||||
/* -99 is a dummy exponent for auto ranging. */
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, -99, "Auto"},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, 1, "30R"},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, 2, "300R"},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, 3, "3kR"},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, 4, "30kR"},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, 5, "300kR"},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, 6, "3MR"},
|
||||
{SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, 7, "30MR"},
|
||||
};
|
||||
|
||||
/** Available digits as strings. */
|
||||
static const char *digits[] = {
|
||||
"3.5", "4.5", "5.5",
|
||||
};
|
||||
|
||||
/** Mapping between devc->spec_digits and digits string. */
|
||||
static const char *digits_map[] = {
|
||||
"", "", "", "", "3.5", "4.5", "5.5",
|
||||
};
|
||||
|
||||
static struct sr_dev_driver hp_3478a_driver_info;
|
||||
|
||||
static int create_front_channel(struct sr_dev_inst *sdi, int chan_idx)
|
||||
{
|
||||
|
@ -118,6 +171,8 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
struct dev_context *devc;
|
||||
int ret;
|
||||
GVariant *arr[2];
|
||||
unsigned int i;
|
||||
const char *range_str;
|
||||
|
||||
(void)cg;
|
||||
|
||||
|
@ -135,6 +190,27 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
arr[1] = g_variant_new_uint64(devc->measurement_mq_flags);
|
||||
*data = g_variant_new_tuple(arr, 2);
|
||||
break;
|
||||
case SR_CONF_RANGE:
|
||||
ret = hp_3478a_get_status_bytes(sdi);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
range_str = "Auto";
|
||||
for (i = 0; i < ARRAY_SIZE(rangeopts); i++) {
|
||||
if (rangeopts[i].mq == devc->measurement_mq &&
|
||||
rangeopts[i].mqflag == devc->measurement_mq_flags &&
|
||||
rangeopts[i].range_exp == devc->range_exp) {
|
||||
range_str = rangeopts[i].range_str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*data = g_variant_new_string(range_str);
|
||||
break;
|
||||
case SR_CONF_DIGITS:
|
||||
ret = hp_3478a_get_status_bytes(sdi);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
*data = g_variant_new_string(digits_map[devc->spec_digits]);
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -149,6 +225,9 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
enum sr_mq mq;
|
||||
enum sr_mqflag mq_flags;
|
||||
GVariant *tuple_child;
|
||||
unsigned int i;
|
||||
const char *range_str;
|
||||
const char *digits_str;
|
||||
|
||||
(void)cg;
|
||||
|
||||
|
@ -165,6 +244,23 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
mq_flags = g_variant_get_uint64(tuple_child);
|
||||
g_variant_unref(tuple_child);
|
||||
return hp_3478a_set_mq(sdi, mq, mq_flags);
|
||||
case SR_CONF_RANGE:
|
||||
range_str = g_variant_get_string(data, NULL);
|
||||
for (i = 0; i < ARRAY_SIZE(rangeopts); i++) {
|
||||
if (rangeopts[i].mq == devc->measurement_mq &&
|
||||
rangeopts[i].mqflag == devc->measurement_mq_flags &&
|
||||
g_strcmp0(rangeopts[i].range_str, range_str) == 0) {
|
||||
return hp_3478a_set_range(sdi, rangeopts[i].range_exp);
|
||||
}
|
||||
}
|
||||
return SR_ERR_NA;
|
||||
case SR_CONF_DIGITS:
|
||||
digits_str = g_variant_get_string(data, NULL);
|
||||
for (i = 0; i < ARRAY_SIZE(rangeopts); i++) {
|
||||
if (g_strcmp0(digits_map[i], digits_str) == 0)
|
||||
return hp_3478a_set_digits(sdi, i);
|
||||
}
|
||||
return SR_ERR_NA;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -175,10 +271,14 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
static int config_list(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
int ret;
|
||||
unsigned int i;
|
||||
GVariant *gvar, *arr[2];
|
||||
GVariantBuilder gvb;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_SCAN_OPTIONS:
|
||||
case SR_CONF_DEVICE_OPTIONS:
|
||||
|
@ -197,6 +297,22 @@ static int config_list(uint32_t key, GVariant **data,
|
|||
}
|
||||
*data = g_variant_builder_end(&gvb);
|
||||
break;
|
||||
case SR_CONF_RANGE:
|
||||
ret = hp_3478a_get_status_bytes(sdi);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
||||
for (i = 0; i < ARRAY_SIZE(rangeopts); i++) {
|
||||
if (rangeopts[i].mq == devc->measurement_mq &&
|
||||
rangeopts[i].mqflag == devc->measurement_mq_flags) {
|
||||
g_variant_builder_add(&gvb, "s", rangeopts[i].range_str);
|
||||
}
|
||||
}
|
||||
*data = g_variant_builder_end(&gvb);
|
||||
break;
|
||||
case SR_CONF_DIGITS:
|
||||
*data = g_variant_new_strv(ARRAY_AND_SIZE(digits));
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -219,7 +335,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
* NOTE: For faster readings, there are some things one can do:
|
||||
* - Turn off the display: sr_scpi_send(scpi, "D3SIGROK").
|
||||
* - Set the line frequency to 60Hz via switch (back of the unit).
|
||||
* - Set to 3.5 digits measurement (add config key SR_CONF_DIGITS).
|
||||
* - Set to 3.5 digits measurement.
|
||||
*/
|
||||
|
||||
/* Set to internal trigger. */
|
||||
|
@ -248,7 +364,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_dev_driver hp_3478a_driver_info = {
|
||||
static struct sr_dev_driver hp_3478a_driver_info = {
|
||||
.name = "hp-3478a",
|
||||
.longname = "HP 3478A",
|
||||
.api_version = 1,
|
||||
|
@ -266,5 +382,4 @@ SR_PRIV struct sr_dev_driver hp_3478a_driver_info = {
|
|||
.dev_acquisition_stop = dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
|
||||
SR_REGISTER_DEV_DRIVER(hp_3478a_driver_info);
|
||||
|
|
|
@ -89,19 +89,63 @@ SR_PRIV int hp_3478a_set_mq(const struct sr_dev_inst *sdi, enum sr_mq mq,
|
|||
return SR_ERR_NA;
|
||||
}
|
||||
|
||||
SR_PRIV int hp_3478a_set_range(const struct sr_dev_inst *sdi, int range_exp)
|
||||
{
|
||||
int ret;
|
||||
struct sr_scpi_dev_inst *scpi = sdi->conn;
|
||||
struct dev_context *devc = sdi->priv;
|
||||
|
||||
/* No need to send command if we're not changing the range. */
|
||||
if (devc->range_exp == range_exp)
|
||||
return SR_OK;
|
||||
|
||||
/* -99 is a dummy exponent for auto ranging. */
|
||||
if (range_exp == -99)
|
||||
ret = sr_scpi_send(scpi, "RA");
|
||||
else
|
||||
ret = sr_scpi_send(scpi, "R%i", range_exp);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
return hp_3478a_get_status_bytes(sdi);
|
||||
}
|
||||
|
||||
SR_PRIV int hp_3478a_set_digits(const struct sr_dev_inst *sdi, uint8_t digits)
|
||||
{
|
||||
int ret;
|
||||
struct sr_scpi_dev_inst *scpi = sdi->conn;
|
||||
struct dev_context *devc = sdi->priv;
|
||||
|
||||
/* No need to send command if we're not changing the range. */
|
||||
if (devc->spec_digits == digits)
|
||||
return SR_OK;
|
||||
|
||||
/* digits are based on devc->spec_digits, so we have to substract 1 */
|
||||
ret = sr_scpi_send(scpi, "N%i", digits-1);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
return hp_3478a_get_status_bytes(sdi);
|
||||
}
|
||||
|
||||
static int parse_range_vdc(struct dev_context *devc, uint8_t range_byte)
|
||||
{
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_30MV)
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_30MV) {
|
||||
devc->range_exp = -2;
|
||||
devc->enc_digits = devc->spec_digits - 2;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_300MV)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_300MV) {
|
||||
devc->range_exp = -1;
|
||||
devc->enc_digits = devc->spec_digits - 3;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_3V)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_3V) {
|
||||
devc->range_exp = 0;
|
||||
devc->enc_digits = devc->spec_digits - 1;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_30V)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_30V) {
|
||||
devc->range_exp = 1;
|
||||
devc->enc_digits = devc->spec_digits - 2;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_300V)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VDC_300V) {
|
||||
devc->range_exp = 2;
|
||||
devc->enc_digits = devc->spec_digits - 3;
|
||||
else
|
||||
} else
|
||||
return SR_ERR_DATA;
|
||||
|
||||
return SR_OK;
|
||||
|
@ -109,15 +153,19 @@ static int parse_range_vdc(struct dev_context *devc, uint8_t range_byte)
|
|||
|
||||
static int parse_range_vac(struct dev_context *devc, uint8_t range_byte)
|
||||
{
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_300MV)
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_300MV) {
|
||||
devc->range_exp = -1;
|
||||
devc->enc_digits = devc->spec_digits - 3;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_3V)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_3V) {
|
||||
devc->range_exp = 0;
|
||||
devc->enc_digits = devc->spec_digits - 1;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_30V)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_30V) {
|
||||
devc->range_exp = 1;
|
||||
devc->enc_digits = devc->spec_digits - 2;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_300V)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_VAC_300V) {
|
||||
devc->range_exp = 2;
|
||||
devc->enc_digits = devc->spec_digits - 3;
|
||||
else
|
||||
} else
|
||||
return SR_ERR_DATA;
|
||||
|
||||
return SR_OK;
|
||||
|
@ -125,11 +173,13 @@ static int parse_range_vac(struct dev_context *devc, uint8_t range_byte)
|
|||
|
||||
static int parse_range_a(struct dev_context *devc, uint8_t range_byte)
|
||||
{
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_A_300MA)
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_A_300MA) {
|
||||
devc->range_exp = -1;
|
||||
devc->enc_digits = devc->spec_digits - 3;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_A_3A)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_A_3A) {
|
||||
devc->range_exp = 0;
|
||||
devc->enc_digits = devc->spec_digits - 1;
|
||||
else
|
||||
} else
|
||||
return SR_ERR_DATA;
|
||||
|
||||
return SR_OK;
|
||||
|
@ -137,21 +187,28 @@ static int parse_range_a(struct dev_context *devc, uint8_t range_byte)
|
|||
|
||||
static int parse_range_ohm(struct dev_context *devc, uint8_t range_byte)
|
||||
{
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_30R)
|
||||
if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_30R) {
|
||||
devc->range_exp = 1;
|
||||
devc->enc_digits = devc->spec_digits - 2;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_300R)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_300R) {
|
||||
devc->range_exp = 2;
|
||||
devc->enc_digits = devc->spec_digits - 3;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_3KR)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_3KR) {
|
||||
devc->range_exp = 3;
|
||||
devc->enc_digits = devc->spec_digits - 1;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_30KR)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_30KR) {
|
||||
devc->range_exp = 4;
|
||||
devc->enc_digits = devc->spec_digits - 2;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_300KR)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_300KR) {
|
||||
devc->range_exp = 5;
|
||||
devc->enc_digits = devc->spec_digits - 3;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_3MR)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_3MR) {
|
||||
devc->range_exp = 6;
|
||||
devc->enc_digits = devc->spec_digits - 1;
|
||||
else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_30MR)
|
||||
} else if ((range_byte & SB1_RANGE_BLOCK) == RANGE_OHM_30MR) {
|
||||
devc->range_exp = 7;
|
||||
devc->enc_digits = devc->spec_digits - 2;
|
||||
else
|
||||
} else
|
||||
return SR_ERR_DATA;
|
||||
|
||||
return SR_OK;
|
||||
|
@ -171,14 +228,17 @@ static int parse_function_byte(struct dev_context *devc, uint8_t function_byte)
|
|||
|
||||
/* Function + Range */
|
||||
devc->measurement_mq_flags = 0;
|
||||
devc->acquisition_mq_flags = 0;
|
||||
if ((function_byte & SB1_FUNCTION_BLOCK) == FUNCTION_VDC) {
|
||||
devc->measurement_mq = SR_MQ_VOLTAGE;
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_DC;
|
||||
devc->acquisition_mq_flags |= SR_MQFLAG_DC;
|
||||
devc->measurement_unit = SR_UNIT_VOLT;
|
||||
parse_range_vdc(devc, function_byte);
|
||||
} else if ((function_byte & SB1_FUNCTION_BLOCK) == FUNCTION_VAC) {
|
||||
devc->measurement_mq = SR_MQ_VOLTAGE;
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_AC;
|
||||
devc->acquisition_mq_flags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
devc->measurement_unit = SR_UNIT_VOLT;
|
||||
parse_range_vac(devc, function_byte);
|
||||
} else if ((function_byte & SB1_FUNCTION_BLOCK) == FUNCTION_2WR) {
|
||||
|
@ -188,16 +248,19 @@ static int parse_function_byte(struct dev_context *devc, uint8_t function_byte)
|
|||
} else if ((function_byte & SB1_FUNCTION_BLOCK) == FUNCTION_4WR) {
|
||||
devc->measurement_mq = SR_MQ_RESISTANCE;
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_FOUR_WIRE;
|
||||
devc->acquisition_mq_flags |= SR_MQFLAG_FOUR_WIRE;
|
||||
devc->measurement_unit = SR_UNIT_OHM;
|
||||
parse_range_ohm(devc, function_byte);
|
||||
} else if ((function_byte & SB1_FUNCTION_BLOCK) == FUNCTION_ADC) {
|
||||
devc->measurement_mq = SR_MQ_CURRENT;
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_DC;
|
||||
devc->acquisition_mq_flags |= SR_MQFLAG_DC;
|
||||
devc->measurement_unit = SR_UNIT_AMPERE;
|
||||
parse_range_a(devc, function_byte);
|
||||
} else if ((function_byte & SB1_FUNCTION_BLOCK) == FUNCTION_AAC) {
|
||||
devc->measurement_mq = SR_MQ_CURRENT;
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_AC;
|
||||
devc->acquisition_mq_flags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
|
||||
devc->measurement_unit = SR_UNIT_AMPERE;
|
||||
parse_range_a(devc, function_byte);
|
||||
} else if ((function_byte & SB1_FUNCTION_BLOCK) == FUNCTION_EXR) {
|
||||
|
@ -242,10 +305,11 @@ static int parse_status_byte(struct dev_context *devc, uint8_t status_byte)
|
|||
devc->auto_zero = FALSE;
|
||||
|
||||
/* Auto-Range */
|
||||
if ((status_byte & STATUS_AUTO_RANGE) == STATUS_AUTO_RANGE)
|
||||
devc->measurement_mq_flags |= SR_MQFLAG_AUTORANGE;
|
||||
else
|
||||
devc->measurement_mq_flags &= ~SR_MQFLAG_AUTORANGE;
|
||||
if ((status_byte & STATUS_AUTO_RANGE) == STATUS_AUTO_RANGE) {
|
||||
devc->acquisition_mq_flags |= SR_MQFLAG_AUTORANGE;
|
||||
devc->range_exp = -99;
|
||||
} else
|
||||
devc->acquisition_mq_flags &= ~SR_MQFLAG_AUTORANGE;
|
||||
|
||||
/* Internal trigger */
|
||||
if ((status_byte & STATUS_INT_TRIGGER) == STATUS_INT_TRIGGER)
|
||||
|
@ -392,7 +456,7 @@ static void acq_send_measurement(struct sr_dev_inst *sdi)
|
|||
encoding.digits = devc->enc_digits;
|
||||
|
||||
meaning.mq = devc->measurement_mq;
|
||||
meaning.mqflags = devc->measurement_mq_flags;
|
||||
meaning.mqflags = devc->acquisition_mq_flags;
|
||||
meaning.unit = devc->measurement_unit;
|
||||
meaning.channels = sdi->channels;
|
||||
|
||||
|
@ -406,6 +470,7 @@ SR_PRIV int hp_3478a_receive_data(int fd, int revents, void *cb_data)
|
|||
struct sr_scpi_dev_inst *scpi;
|
||||
struct sr_dev_inst *sdi;
|
||||
struct dev_context *devc;
|
||||
char status_register;
|
||||
|
||||
(void)fd;
|
||||
(void)revents;
|
||||
|
@ -416,18 +481,32 @@ SR_PRIV int hp_3478a_receive_data(int fd, int revents, void *cb_data)
|
|||
scpi = sdi->conn;
|
||||
|
||||
/*
|
||||
* This is necessary to get the actual range for the encoding digits.
|
||||
* When SPoll is implemmented, this can be done via SPoll.
|
||||
* TODO: Wait for SRQ from the DMM when a new measurement is available.
|
||||
* For now, we don't wait for a SRQ, but just do a SPoll and
|
||||
* check the Data Ready bit (0x01).
|
||||
* This is necessary, because (1) reading a value will block the
|
||||
* bus until a measurement is available and (2) when switching
|
||||
* ranges, there could be a timeout.
|
||||
*/
|
||||
if (hp_3478a_get_status_bytes(sdi) != SR_OK)
|
||||
if (sr_scpi_gpib_spoll(scpi, &status_register) != SR_OK)
|
||||
return FALSE;
|
||||
if (!(((uint8_t)status_register) & 0x01))
|
||||
return TRUE;
|
||||
|
||||
/* Get a reading from the DMM. */
|
||||
if (sr_scpi_get_double(scpi, NULL, &devc->measurement) != SR_OK)
|
||||
return FALSE;
|
||||
|
||||
/* Check for overflow. */
|
||||
if (devc->measurement >= 9.998e+9)
|
||||
devc->measurement = INFINITY;
|
||||
|
||||
/*
|
||||
* TODO: Implement GPIB-SPoll, to get notified by a SRQ when a new
|
||||
* measurement is available. This is necessary, because when
|
||||
* switching ranges, there could be a timeout.
|
||||
* This is necessary to get the actual range for the encoding digits.
|
||||
* Must be called after reading the value, because it resets the
|
||||
* status register!
|
||||
*/
|
||||
if (sr_scpi_get_double(scpi, NULL, &devc->measurement) != SR_OK)
|
||||
if (hp_3478a_get_status_bytes(sdi) != SR_OK)
|
||||
return FALSE;
|
||||
|
||||
acq_send_measurement(sdi);
|
||||
|
|
|
@ -138,8 +138,12 @@ struct dev_context {
|
|||
|
||||
double measurement;
|
||||
enum sr_mq measurement_mq;
|
||||
/** The measurement mq flags only contain flags for AC, DC and 4-wire. */
|
||||
enum sr_mqflag measurement_mq_flags;
|
||||
/** The acquisition mq flags also contain flags for autoranging and RMS. */
|
||||
enum sr_mqflag acquisition_mq_flags;
|
||||
enum sr_unit measurement_unit;
|
||||
int range_exp;
|
||||
uint8_t enc_digits;
|
||||
uint8_t spec_digits;
|
||||
|
||||
|
@ -157,6 +161,8 @@ struct channel_context {
|
|||
|
||||
SR_PRIV int hp_3478a_set_mq(const struct sr_dev_inst *sdi, enum sr_mq mq,
|
||||
enum sr_mqflag mq_flags);
|
||||
SR_PRIV int hp_3478a_set_range(const struct sr_dev_inst *sdi, int range_exp);
|
||||
SR_PRIV int hp_3478a_set_digits(const struct sr_dev_inst *sdi, uint8_t digits);
|
||||
SR_PRIV int hp_3478a_get_status_bytes(const struct sr_dev_inst *sdi);
|
||||
SR_PRIV int hp_3478a_receive_data(int fd, int revents, void *cb_data);
|
||||
|
||||
|
|
|
@ -42,8 +42,6 @@ static const int32_t trigger_matches[] = {
|
|||
SR_TRIGGER_EDGE,
|
||||
};
|
||||
|
||||
SR_PRIV struct sr_dev_driver ipdbg_la_driver_info;
|
||||
|
||||
static void ipdbg_la_split_addr_port(const char *conn, char **addr,
|
||||
char **port)
|
||||
{
|
||||
|
@ -209,7 +207,11 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
devc->capture_ratio = g_variant_get_uint64(data);
|
||||
break;
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
devc->limit_samples = g_variant_get_uint64(data);
|
||||
{
|
||||
uint64_t limit_samples = g_variant_get_uint64(data);
|
||||
if (limit_samples <= devc->limit_samples_max)
|
||||
devc->limit_samples = limit_samples;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
|
@ -260,13 +262,15 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
struct ipdbg_la_tcp *tcp = sdi->conn;
|
||||
struct dev_context *devc = sdi->priv;
|
||||
|
||||
uint8_t byte;
|
||||
const size_t bufsize = 1024;
|
||||
uint8_t buffer[bufsize];
|
||||
|
||||
if (devc->num_transfers > 0) {
|
||||
while (devc->num_transfers <
|
||||
(devc->limit_samples_max * devc->data_width_bytes)) {
|
||||
ipdbg_la_tcp_receive(tcp, &byte);
|
||||
devc->num_transfers++;
|
||||
int recd = ipdbg_la_tcp_receive(tcp, buffer, bufsize);
|
||||
if (recd > 0)
|
||||
devc->num_transfers += recd;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +280,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_dev_driver ipdbg_la_driver_info = {
|
||||
static struct sr_dev_driver ipdbg_la_driver_info = {
|
||||
.name = "ipdbg-la",
|
||||
.longname = "IPDBG LA",
|
||||
.api_version = 1,
|
||||
|
@ -294,5 +298,4 @@ SR_PRIV struct sr_dev_driver ipdbg_la_driver_info = {
|
|||
.dev_acquisition_stop = dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
|
||||
SR_REGISTER_DEV_DRIVER(ipdbg_la_driver_info);
|
||||
|
|
|
@ -67,18 +67,15 @@ static gboolean data_available(struct ipdbg_la_tcp *tcp)
|
|||
{
|
||||
#ifdef _WIN32
|
||||
u_long bytes_available;
|
||||
ioctlsocket(tcp->socket, FIONREAD, &bytes_available);
|
||||
return (bytes_available > 0);
|
||||
if (ioctlsocket(tcp->socket, FIONREAD, &bytes_available) != 0) {
|
||||
#else
|
||||
int status;
|
||||
|
||||
if (ioctl(tcp->socket, FIONREAD, &status) < 0) { // TIOCMGET
|
||||
int bytes_available;
|
||||
if (ioctl(tcp->socket, FIONREAD, &bytes_available) < 0) { /* TIOCMGET */
|
||||
#endif
|
||||
sr_err("FIONREAD failed: %s\n", g_strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (status < 1) ? FALSE : TRUE;
|
||||
#endif
|
||||
return (bytes_available > 0);
|
||||
}
|
||||
|
||||
SR_PRIV struct ipdbg_la_tcp *ipdbg_la_tcp_new(void)
|
||||
|
@ -145,6 +142,14 @@ SR_PRIV int ipdbg_la_tcp_close(struct ipdbg_la_tcp *tcp)
|
|||
{
|
||||
int ret = SR_OK;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (shutdown(tcp->socket, SD_SEND) != SOCKET_ERROR) {
|
||||
char recvbuf[16];
|
||||
int recvbuflen = 16;
|
||||
/* Receive until the peer closes the connection. */
|
||||
while (recv(tcp->socket, recvbuf, recvbuflen, 0) > 0);
|
||||
}
|
||||
#endif
|
||||
if (close(tcp->socket) < 0)
|
||||
ret = SR_ERR;
|
||||
|
||||
|
@ -175,14 +180,16 @@ static int tcp_receive_blocking(struct ipdbg_la_tcp *tcp,
|
|||
int received = 0;
|
||||
int error_count = 0;
|
||||
|
||||
/* Timeout after 500ms of not receiving data */
|
||||
while ((received < bufsize) && (error_count < 500)) {
|
||||
if (ipdbg_la_tcp_receive(tcp, buf) > 0) {
|
||||
buf++;
|
||||
received++;
|
||||
/* Timeout after 2s of not receiving data. */
|
||||
/* Increase timeout in case lab is not just beside the office. */
|
||||
while ((received < bufsize) && (error_count < 2000)) {
|
||||
int recd = ipdbg_la_tcp_receive(tcp, buf, bufsize - received);
|
||||
if (recd > 0) {
|
||||
buf += recd;
|
||||
received += recd;
|
||||
} else {
|
||||
error_count++;
|
||||
g_usleep(1000); /* Sleep for 1ms */
|
||||
g_usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,24 +197,16 @@ static int tcp_receive_blocking(struct ipdbg_la_tcp *tcp,
|
|||
}
|
||||
|
||||
SR_PRIV int ipdbg_la_tcp_receive(struct ipdbg_la_tcp *tcp,
|
||||
uint8_t *buf)
|
||||
uint8_t *buf, size_t bufsize)
|
||||
{
|
||||
int received = 0;
|
||||
|
||||
if (data_available(tcp)) {
|
||||
while (received < 1) {
|
||||
int len = recv(tcp->socket, (char *)buf, 1, 0);
|
||||
|
||||
if (len < 0) {
|
||||
sr_err("Receive error: %s", g_strerror(errno));
|
||||
return SR_ERR;
|
||||
} else
|
||||
received += len;
|
||||
}
|
||||
|
||||
return received;
|
||||
} else
|
||||
if (data_available(tcp))
|
||||
received = recv(tcp->socket, (char *)buf, bufsize, 0);
|
||||
if (received < 0) {
|
||||
sr_err("Receive error: %s", g_strerror(errno));
|
||||
return -1;
|
||||
} else
|
||||
return received;
|
||||
}
|
||||
|
||||
SR_PRIV int ipdbg_la_convert_trigger(const struct sr_dev_inst *sdi)
|
||||
|
@ -310,14 +309,22 @@ SR_PRIV int ipdbg_la_receive_data(int fd, int revents, void *cb_data)
|
|||
|
||||
if (devc->num_transfers <
|
||||
(devc->limit_samples_max * devc->data_width_bytes)) {
|
||||
uint8_t byte;
|
||||
const size_t bufsize = 1024;
|
||||
uint8_t buffer[bufsize];
|
||||
|
||||
if (ipdbg_la_tcp_receive(tcp, &byte) == 1) {
|
||||
if (devc->num_transfers <
|
||||
(devc->limit_samples * devc->data_width_bytes))
|
||||
devc->raw_sample_buf[devc->num_transfers] = byte;
|
||||
|
||||
devc->num_transfers++;
|
||||
const int recd = ipdbg_la_tcp_receive(tcp, buffer, bufsize);
|
||||
if ( recd > 0) {
|
||||
int num_move = (((devc->num_transfers + recd) <=
|
||||
(devc->limit_samples * devc->data_width_bytes))
|
||||
?
|
||||
recd
|
||||
:
|
||||
(int)((devc->limit_samples * devc->data_width_bytes) -
|
||||
devc->num_transfers));
|
||||
if ( num_move > 0 )
|
||||
memcpy(&(devc->raw_sample_buf[devc->num_transfers]),
|
||||
buffer, num_move);
|
||||
devc->num_transfers += recd;
|
||||
}
|
||||
} else {
|
||||
if (devc->delay_value > 0) {
|
||||
|
@ -379,7 +386,7 @@ static int send_escaping(struct ipdbg_la_tcp *tcp, uint8_t *data_to_send,
|
|||
SR_PRIV int ipdbg_la_send_delay(struct dev_context *devc,
|
||||
struct ipdbg_la_tcp *tcp)
|
||||
{
|
||||
devc->delay_value = (devc->limit_samples / 100.0) * devc->capture_ratio;
|
||||
devc->delay_value = ((devc->limit_samples - 1) / 100.0) * devc->capture_ratio;
|
||||
|
||||
uint8_t buf;
|
||||
buf = CMD_CFG_LA;
|
||||
|
|
|
@ -58,7 +58,8 @@ SR_PRIV struct ipdbg_la_tcp *ipdbg_la_tcp_new(void);
|
|||
SR_PRIV void ipdbg_la_tcp_free(struct ipdbg_la_tcp *tcp);
|
||||
SR_PRIV int ipdbg_la_tcp_open(struct ipdbg_la_tcp *tcp);
|
||||
SR_PRIV int ipdbg_la_tcp_close(struct ipdbg_la_tcp *tcp);
|
||||
SR_PRIV int ipdbg_la_tcp_receive(struct ipdbg_la_tcp *tcp, uint8_t *buf);
|
||||
SR_PRIV int ipdbg_la_tcp_receive(struct ipdbg_la_tcp *tcp,
|
||||
uint8_t *buf, size_t bufsize);
|
||||
|
||||
SR_PRIV int ipdbg_la_convert_trigger(const struct sr_dev_inst *sdi);
|
||||
|
||||
|
|
|
@ -371,7 +371,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
packet.payload = &meta;
|
||||
meta.config = g_slist_append(NULL, src);
|
||||
sr_session_send(sdi, &packet);
|
||||
g_free(src);
|
||||
g_slist_free(meta.config);
|
||||
sr_config_free(src);
|
||||
}
|
||||
|
||||
if (!(devc->xfer = libusb_alloc_transfer(0)))
|
||||
|
|
|
@ -89,7 +89,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
/* Let's get a bit of data and see if we can find a packet. */
|
||||
len = sizeof(buf);
|
||||
ret = serial_stream_detect(serial, buf, &len, scale->packet_size,
|
||||
scale->packet_valid, 3000, scale->baudrate);
|
||||
scale->packet_valid, 3000);
|
||||
if (ret != SR_OK)
|
||||
goto scan_cleanup;
|
||||
|
||||
|
@ -153,7 +153,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
#define SCALE(ID, CHIPSET, VENDOR, MODEL, CONN, BAUDRATE, PACKETSIZE, \
|
||||
#define SCALE(ID, CHIPSET, VENDOR, MODEL, CONN, PACKETSIZE, \
|
||||
VALID, PARSE) \
|
||||
&((struct scale_info) { \
|
||||
{ \
|
||||
|
@ -174,7 +174,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
.dev_acquisition_stop = std_serial_dev_acquisition_stop, \
|
||||
.context = NULL, \
|
||||
}, \
|
||||
VENDOR, MODEL, CONN, BAUDRATE, PACKETSIZE, \
|
||||
VENDOR, MODEL, CONN, PACKETSIZE, \
|
||||
VALID, PARSE, sizeof(struct CHIPSET##_info) \
|
||||
}).di
|
||||
|
||||
|
@ -191,7 +191,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
SR_REGISTER_DEV_DRIVER_LIST(kern_scale_drivers,
|
||||
SCALE(
|
||||
"kern-ew-6200-2nm", kern,
|
||||
"KERN", "EW 6200-2NM", "1200/8n2", 1200,
|
||||
"KERN", "EW 6200-2NM", "1200/8n2",
|
||||
15 /* (or 14) */, sr_kern_packet_valid, sr_kern_parse
|
||||
)
|
||||
);
|
||||
|
|
|
@ -31,8 +31,6 @@ struct scale_info {
|
|||
const char *device;
|
||||
/** serialconn string. */
|
||||
const char *conn;
|
||||
/** Baud rate. */
|
||||
uint32_t baudrate;
|
||||
/** Packet size in bytes. */
|
||||
int packet_size;
|
||||
/** Packet validation function. */
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
|
||||
* Copyright (C) 2018 Frank Stettner <frank-stettner@gmx.net>
|
||||
* Copyright (C) 2018-2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -55,16 +55,27 @@ static const struct korad_kaxxxxp_model models[] = {
|
|||
/* Sometimes the KA3005P has an extra 0x01 after the ID. */
|
||||
{KORAD_KA3005P_0X01, "Korad", "KA3005P",
|
||||
"KORADKA3005PV2.0\x01", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
/* Sometimes the KA3005P has an extra 0xBC after the ID. */
|
||||
{KORAD_KA3005P_0XBC, "Korad", "KA3005P",
|
||||
"KORADKA3005PV2.0\xBC", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
{KORAD_KD3005P, "Korad", "KD3005P",
|
||||
"KORAD KD3005P V2.0", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
{KORAD_KD3005P_V20_NOSP, "Korad", "KD3005P",
|
||||
"KORADKD3005PV2.0", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
{RND_320_KD3005P, "RND", "KD3005P",
|
||||
"RND 320-KD3005P V4.2", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
{RND_320K30PV, "RND", "KA3005P",
|
||||
"RND 320-KA3005P V2.0", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
{TENMA_72_2540_V20, "Tenma", "72-2540",
|
||||
"TENMA72-2540V2.0", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
{TENMA_72_2540_V21, "Tenma", "72-2540",
|
||||
"TENMA 72-2540 V2.1", 1, {0, 31, 0.01}, {0, 5, 0.001}},
|
||||
{TENMA_72_2535_V21, "Tenma", "72-2535",
|
||||
"TENMA 72-2535 V2.1", 1, {0, 31, 0.01}, {0, 3, 0.001}},
|
||||
{STAMOS_SLS31_V20, "Stamos Soldering", "S-LS-31",
|
||||
"S-LS-31 V2.0", 1, {0, 31, 0.01}, {0, 5.1, 0.001}},
|
||||
{KORAD_KD6005P, "Korad", "KD6005P",
|
||||
"KORAD KD6005P V2.2", 1, {0, 61, 0.01}, {0, 5, 0.001}},
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
|
@ -115,6 +126,13 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
if (strlen(models[i].id) > len)
|
||||
len = strlen(models[i].id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some models also include the serial number:
|
||||
* RND 320-KD3005P V4.2 SN:59834414
|
||||
*/
|
||||
len += 12;
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
sr_dbg("Want max %d bytes.", len);
|
||||
if ((korad_kaxxxxp_send_cmd(serial, "*IDN?") < 0))
|
||||
|
@ -125,8 +143,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
return NULL;
|
||||
sr_dbg("Received: %d, %s", i, reply);
|
||||
model_id = -1;
|
||||
|
||||
/* Truncate before serial number. */
|
||||
char *sn = g_strrstr(reply, " SN:");
|
||||
if (sn)
|
||||
*sn = '\0';
|
||||
|
||||
for (i = 0; models[i].id; i++) {
|
||||
if (!strcmp(models[i].id, reply))
|
||||
if (!g_strcmp0(models[i].id, reply))
|
||||
model_id = i;
|
||||
}
|
||||
if (model_id < 0) {
|
||||
|
@ -151,6 +175,11 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
g_mutex_init(&devc->rw_mutex);
|
||||
devc->model = &models[model_id];
|
||||
devc->req_sent_at = 0;
|
||||
devc->cc_mode_1_changed = FALSE;
|
||||
devc->cc_mode_2_changed = FALSE;
|
||||
devc->output_enabled_changed = FALSE;
|
||||
devc->ocp_enabled_changed = FALSE;
|
||||
devc->ovp_enabled_changed = FALSE;
|
||||
sdi->priv = devc;
|
||||
|
||||
/* Get current status of device. */
|
||||
|
@ -190,16 +219,16 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
*data = g_variant_new_double(devc->voltage);
|
||||
break;
|
||||
case SR_CONF_VOLTAGE_TARGET:
|
||||
korad_kaxxxxp_get_value(sdi->conn, KAXXXXP_VOLTAGE_MAX, devc);
|
||||
*data = g_variant_new_double(devc->voltage_max);
|
||||
korad_kaxxxxp_get_value(sdi->conn, KAXXXXP_VOLTAGE_TARGET, devc);
|
||||
*data = g_variant_new_double(devc->voltage_target);
|
||||
break;
|
||||
case SR_CONF_CURRENT:
|
||||
korad_kaxxxxp_get_value(sdi->conn, KAXXXXP_CURRENT, devc);
|
||||
*data = g_variant_new_double(devc->current);
|
||||
break;
|
||||
case SR_CONF_CURRENT_LIMIT:
|
||||
korad_kaxxxxp_get_value(sdi->conn, KAXXXXP_CURRENT_MAX, devc);
|
||||
*data = g_variant_new_double(devc->current_max);
|
||||
korad_kaxxxxp_get_value(sdi->conn, KAXXXXP_CURRENT_LIMIT, devc);
|
||||
*data = g_variant_new_double(devc->current_limit);
|
||||
break;
|
||||
case SR_CONF_ENABLED:
|
||||
korad_kaxxxxp_get_value(sdi->conn, KAXXXXP_OUTPUT, devc);
|
||||
|
@ -244,34 +273,34 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
dval = g_variant_get_double(data);
|
||||
if (dval < devc->model->voltage[0] || dval > devc->model->voltage[1])
|
||||
return SR_ERR_ARG;
|
||||
devc->voltage_max = dval;
|
||||
if (korad_kaxxxxp_set_value(sdi->conn, KAXXXXP_VOLTAGE_MAX, devc) < 0)
|
||||
devc->set_voltage_target = dval;
|
||||
if (korad_kaxxxxp_set_value(sdi->conn, KAXXXXP_VOLTAGE_TARGET, devc) < 0)
|
||||
return SR_ERR;
|
||||
break;
|
||||
case SR_CONF_CURRENT_LIMIT:
|
||||
dval = g_variant_get_double(data);
|
||||
if (dval < devc->model->current[0] || dval > devc->model->current[1])
|
||||
return SR_ERR_ARG;
|
||||
devc->current_max = dval;
|
||||
if (korad_kaxxxxp_set_value(sdi->conn, KAXXXXP_CURRENT_MAX, devc) < 0)
|
||||
devc->set_current_limit = dval;
|
||||
if (korad_kaxxxxp_set_value(sdi->conn, KAXXXXP_CURRENT_LIMIT, devc) < 0)
|
||||
return SR_ERR;
|
||||
break;
|
||||
case SR_CONF_ENABLED:
|
||||
bval = g_variant_get_boolean(data);
|
||||
/* Set always so it is possible turn off with sigrok-cli. */
|
||||
devc->output_enabled = bval;
|
||||
devc->set_output_enabled = bval;
|
||||
if (korad_kaxxxxp_set_value(sdi->conn, KAXXXXP_OUTPUT, devc) < 0)
|
||||
return SR_ERR;
|
||||
break;
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
|
||||
bval = g_variant_get_boolean(data);
|
||||
devc->ocp_enabled = bval;
|
||||
devc->set_ocp_enabled = bval;
|
||||
if (korad_kaxxxxp_set_value(sdi->conn, KAXXXXP_OCP, devc) < 0)
|
||||
return SR_ERR;
|
||||
break;
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
|
||||
bval = g_variant_get_boolean(data);
|
||||
devc->ovp_enabled = bval;
|
||||
devc->set_ovp_enabled = bval;
|
||||
if (korad_kaxxxxp_set_value(sdi->conn, KAXXXXP_OVP, devc) < 0)
|
||||
return SR_ERR;
|
||||
break;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
|
||||
* Copyright (C) 2018 Frank Stettner <frank-stettner@gmx.net>
|
||||
* Copyright (C) 2018-2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -96,29 +96,35 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
|
|||
sr_err("Can't set measurable parameter %d.", target);
|
||||
g_mutex_unlock(&devc->rw_mutex);
|
||||
return SR_ERR;
|
||||
case KAXXXXP_CURRENT_MAX:
|
||||
case KAXXXXP_CURRENT_LIMIT:
|
||||
cmd = "ISET1:%05.3f";
|
||||
value = devc->current_max;
|
||||
value = devc->set_current_limit;
|
||||
break;
|
||||
case KAXXXXP_VOLTAGE_MAX:
|
||||
case KAXXXXP_VOLTAGE_TARGET:
|
||||
cmd = "VSET1:%05.2f";
|
||||
value = devc->voltage_max;
|
||||
value = devc->set_voltage_target;
|
||||
break;
|
||||
case KAXXXXP_OUTPUT:
|
||||
cmd = "OUT%01.0f";
|
||||
value = (devc->output_enabled) ? 1 : 0;
|
||||
value = (devc->set_output_enabled) ? 1 : 0;
|
||||
/* Set value back to recognize changes */
|
||||
devc->output_enabled = devc->set_output_enabled;
|
||||
break;
|
||||
case KAXXXXP_BEEP:
|
||||
cmd = "BEEP%01.0f";
|
||||
value = (devc->beep_enabled) ? 1 : 0;
|
||||
value = (devc->set_beep_enabled) ? 1 : 0;
|
||||
break;
|
||||
case KAXXXXP_OCP:
|
||||
cmd = "OCP%01.0f";
|
||||
value = (devc->ocp_enabled) ? 1 : 0;
|
||||
value = (devc->set_ocp_enabled) ? 1 : 0;
|
||||
/* Set value back to recognize changes */
|
||||
devc->ocp_enabled = devc->set_ocp_enabled;
|
||||
break;
|
||||
case KAXXXXP_OVP:
|
||||
cmd = "OVP%01.0f";
|
||||
value = (devc->ovp_enabled) ? 1 : 0;
|
||||
value = (devc->set_ovp_enabled) ? 1 : 0;
|
||||
/* Set value back to recognize changes */
|
||||
devc->ovp_enabled = devc->set_ovp_enabled;
|
||||
break;
|
||||
case KAXXXXP_SAVE:
|
||||
cmd = "SAV%01.0f";
|
||||
|
@ -166,6 +172,7 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
|
|||
char reply[6];
|
||||
float *value;
|
||||
char status_byte;
|
||||
gboolean prev_status;
|
||||
|
||||
g_mutex_lock(&devc->rw_mutex);
|
||||
give_device_time_to_process(devc);
|
||||
|
@ -179,20 +186,20 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
|
|||
ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?");
|
||||
value = &(devc->current);
|
||||
break;
|
||||
case KAXXXXP_CURRENT_MAX:
|
||||
case KAXXXXP_CURRENT_LIMIT:
|
||||
/* Read set current from device. */
|
||||
ret = korad_kaxxxxp_send_cmd(serial, "ISET1?");
|
||||
value = &(devc->current_max);
|
||||
value = &(devc->current_limit);
|
||||
break;
|
||||
case KAXXXXP_VOLTAGE:
|
||||
/* Read voltage from device. */
|
||||
ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?");
|
||||
value = &(devc->voltage);
|
||||
break;
|
||||
case KAXXXXP_VOLTAGE_MAX:
|
||||
case KAXXXXP_VOLTAGE_TARGET:
|
||||
/* Read set voltage from device. */
|
||||
ret = korad_kaxxxxp_send_cmd(serial, "VSET1?");
|
||||
value = &(devc->voltage_max);
|
||||
value = &(devc->voltage_target);
|
||||
break;
|
||||
case KAXXXXP_STATUS:
|
||||
case KAXXXXP_OUTPUT:
|
||||
|
@ -223,37 +230,58 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
|
|||
} else {
|
||||
/* We have status reply. */
|
||||
status_byte = reply[0];
|
||||
/* Constant current */
|
||||
devc->cc_mode[0] = !(status_byte & (1 << 0)); /* Channel one */
|
||||
devc->cc_mode[1] = !(status_byte & (1 << 1)); /* Channel two */
|
||||
|
||||
/* Constant current channel one. */
|
||||
prev_status = devc->cc_mode[0];
|
||||
devc->cc_mode[0] = !(status_byte & (1 << 0));
|
||||
devc->cc_mode_1_changed = devc->cc_mode[0] != prev_status;
|
||||
/* Constant current channel two. */
|
||||
prev_status = devc->cc_mode[1];
|
||||
devc->cc_mode[1] = !(status_byte & (1 << 1));
|
||||
devc->cc_mode_2_changed = devc->cc_mode[1] != prev_status;
|
||||
|
||||
/*
|
||||
* Tracking
|
||||
* Tracking:
|
||||
* status_byte & ((1 << 2) | (1 << 3))
|
||||
* 00 independent 01 series 11 parallel
|
||||
*/
|
||||
devc->beep_enabled = (1 << 4);
|
||||
devc->ocp_enabled = (status_byte & (1 << 5));
|
||||
devc->output_enabled = (status_byte & (1 << 6));
|
||||
/* Velleman LABPS3005 quirk */
|
||||
if (devc->output_enabled)
|
||||
devc->ovp_enabled = (status_byte & (1 << 7));
|
||||
devc->beep_enabled = status_byte & (1 << 4);
|
||||
|
||||
/* OCP enabled. */
|
||||
prev_status = devc->ocp_enabled;
|
||||
devc->ocp_enabled = status_byte & (1 << 5);
|
||||
devc->ocp_enabled_changed = devc->ocp_enabled != prev_status;
|
||||
|
||||
/* Output status. */
|
||||
prev_status = devc->output_enabled;
|
||||
devc->output_enabled = status_byte & (1 << 6);
|
||||
devc->output_enabled_changed = devc->output_enabled != prev_status;
|
||||
|
||||
/* OVP enabled, special handling for Velleman LABPS3005 quirk. */
|
||||
if ((devc->model->model_id == VELLEMAN_LABPS3005D && devc->output_enabled) ||
|
||||
devc->model->model_id != VELLEMAN_LABPS3005D) {
|
||||
|
||||
prev_status = devc->ovp_enabled;
|
||||
devc->ovp_enabled = status_byte & (1 << 7);
|
||||
devc->ovp_enabled_changed = devc->ovp_enabled != prev_status;
|
||||
}
|
||||
|
||||
sr_dbg("Status: 0x%02x", status_byte);
|
||||
sr_spew("Status: CH1: constant %s CH2: constant %s. "
|
||||
"Tracking would be %s. Device is "
|
||||
"%s and %s. Buttons are %s. Output is %s "
|
||||
"and extra byte is %s.",
|
||||
"Tracking would be %s and %s. Output is %s. "
|
||||
"OCP is %s, OVP is %s. Device is %s.",
|
||||
(status_byte & (1 << 0)) ? "voltage" : "current",
|
||||
(status_byte & (1 << 1)) ? "voltage" : "current",
|
||||
(status_byte & (1 << 2)) ? "parallel" : "series",
|
||||
(status_byte & (1 << 3)) ? "tracking" : "independent",
|
||||
(status_byte & (1 << 4)) ? "beeping" : "silent",
|
||||
(status_byte & (1 << 5)) ? "locked" : "unlocked",
|
||||
(status_byte & (1 << 6)) ? "enabled" : "disabled",
|
||||
(status_byte & (1 << 7)) ? "true" : "false");
|
||||
(status_byte & (1 << 5)) ? "enabled" : "disabled",
|
||||
(status_byte & (1 << 7)) ? "enabled" : "disabled",
|
||||
(status_byte & (1 << 4)) ? "beeping" : "silent");
|
||||
}
|
||||
|
||||
/* Read the sixth byte from ISET? BUG workaround. */
|
||||
if (target == KAXXXXP_CURRENT_MAX)
|
||||
if (target == KAXXXXP_CURRENT_LIMIT)
|
||||
serial_read_blocking(serial, &status_byte, 1, 10);
|
||||
|
||||
g_mutex_unlock(&devc->rw_mutex);
|
||||
|
@ -332,7 +360,7 @@ SR_PRIV int korad_kaxxxxp_receive_data(int fd, int revents, void *cb_data)
|
|||
analog.meaning->channels = l;
|
||||
analog.meaning->mq = SR_MQ_CURRENT;
|
||||
analog.meaning->unit = SR_UNIT_AMPERE;
|
||||
analog.meaning->mqflags = 0;
|
||||
analog.meaning->mqflags = SR_MQFLAG_DC;
|
||||
analog.encoding->digits = 3;
|
||||
analog.spec->spec_digits = 3;
|
||||
analog.data = &devc->current;
|
||||
|
@ -348,6 +376,32 @@ SR_PRIV int korad_kaxxxxp_receive_data(int fd, int revents, void *cb_data)
|
|||
analog.data = &devc->voltage;
|
||||
sr_session_send(sdi, &packet);
|
||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||
} else if (devc->acquisition_target == KAXXXXP_STATUS) {
|
||||
if (devc->cc_mode_1_changed) {
|
||||
sr_session_send_meta(sdi, SR_CONF_REGULATION,
|
||||
g_variant_new_string((devc->cc_mode[0]) ? "CC" : "CV"));
|
||||
devc->cc_mode_1_changed = FALSE;
|
||||
}
|
||||
if (devc->cc_mode_2_changed) {
|
||||
sr_session_send_meta(sdi, SR_CONF_REGULATION,
|
||||
g_variant_new_string((devc->cc_mode[1]) ? "CC" : "CV"));
|
||||
devc->cc_mode_2_changed = FALSE;
|
||||
}
|
||||
if (devc->output_enabled_changed) {
|
||||
sr_session_send_meta(sdi, SR_CONF_ENABLED,
|
||||
g_variant_new_boolean(devc->output_enabled));
|
||||
devc->output_enabled_changed = FALSE;
|
||||
}
|
||||
if (devc->ocp_enabled_changed) {
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_CURRENT_PROTECTION_ENABLED,
|
||||
g_variant_new_boolean(devc->ocp_enabled));
|
||||
devc->ocp_enabled_changed = FALSE;
|
||||
}
|
||||
if (devc->ovp_enabled_changed) {
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED,
|
||||
g_variant_new_boolean(devc->ovp_enabled));
|
||||
devc->ovp_enabled_changed = FALSE;
|
||||
}
|
||||
}
|
||||
next_measurement(devc);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
|
||||
* Copyright (C) 2018 Frank Stettner <frank-stettner@gmx.net>
|
||||
* Copyright (C) 2018-2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -36,11 +36,16 @@ enum {
|
|||
VELLEMAN_LABPS3005D,
|
||||
KORAD_KA3005P,
|
||||
KORAD_KA3005P_0X01,
|
||||
KORAD_KA3005P_0XBC,
|
||||
KORAD_KD3005P,
|
||||
KORAD_KD3005P_V20_NOSP,
|
||||
RND_320_KD3005P,
|
||||
RND_320K30PV,
|
||||
TENMA_72_2540_V20,
|
||||
TENMA_72_2540_V21,
|
||||
TENMA_72_2535_V21,
|
||||
STAMOS_SLS31_V20,
|
||||
KORAD_KD6005P,
|
||||
/* Support for future devices with this protocol. */
|
||||
};
|
||||
|
||||
|
@ -58,9 +63,9 @@ struct korad_kaxxxxp_model {
|
|||
/* Reply targets */
|
||||
enum {
|
||||
KAXXXXP_CURRENT,
|
||||
KAXXXXP_CURRENT_MAX,
|
||||
KAXXXXP_CURRENT_LIMIT,
|
||||
KAXXXXP_VOLTAGE,
|
||||
KAXXXXP_VOLTAGE_MAX,
|
||||
KAXXXXP_VOLTAGE_TARGET,
|
||||
KAXXXXP_STATUS,
|
||||
KAXXXXP_OUTPUT,
|
||||
KAXXXXP_BEEP,
|
||||
|
@ -78,9 +83,9 @@ struct dev_context {
|
|||
GMutex rw_mutex;
|
||||
|
||||
float current; /**< Last current value [A] read from device. */
|
||||
float current_max; /**< Output current set. */
|
||||
float current_limit; /**< Output current set. */
|
||||
float voltage; /**< Last voltage value [V] read from device. */
|
||||
float voltage_max; /**< Output voltage set. */
|
||||
float voltage_target; /**< Output voltage set. */
|
||||
gboolean cc_mode[2]; /**< Device is in CC mode (otherwise CV). */
|
||||
|
||||
gboolean output_enabled; /**< Is the output enabled? */
|
||||
|
@ -88,8 +93,21 @@ struct dev_context {
|
|||
gboolean ocp_enabled; /**< Output current protection enabled. */
|
||||
gboolean ovp_enabled; /**< Output voltage protection enabled. */
|
||||
|
||||
gboolean cc_mode_1_changed; /**< CC mode of channel 1 has changed. */
|
||||
gboolean cc_mode_2_changed; /**< CC mode of channel 2 has changed. */
|
||||
gboolean output_enabled_changed; /**< Output enabled state has changed. */
|
||||
gboolean ocp_enabled_changed; /**< OCP enabled state has changed. */
|
||||
gboolean ovp_enabled_changed; /**< OVP enabled state has changed. */
|
||||
|
||||
int acquisition_target; /**< What reply to expect. */
|
||||
int program; /**< Program to store or recall. */
|
||||
|
||||
float set_current_limit; /**< New output current to set. */
|
||||
float set_voltage_target; /**< New output voltage to set. */
|
||||
gboolean set_output_enabled; /**< New output enabled to set. */
|
||||
gboolean set_beep_enabled; /**< New enable beeper to set. */
|
||||
gboolean set_ocp_enabled; /**< New OCP enabled to set. */
|
||||
gboolean set_ovp_enabled; /**< New OVP enabled to set. */
|
||||
};
|
||||
|
||||
SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
|
||||
|
|
|
@ -288,7 +288,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, g_variant_new_uint64(interval));
|
||||
meta.config = g_slist_append(NULL, src);
|
||||
sr_session_send(sdi, &packet);
|
||||
g_free(src);
|
||||
g_slist_free(meta.config);
|
||||
sr_config_free(src);
|
||||
|
||||
if (devc->logged_samples == 0) {
|
||||
/* This ensures the frontend knows the session is done. */
|
||||
|
|
|
@ -626,7 +626,6 @@ SR_PRIV int lecroy_xstream_receive_data(int fd, int revents, void *cb_data)
|
|||
struct sr_analog_encoding encoding;
|
||||
struct sr_analog_meaning meaning;
|
||||
struct sr_analog_spec spec;
|
||||
char buf[8];
|
||||
|
||||
(void)fd;
|
||||
(void)revents;
|
||||
|
@ -645,12 +644,6 @@ SR_PRIV int lecroy_xstream_receive_data(int fd, int revents, void *cb_data)
|
|||
if (ch->type != SR_CHANNEL_ANALOG)
|
||||
return SR_ERR;
|
||||
|
||||
/* Pass on the received data of the channel(s). */
|
||||
if (sr_scpi_read_data(sdi->conn, buf, 4) != 4) {
|
||||
sr_err("Reading header failed, scope probably didn't send any data.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (sr_scpi_get_block(sdi->conn, NULL, &data) != SR_OK) {
|
||||
if (data)
|
||||
g_byte_array_free(data, TRUE);
|
||||
|
|
|
@ -43,23 +43,27 @@ static const uint32_t devopts[] = {
|
|||
|
||||
/* Note: All models have one power supply output only. */
|
||||
static const struct hcs_model models[] = {
|
||||
{ MANSON_HCS_3100, "HCS-3100", "3100", { 1, 18, 0.1 }, { 0, 10, 0.10 } },
|
||||
{ MANSON_HCS_3102, "HCS-3102", "3102", { 1, 36, 0.1 }, { 0, 5, 0.01 } },
|
||||
{ MANSON_HCS_3104, "HCS-3104", "3104", { 1, 60, 0.1 }, { 0, 2.5, 0.01 } },
|
||||
{ MANSON_HCS_3150, "HCS-3150", "3150", { 1, 18, 0.1 }, { 0, 15, 0.10 } },
|
||||
{ MANSON_HCS_3200, "HCS-3200", "3200", { 1, 18, 0.1 }, { 0, 20, 0.10 } },
|
||||
{ MANSON_HCS_3202, "HCS-3202", "3202", { 1, 36, 0.1 }, { 0, 10, 0.10 } },
|
||||
{ MANSON_HCS_3204, "HCS-3204", "3204", { 1, 60, 0.1 }, { 0, 5, 0.01 } },
|
||||
{ MANSON_HCS_3300, "HCS-3300-USB", "3300", { 1, 16, 0.1 }, { 0, 30, 0.10 } },
|
||||
{ MANSON_HCS_3302, "HCS-3302-USB", "3302", { 1, 32, 0.1 }, { 0, 15, 0.10 } },
|
||||
{ MANSON_HCS_3304, "HCS-3304-USB", "3304", { 1, 60, 0.1 }, { 0, 8, 0.10 } },
|
||||
{ MANSON_HCS_3100, "HCS-3100", "3100", { 1, 18, 0.1 }, { 0, 10, 0.10 } },
|
||||
{ MANSON_HCS_3102, "HCS-3102", "3102", { 1, 36, 0.1 }, { 0, 5, 0.01 } },
|
||||
{ MANSON_HCS_3104, "HCS-3104", "3104", { 1, 60, 0.1 }, { 0, 2.5, 0.01 } },
|
||||
{ MANSON_HCS_3150, "HCS-3150", "3150", { 1, 18, 0.1 }, { 0, 15, 0.10 } },
|
||||
{ MANSON_HCS_3200, "HCS-3200", "3200", { 1, 18, 0.1 }, { 0, 20, 0.10 } },
|
||||
{ MANSON_HCS_3200, "HCS-3200", "HCS-3200", { 1, 18, 0.1 }, { 0, 20, 0.10 } },
|
||||
{ MANSON_HCS_3202, "HCS-3202", "3202", { 1, 36, 0.1 }, { 0, 10, 0.10 } },
|
||||
{ MANSON_HCS_3202, "HCS-3202", "HCS-3202", { 1, 36, 0.1 }, { 0, 10, 0.10 } },
|
||||
{ MANSON_HCS_3204, "HCS-3204", "3204", { 1, 60, 0.1 }, { 0, 5, 0.01 } },
|
||||
{ MANSON_HCS_3300, "HCS-3300-USB", "3300", { 1, 16, 0.1 }, { 0, 30, 0.10 } },
|
||||
{ MANSON_HCS_3300, "HCS-3300-USB", "HCS-3300", { 1, 16, 0.1 }, { 0, 30, 0.10 } },
|
||||
{ MANSON_HCS_3302, "HCS-3302-USB", "3302", { 1, 32, 0.1 }, { 0, 15, 0.10 } },
|
||||
{ MANSON_HCS_3302, "HCS-3302-USB", "HCS-3302", { 1, 32, 0.1 }, { 0, 15, 0.10 } },
|
||||
{ MANSON_HCS_3304, "HCS-3304-USB", "3304", { 1, 60, 0.1 }, { 0, 8, 0.10 } },
|
||||
{ MANSON_HCS_3304, "HCS-3304-USB", "HCS-3304", { 1, 60, 0.1 }, { 0, 8, 0.10 } },
|
||||
{ MANSON_HCS_3400, "HCS-3400-USB", "3400", { 1, 16, 0.1 }, { 0, 40, 0.10 } },
|
||||
{ MANSON_HCS_3402, "HCS-3402-USB", "3402", { 1, 32, 0.1 }, { 0, 20, 0.10 } },
|
||||
{ MANSON_HCS_3404, "HCS-3404-USB", "3404", { 1, 60, 0.1 }, { 0, 10, 0.10 } },
|
||||
{ MANSON_HCS_3600, "HCS-3600-USB", "3600", { 1, 16, 0.1 }, { 0, 60, 0.10 } },
|
||||
{ MANSON_HCS_3602, "HCS-3602-USB", "3602", { 1, 32, 0.1 }, { 0, 30, 0.10 } },
|
||||
{ MANSON_HCS_3604, "HCS-3604-USB", "3604", { 1, 60, 0.1 }, { 0, 15, 0.10 } },
|
||||
{ MANSON_HCS_3400, "HCS-3400-USB", "3400", { 1, 16, 0.1 }, { 0, 40, 0.10 } },
|
||||
{ MANSON_HCS_3402, "HCS-3402-USB", "3402", { 1, 32, 0.1 }, { 0, 20, 0.10 } },
|
||||
{ MANSON_HCS_3404, "HCS-3404-USB", "3404", { 1, 60, 0.1 }, { 0, 10, 0.10 } },
|
||||
{ MANSON_HCS_3600, "HCS-3600-USB", "3600", { 1, 16, 0.1 }, { 0, 60, 0.10 } },
|
||||
{ MANSON_HCS_3602, "HCS-3602-USB", "3602", { 1, 32, 0.1 }, { 0, 30, 0.10 } },
|
||||
{ MANSON_HCS_3604, "HCS-3604-USB", "3604", { 1, 60, 0.1 }, { 0, 15, 0.10 } },
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2019 Dave Buechi <db@pflutsch.ch>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "protocol.h"
|
||||
|
||||
static const uint32_t scanopts[] = {
|
||||
SR_CONF_CONN,
|
||||
SR_CONF_SERIALCOMM,
|
||||
};
|
||||
|
||||
static const uint32_t drvopts[] = {
|
||||
SR_CONF_THERMOMETER,
|
||||
};
|
||||
|
||||
static const uint32_t devopts[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_DATA_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
};
|
||||
|
||||
static const char *channel_names[] = {
|
||||
"T1", "T2", "T1-T2",
|
||||
};
|
||||
|
||||
static const char *data_sources[] = {
|
||||
"Live", "Memory",
|
||||
};
|
||||
|
||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_serial_dev_inst *serial;
|
||||
struct sr_dev_inst *sdi;
|
||||
struct sr_config *src;
|
||||
GSList *devices, *l;
|
||||
const char *conn, *serialcomm;
|
||||
uint8_t buf[2 * MASTECH_MS6514_FRAME_SIZE];
|
||||
size_t len, i;
|
||||
|
||||
len = sizeof(buf);
|
||||
devices = NULL;
|
||||
conn = serialcomm = NULL;
|
||||
for (l = options; l; l = l->next) {
|
||||
src = l->data;
|
||||
switch (src->key) {
|
||||
case SR_CONF_CONN:
|
||||
conn = g_variant_get_string(src->data, NULL);
|
||||
break;
|
||||
case SR_CONF_SERIALCOMM:
|
||||
serialcomm = g_variant_get_string(src->data, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!conn)
|
||||
return NULL;
|
||||
if (!serialcomm)
|
||||
serialcomm = "9600/8n1";
|
||||
|
||||
serial = sr_serial_dev_inst_new(conn, serialcomm);
|
||||
|
||||
if (serial_open(serial, SERIAL_RDONLY) != SR_OK)
|
||||
return NULL;
|
||||
|
||||
sr_info("Probing serial port %s.", conn);
|
||||
|
||||
serial_flush(serial);
|
||||
|
||||
/* Let's get a bit of data and see if we can find a packet. */
|
||||
if (serial_stream_detect(serial, buf, &len, (2 * MASTECH_MS6514_FRAME_SIZE),
|
||||
mastech_ms6514_packet_valid, 500) != SR_OK)
|
||||
goto scan_cleanup;
|
||||
|
||||
sr_info("Found device on port %s.", conn);
|
||||
|
||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||
sdi->status = SR_ST_INACTIVE;
|
||||
sdi->vendor = g_strdup("MASTECH");
|
||||
sdi->model = g_strdup("MS6514");
|
||||
devc = g_malloc0(sizeof(struct dev_context));
|
||||
devc->data_source = DEFAULT_DATA_SOURCE;
|
||||
sdi->inst_type = SR_INST_SERIAL;
|
||||
sdi->conn = serial;
|
||||
sdi->priv = devc;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(channel_names); i++)
|
||||
sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, channel_names[i]);
|
||||
|
||||
devices = g_slist_append(devices, sdi);
|
||||
|
||||
scan_cleanup:
|
||||
serial_close(serial);
|
||||
|
||||
return std_scan_complete(di, devices);
|
||||
}
|
||||
|
||||
static int config_get(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc = sdi->priv;
|
||||
|
||||
(void)cg;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
case SR_CONF_LIMIT_MSEC:
|
||||
return sr_sw_limits_config_get(&devc->limits, key, data);
|
||||
case SR_CONF_DATA_SOURCE:
|
||||
*data = g_variant_new_string(data_sources[devc->data_source]);
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int config_set(uint32_t key, GVariant *data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
int idx;
|
||||
|
||||
(void)cg;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
case SR_CONF_LIMIT_MSEC:
|
||||
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||
case SR_CONF_DATA_SOURCE:
|
||||
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
|
||||
return SR_ERR_ARG;
|
||||
devc->data_source = idx;
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int config_list(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
switch (key) {
|
||||
case SR_CONF_SCAN_OPTIONS:
|
||||
case SR_CONF_DEVICE_OPTIONS:
|
||||
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||
case SR_CONF_DATA_SOURCE:
|
||||
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_serial_dev_inst *serial;
|
||||
struct dev_context *devc;
|
||||
uint8_t command;
|
||||
|
||||
serial = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
sr_sw_limits_acquisition_start(&devc->limits);
|
||||
std_session_send_df_header(sdi);
|
||||
|
||||
if (devc->data_source == DATA_SOURCE_MEMORY) {
|
||||
command = CMD_GET_STORED;
|
||||
serial_write_blocking(serial, &command, sizeof(command), 0);
|
||||
}
|
||||
|
||||
serial_source_add(sdi->session, serial, G_IO_IN, MASTECH_MS6514_BUF_SIZE,
|
||||
mastech_ms6514_receive_data, (void *)sdi);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static struct sr_dev_driver mastech_ms6514_driver_info = {
|
||||
.name = "mastech-ms6514",
|
||||
.longname = "MASTECH MS6514",
|
||||
.api_version = 1,
|
||||
.init = std_init,
|
||||
.cleanup = std_cleanup,
|
||||
.scan = scan,
|
||||
.dev_list = std_dev_list,
|
||||
.dev_clear = std_dev_clear,
|
||||
.config_get = config_get,
|
||||
.config_set = config_set,
|
||||
.config_list = config_list,
|
||||
.dev_open = std_serial_dev_open,
|
||||
.dev_close = std_serial_dev_close,
|
||||
.dev_acquisition_start = dev_acquisition_start,
|
||||
.dev_acquisition_stop = std_serial_dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
SR_REGISTER_DEV_DRIVER(mastech_ms6514_driver_info);
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2019 Dave Buechi <db@pflutsch.ch>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "protocol.h"
|
||||
|
||||
static const uint8_t channel_assignment[16][2] = {
|
||||
/* MAIN AUX */
|
||||
{0, 1}, /* T1 T2 */
|
||||
{1, 0}, /* T2 T1 */
|
||||
{2, 0}, /* T1-T2 T1 */
|
||||
{2, 1}, /* T1-T2 T2 */
|
||||
{0, 0}, /* T1 T1 MAX */
|
||||
{1, 1}, /* T2 T2 MAX */
|
||||
{2, 2}, /* T1-T2 T1-T2 MAX */
|
||||
{2, 2}, /* T1-T2 T1-T2 MAX */
|
||||
{0, 0}, /* T1 T1 MIN */
|
||||
{1, 1}, /* T2 T2 MIN */
|
||||
{2, 2}, /* T1-T2 T1-T2 MIN */
|
||||
{2, 2}, /* T1-T2 T1-T2 MIN */
|
||||
{0, 0}, /* T1 T1 AVG */
|
||||
{1, 1}, /* T2 T2 AVG */
|
||||
{2, 2}, /* T1-T2 T1-T2 AVG */
|
||||
{2, 2}, /* T1-T2 T1-T2 AVG */
|
||||
};
|
||||
|
||||
SR_PRIV gboolean mastech_ms6514_packet_valid(const uint8_t *buf)
|
||||
{
|
||||
if ((buf[0] == 0x65) && (buf[1] == 0x14) &&
|
||||
(buf[16] == 0x0D) && (buf[17] == 0x0A))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static uint64_t mastech_ms6514_flags(const uint8_t *buf, const uint8_t channel_index)
|
||||
{
|
||||
uint64_t flags;
|
||||
|
||||
flags = 0;
|
||||
if ((buf[10] & 0x40) == 0x40)
|
||||
flags |= SR_MQFLAG_HOLD;
|
||||
|
||||
if (channel_index == 0) {
|
||||
if ((buf[11] & 0x03) > 0x01)
|
||||
flags |= SR_MQFLAG_RELATIVE;
|
||||
}
|
||||
|
||||
if (channel_index == 1) {
|
||||
switch (buf[12] & 0x03) {
|
||||
case 0x01:
|
||||
flags |= SR_MQFLAG_MAX;
|
||||
break;
|
||||
case 0x02:
|
||||
flags |= SR_MQFLAG_MIN;
|
||||
break;
|
||||
case 0x03:
|
||||
flags |= SR_MQFLAG_AVG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static enum sr_unit mastech_ms6514_unit(const uint8_t *buf)
|
||||
{
|
||||
enum sr_unit unit;
|
||||
|
||||
switch (buf[10] & 0x03) {
|
||||
case 0x01:
|
||||
unit = SR_UNIT_CELSIUS;
|
||||
break;
|
||||
case 0x02:
|
||||
unit = SR_UNIT_FAHRENHEIT;
|
||||
break;
|
||||
case 0x03:
|
||||
unit = SR_UNIT_KELVIN;
|
||||
break;
|
||||
default:
|
||||
unit = SR_UNIT_UNITLESS;
|
||||
break;
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
static uint8_t mastech_ms6514_channel_assignment(const uint8_t *buf, const uint8_t index)
|
||||
{
|
||||
return channel_assignment[((buf[12] & 0x03) << 2) + (buf[11] & 0x03)][index];
|
||||
}
|
||||
|
||||
static uint8_t mastech_ms6514_data_source(const uint8_t *buf)
|
||||
{
|
||||
if ((buf[2] & 0x01) == 0x01)
|
||||
return DATA_SOURCE_MEMORY;
|
||||
else
|
||||
return DATA_SOURCE_LIVE;
|
||||
}
|
||||
|
||||
static float mastech_ms6514_temperature(const uint8_t *buf, const uint8_t channel_index, int *digits)
|
||||
{
|
||||
float value;
|
||||
uint8_t modifiers;
|
||||
|
||||
*digits = 0;
|
||||
value = (buf[5 + channel_index * 2] << 8) + buf[6 + channel_index * 2];
|
||||
modifiers = buf[11 + channel_index];
|
||||
|
||||
if ((modifiers & 0x80) == 0x80)
|
||||
value = -value;
|
||||
|
||||
if ((modifiers & 0x08) == 0x08) {
|
||||
value /= 10.0;
|
||||
*digits = 1;
|
||||
}
|
||||
|
||||
if ((modifiers & 0x40) == 0x40)
|
||||
value = INFINITY;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void mastech_ms6514_data(struct sr_dev_inst *sdi, const uint8_t *buf)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog analog;
|
||||
struct sr_analog_encoding encoding;
|
||||
struct sr_analog_meaning meaning;
|
||||
struct sr_analog_spec spec;
|
||||
struct sr_channel *ch;
|
||||
float value;
|
||||
int i, digits;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
if ((devc->data_source == DATA_SOURCE_MEMORY) && \
|
||||
(mastech_ms6514_data_source(buf) == DATA_SOURCE_LIVE)) {
|
||||
sr_dev_acquisition_stop(sdi);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MASTECH_MS6514_NUM_CHANNELS; i++) {
|
||||
ch = g_slist_nth_data(sdi->channels, i);
|
||||
if (!ch->enabled)
|
||||
continue;
|
||||
|
||||
value = mastech_ms6514_temperature(buf, i, &digits);
|
||||
sr_analog_init(&analog, &encoding, &meaning, &spec, digits);
|
||||
analog.num_samples = 1;
|
||||
analog.data = &value;
|
||||
analog.meaning->mq = SR_MQ_TEMPERATURE;
|
||||
analog.meaning->unit = mastech_ms6514_unit(buf);
|
||||
analog.meaning->mqflags = mastech_ms6514_flags(buf, i);
|
||||
|
||||
analog.meaning->channels = g_slist_append(NULL,
|
||||
g_slist_nth_data(sdi->channels,
|
||||
mastech_ms6514_channel_assignment(buf, i)));
|
||||
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &analog;
|
||||
sr_session_send(sdi, &packet);
|
||||
g_slist_free(analog.meaning->channels);
|
||||
}
|
||||
|
||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||
}
|
||||
|
||||
static const uint8_t *mastech_ms6514_parse_data(struct sr_dev_inst *sdi,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
if (len < MASTECH_MS6514_FRAME_SIZE)
|
||||
return NULL; /* Not enough data for a full packet. */
|
||||
|
||||
if (buf[0] != 0x65 || buf[1] != 0x14)
|
||||
return buf + 1; /* Try to re-synchronize on a packet start. */
|
||||
|
||||
if (buf[16] != 0x0D || buf[17] != 0x0A)
|
||||
return buf + MASTECH_MS6514_FRAME_SIZE; /* Valid start but no valid end -> skip. */
|
||||
|
||||
mastech_ms6514_data(sdi, buf);
|
||||
|
||||
return buf + MASTECH_MS6514_FRAME_SIZE;
|
||||
}
|
||||
|
||||
SR_PRIV int mastech_ms6514_receive_data(int fd, int revents, void *cb_data)
|
||||
{
|
||||
struct sr_dev_inst *sdi;
|
||||
struct dev_context *devc;
|
||||
struct sr_serial_dev_inst *serial;
|
||||
const uint8_t *ptr, *next_ptr, *end_ptr;
|
||||
int len;
|
||||
|
||||
(void)fd;
|
||||
|
||||
if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
|
||||
return TRUE;
|
||||
serial = sdi->conn;
|
||||
|
||||
/* Try to get as much data as the buffer can hold. */
|
||||
len = sizeof(devc->buf) - devc->buf_len;
|
||||
len = serial_read_nonblocking(serial, devc->buf + devc->buf_len, len);
|
||||
if (len < 1) {
|
||||
sr_err("Serial port read error: %d.", len);
|
||||
return FALSE;
|
||||
}
|
||||
devc->buf_len += len;
|
||||
|
||||
/* Now look for packets in that data. */
|
||||
ptr = devc->buf;
|
||||
end_ptr = ptr + devc->buf_len;
|
||||
while ((next_ptr = mastech_ms6514_parse_data(sdi, ptr, end_ptr - ptr)))
|
||||
ptr = next_ptr;
|
||||
|
||||
/* If we have any data left, move it to the beginning of our buffer. */
|
||||
memmove(devc->buf, ptr, end_ptr - ptr);
|
||||
devc->buf_len -= ptr - devc->buf;
|
||||
|
||||
/* If buffer is full and no valid packet was found, wipe buffer. */
|
||||
if (devc->buf_len >= sizeof(devc->buf)) {
|
||||
devc->buf_len = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (sr_sw_limits_check(&devc->limits)) {
|
||||
sr_dev_acquisition_stop(sdi);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2019 Dave Buechi <db@pflutsch.ch>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,21 +17,39 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
|
||||
#define LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
|
||||
#ifndef LIBSIGROK_HARDWARE_MASTECH_MS6514_PROTOCOL_H
|
||||
#define LIBSIGROK_HARDWARE_MASTECH_MS6514_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "victor-dmm"
|
||||
#define LOG_PREFIX "mastech-ms6514"
|
||||
|
||||
#define DMM_DATA_SIZE 14
|
||||
#define MASTECH_MS6514_NUM_CHANNELS 2
|
||||
#define MASTECH_MS6514_BUF_SIZE (3 * 18)
|
||||
#define MASTECH_MS6514_FRAME_SIZE 18
|
||||
#define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE
|
||||
|
||||
enum mastech_ms6614_data_source {
|
||||
DATA_SOURCE_LIVE,
|
||||
DATA_SOURCE_MEMORY,
|
||||
};
|
||||
|
||||
enum mastech_ms6614_command {
|
||||
CMD_GET_STORED = 0xA1
|
||||
};
|
||||
|
||||
struct dev_context {
|
||||
struct sr_sw_limits limits;
|
||||
enum mastech_ms6614_data_source data_source;
|
||||
unsigned int buf_len;
|
||||
uint8_t buf[MASTECH_MS6514_BUF_SIZE];
|
||||
unsigned int log_buf_len;
|
||||
};
|
||||
|
||||
SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf);
|
||||
SR_PRIV int mastech_ms6514_receive_data(int fd, int revents, void *cb_data);
|
||||
SR_PRIV gboolean mastech_ms6514_packet_valid(const uint8_t *buf);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* - Data acquisition works, but triggers either seem to not take effect,
|
||||
* or the trigger position is not in the expected spot according to the
|
||||
* user provided acquisition parameters. More research is required. The
|
||||
* bitmasks for enable/level/edge as well as the magic 16bit values for
|
||||
* position may need adjustment.
|
||||
* - The trigger position logic assumes that capture ratio specs are in
|
||||
* the range of 0-6%, which gets mapped to none/10%/50%/90%/+1W/+2W/+3W
|
||||
* choices. This avoids issues with applications which lack support for
|
||||
* non-contiguous discrete supported values, and values outside of the
|
||||
* 0-100% range. This is considered acceptable, to avoid the necessity
|
||||
* to extend common infrastructure to an unusual feature of a single
|
||||
* device of limited popularity. Just needs to get communicated to users.
|
||||
* - When a formula for the trigger position values in the SETUP packet
|
||||
* is found, the driver may accept arbitrary values between 0-100%, but
|
||||
* still could not express the "plus N windows" settings. Though that'd
|
||||
* be a rather useful feature considering the very short memory depth.
|
||||
* - The current implementation assumes externally provided Vdd, without
|
||||
* which input levels won't get detected. A future implementation could
|
||||
* optionally power Vdd from the PICkit2 itself, according to a user
|
||||
* provided configuration value.
|
||||
* - The current implementation silently accepts sample count limits beyond
|
||||
* 1024, just won't provide more than 1024 samples to the session. A
|
||||
* future implementation could cap the settings upon reception. Apps
|
||||
* like PulseView may not be able to specify 1024, and pass 1000 or
|
||||
* 2000 instead (the latter results in 1024 getting used).
|
||||
* - The manual suggests that users can assign names to devices. The
|
||||
* current implementation supports conn= specs with USB VID:PID pairs
|
||||
* or bus/address numbers. A future implementation could scan for user
|
||||
* assigned names as well (when the opcode to query the name was found).
|
||||
* - The "attach kernel driver" support code probably should move to a
|
||||
* common location, instead of getting repeated across several drivers.
|
||||
* - Diagnostics may benefit from cleanup.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <libusb.h>
|
||||
#include <string.h>
|
||||
#include "protocol.h"
|
||||
|
||||
#define PICKIT2_VENDOR_NAME "Microchip"
|
||||
#define PICKIT2_PRODUCT_NAME "PICkit2"
|
||||
|
||||
#define PICKIT2_DEFAULT_ADDRESS "04d8.0033"
|
||||
#define PICKIT2_USB_INTERFACE 0
|
||||
|
||||
static struct sr_dev_driver microchip_pickit2_driver_info;
|
||||
|
||||
static const char *channel_names[] = {
|
||||
"pin4", "pin5", "pin6",
|
||||
};
|
||||
|
||||
static const uint32_t scanopts[] = {
|
||||
SR_CONF_CONN,
|
||||
};
|
||||
|
||||
static const uint32_t drvopts[] = {
|
||||
SR_CONF_LOGIC_ANALYZER,
|
||||
};
|
||||
|
||||
static const uint32_t devopts[] = {
|
||||
SR_CONF_CONN | SR_CONF_GET,
|
||||
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
|
||||
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
};
|
||||
|
||||
static const int32_t trigger_matches[] = {
|
||||
SR_TRIGGER_ZERO,
|
||||
SR_TRIGGER_ONE,
|
||||
SR_TRIGGER_RISING,
|
||||
SR_TRIGGER_FALLING,
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that a list of 0, 10, 50, 90, 91, 92, 93, would have been nicer
|
||||
* from a user's perspective, but applications may not support a set of
|
||||
* discrete supported values, and 91+ is as much of a hack to work around
|
||||
* the "0-100%" limitation. So let's map those 0-6 "percent" to the vendor
|
||||
* app's 10/50/90/1W/2W/3W locations.
|
||||
*/
|
||||
static const uint64_t captureratios[] = {
|
||||
0, 1, 2, 3, 4, 5, 6,
|
||||
};
|
||||
|
||||
static const uint64_t samplerates[] = {
|
||||
SR_KHZ(5),
|
||||
SR_KHZ(10),
|
||||
SR_KHZ(25),
|
||||
SR_KHZ(50),
|
||||
SR_KHZ(100),
|
||||
SR_KHZ(250),
|
||||
SR_KHZ(500),
|
||||
SR_MHZ(1),
|
||||
};
|
||||
|
||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||
{
|
||||
struct drv_context *drvc;
|
||||
const char *conn;
|
||||
GSList *l, *devices, *usb_devices;
|
||||
struct sr_config *cfg;
|
||||
struct sr_usb_dev_inst *usb;
|
||||
struct sr_dev_inst *sdi;
|
||||
struct sr_channel_group *cg;
|
||||
size_t ch_count, ch_idx;
|
||||
struct sr_channel *ch;
|
||||
struct dev_context *devc;
|
||||
|
||||
drvc = di->context;
|
||||
|
||||
conn = PICKIT2_DEFAULT_ADDRESS;
|
||||
for (l = options; l; l = l->next) {
|
||||
cfg = l->data;
|
||||
switch (cfg->key) {
|
||||
case SR_CONF_CONN:
|
||||
conn = g_variant_get_string(cfg->data, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
devices = NULL;
|
||||
usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
|
||||
if (!usb_devices)
|
||||
return NULL;
|
||||
|
||||
for (l = usb_devices; l; l = l->next) {
|
||||
usb = l->data;
|
||||
|
||||
/* Create the device instance. */
|
||||
sdi = g_malloc0(sizeof(*sdi));
|
||||
devices = g_slist_append(devices, sdi);
|
||||
sdi->status = SR_ST_INACTIVE;
|
||||
sdi->vendor = g_strdup(PICKIT2_VENDOR_NAME);
|
||||
sdi->model = g_strdup(PICKIT2_PRODUCT_NAME);
|
||||
sdi->inst_type = SR_INST_USB;
|
||||
sdi->conn = usb;
|
||||
sdi->connection_id = g_strdup(conn);
|
||||
|
||||
/* Create the logic channels group. */
|
||||
cg = g_malloc0(sizeof(*cg));
|
||||
sdi->channel_groups = g_slist_append(NULL, cg);
|
||||
cg->name = g_strdup("Logic");
|
||||
ch_count = ARRAY_SIZE(channel_names);
|
||||
for (ch_idx = 0; ch_idx < ch_count; ch_idx++) {
|
||||
ch = sr_channel_new(sdi, ch_idx, SR_CHANNEL_LOGIC,
|
||||
TRUE, channel_names[ch_idx]);
|
||||
cg->channels = g_slist_append(cg->channels, ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the device context. Pre-select the highest
|
||||
* samplerate and the deepest sample count available.
|
||||
*/
|
||||
devc = g_malloc0(sizeof(*devc));
|
||||
sdi->priv = devc;
|
||||
devc->samplerates = samplerates;
|
||||
devc->num_samplerates = ARRAY_SIZE(samplerates);
|
||||
devc->curr_samplerate_idx = devc->num_samplerates - 1;
|
||||
devc->captureratios = captureratios;
|
||||
devc->num_captureratios = ARRAY_SIZE(captureratios);
|
||||
devc->curr_captureratio_idx = 0;
|
||||
devc->sw_limits.limit_samples = PICKIT2_SAMPLE_COUNT;
|
||||
}
|
||||
|
||||
return std_scan_complete(di, devices);
|
||||
}
|
||||
|
||||
static int dev_open(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_usb_dev_inst *usb;
|
||||
struct dev_context *devc;
|
||||
struct sr_dev_driver *di;
|
||||
struct drv_context *drvc;
|
||||
int ret;
|
||||
|
||||
usb = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
di = sdi->driver;
|
||||
drvc = di->context;
|
||||
|
||||
ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
|
||||
if (ret < 0)
|
||||
return SR_ERR;
|
||||
|
||||
if (libusb_kernel_driver_active(usb->devhdl, PICKIT2_USB_INTERFACE) == 1) {
|
||||
ret = libusb_detach_kernel_driver(usb->devhdl, PICKIT2_USB_INTERFACE);
|
||||
if (ret < 0) {
|
||||
sr_err("Canot detach kernel driver: %s.",
|
||||
libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
devc->detached_kernel_driver = TRUE;
|
||||
}
|
||||
|
||||
ret = libusb_claim_interface(usb->devhdl, PICKIT2_USB_INTERFACE);
|
||||
if (ret < 0) {
|
||||
sr_err("Cannot claim interface: %s.", libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_close(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_usb_dev_inst *usb;
|
||||
struct dev_context *devc;
|
||||
int ret;
|
||||
|
||||
usb = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
if (!usb)
|
||||
return SR_OK;
|
||||
if (!usb->devhdl)
|
||||
return SR_OK;
|
||||
|
||||
ret = libusb_release_interface(usb->devhdl, PICKIT2_USB_INTERFACE);
|
||||
if (ret) {
|
||||
sr_err("Cannot release interface: %s.", libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if (devc->detached_kernel_driver) {
|
||||
ret = libusb_attach_kernel_driver(usb->devhdl, PICKIT2_USB_INTERFACE);
|
||||
if (ret) {
|
||||
sr_err("Cannot attach kernel driver: %s.",
|
||||
libusb_error_name(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
devc->detached_kernel_driver = FALSE;
|
||||
}
|
||||
|
||||
libusb_close(usb->devhdl);
|
||||
sdi->conn = NULL;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int config_get(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_usb_dev_inst *usb;
|
||||
uint64_t rate, ratio;
|
||||
|
||||
(void)cg;
|
||||
|
||||
devc = sdi ? sdi->priv : NULL;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_CONN:
|
||||
if (!sdi->conn)
|
||||
return SR_ERR_ARG;
|
||||
usb = sdi->conn;
|
||||
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
|
||||
return SR_OK;
|
||||
case SR_CONF_SAMPLERATE:
|
||||
rate = devc->samplerates[devc->curr_samplerate_idx];
|
||||
*data = g_variant_new_uint64(rate);
|
||||
return SR_OK;
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
return sr_sw_limits_config_get(&devc->sw_limits, key, data);
|
||||
case SR_CONF_CAPTURE_RATIO:
|
||||
ratio = devc->captureratios[devc->curr_captureratio_idx];
|
||||
*data = g_variant_new_uint64(ratio);
|
||||
return SR_OK;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
}
|
||||
|
||||
static int config_set(uint32_t key, GVariant *data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
int idx;
|
||||
|
||||
(void)cg;
|
||||
|
||||
devc = sdi ? sdi->priv : NULL;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_SAMPLERATE:
|
||||
if (!devc)
|
||||
return SR_ERR_ARG;
|
||||
idx = std_u64_idx(data, devc->samplerates, devc->num_samplerates);
|
||||
if (idx < 0)
|
||||
return SR_ERR_ARG;
|
||||
devc->curr_samplerate_idx = idx;
|
||||
return SR_OK;
|
||||
case SR_CONF_CAPTURE_RATIO:
|
||||
if (!devc)
|
||||
return SR_ERR_ARG;
|
||||
idx = std_u64_idx(data, devc->captureratios, devc->num_captureratios);
|
||||
if (idx >= 0)
|
||||
devc->curr_captureratio_idx = idx;
|
||||
return SR_OK;
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
}
|
||||
|
||||
static int config_list(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
|
||||
devc = sdi ? sdi->priv : NULL;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_SCAN_OPTIONS:
|
||||
case SR_CONF_DEVICE_OPTIONS:
|
||||
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||
case SR_CONF_SAMPLERATE:
|
||||
if (!devc)
|
||||
return SR_ERR_NA;
|
||||
*data = std_gvar_samplerates(devc->samplerates, devc->num_samplerates);
|
||||
return SR_OK;
|
||||
case SR_CONF_TRIGGER_MATCH:
|
||||
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
|
||||
return SR_OK;
|
||||
case SR_CONF_CAPTURE_RATIO:
|
||||
*data = std_gvar_array_u64(ARRAY_AND_SIZE(captureratios));
|
||||
return SR_OK;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
}
|
||||
|
||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_trigger *trigger;
|
||||
struct sr_trigger_stage *stage;
|
||||
struct sr_trigger_match *match;
|
||||
GSList *l;
|
||||
size_t idx;
|
||||
int ret;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
/*
|
||||
* Query triggers, translate the more complex caller spec to
|
||||
* "flat" internal variables, to simplify the construction of
|
||||
* the SETUP packet elsewhere. This driver supports a single
|
||||
* stage, with match conditions for one or multiple channels.
|
||||
*/
|
||||
memset(&devc->triggers, 0, sizeof(devc->triggers));
|
||||
trigger = sr_session_trigger_get(sdi->session);
|
||||
if (trigger) {
|
||||
if (g_slist_length(trigger->stages) > 1)
|
||||
return SR_ERR_NA;
|
||||
stage = g_slist_nth_data(trigger->stages, 0);
|
||||
if (!stage)
|
||||
return SR_ERR_ARG;
|
||||
for (l = stage->matches; l; l = l->next) {
|
||||
match = l->data;
|
||||
if (!match->match)
|
||||
continue;
|
||||
if (!match->channel->enabled)
|
||||
continue;
|
||||
idx = match->channel->index;
|
||||
devc->triggers[idx] = match->match;
|
||||
}
|
||||
sr_dbg("acq start: trigger specs: %x/%x/%x",
|
||||
devc->triggers[0], devc->triggers[1],
|
||||
devc->triggers[2]);
|
||||
}
|
||||
devc->trigpos = trigger ? devc->curr_captureratio_idx : 0;
|
||||
|
||||
/* Have the SETUP packet sent, then poll for the status. */
|
||||
devc->state = STATE_CONF;
|
||||
ret = microchip_pickit2_setup_trigger(sdi);
|
||||
if (ret) {
|
||||
devc->state = STATE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
devc->state = STATE_WAIT;
|
||||
|
||||
std_session_send_df_header(sdi);
|
||||
sr_session_source_add(sdi->session, -1, 0, 20,
|
||||
microchip_pickit2_receive_data, (void *)sdi);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
|
||||
devc = sdi->priv;
|
||||
if (devc->state < STATE_CONF)
|
||||
return SR_OK;
|
||||
|
||||
/*
|
||||
* Keep up the acquisition until either data becomes available
|
||||
* (according to the previously configured trigger condition),
|
||||
* or until the user cancels the acquisition by pressing the
|
||||
* device's button. This is a firmware limitation which the
|
||||
* vendor software "suffers from" as well.
|
||||
*/
|
||||
if (devc->state == STATE_WAIT) {
|
||||
sr_err("Cannot terminate by software, need either data trigger or cancel button.");
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
if (devc->state > STATE_CONF) {
|
||||
std_session_send_df_end(sdi);
|
||||
}
|
||||
sr_session_source_remove(sdi->session, -1);
|
||||
devc->state = STATE_IDLE;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static struct sr_dev_driver microchip_pickit2_driver_info = {
|
||||
.name = "microchip-pickit2",
|
||||
.longname = PICKIT2_VENDOR_NAME " " PICKIT2_PRODUCT_NAME,
|
||||
.api_version = 1,
|
||||
.init = std_init,
|
||||
.cleanup = std_cleanup,
|
||||
.scan = scan,
|
||||
.dev_list = std_dev_list,
|
||||
.dev_clear = std_dev_clear,
|
||||
.config_get = config_get,
|
||||
.config_set = config_set,
|
||||
.config_list = config_list,
|
||||
.dev_open = dev_open,
|
||||
.dev_close = dev_close,
|
||||
.dev_acquisition_start = dev_acquisition_start,
|
||||
.dev_acquisition_stop = dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
SR_REGISTER_DEV_DRIVER(microchip_pickit2_driver_info);
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include "protocol.h"
|
||||
|
||||
#define PICKIT2_PACKET_LENGTH 64
|
||||
#define PICKIT2_USB_ENDPOINT 1
|
||||
#define PICKIT2_USB_TIMEOUT 250
|
||||
|
||||
#define PICKIT2_CMD_CHKSTAT 0xa2
|
||||
#define PICKIT2_CMD_CHKVOLT 0xa3
|
||||
#define PICKIT2_CMD_READ 0xac
|
||||
#define PICKIT2_CMD_PADCHAR 0xad
|
||||
#define PICKIT2_CMD_SETUP 0xb8
|
||||
#define PICKIT2_CMD_SETPOS 0xb9
|
||||
|
||||
#define PICKIT2_SEL_BANK0 0x06
|
||||
#define PICKIT2_SEL_BANK1 0x07
|
||||
|
||||
struct pickit2_cmd {
|
||||
size_t length;
|
||||
uint8_t raw[PICKIT2_PACKET_LENGTH];
|
||||
};
|
||||
|
||||
static void pickit2_cmd_clear(struct pickit2_cmd *cmd)
|
||||
{
|
||||
if (!cmd)
|
||||
return;
|
||||
memset(&cmd->raw[0], PICKIT2_CMD_PADCHAR, PICKIT2_PACKET_LENGTH);
|
||||
cmd->length = 0;
|
||||
}
|
||||
|
||||
static void pickit2_cmd_append(struct pickit2_cmd *cmd, uint8_t b)
|
||||
{
|
||||
if (!cmd)
|
||||
return;
|
||||
if (cmd->length == PICKIT2_PACKET_LENGTH)
|
||||
return;
|
||||
cmd->raw[cmd->length++] = b;
|
||||
}
|
||||
|
||||
static int pickit2_usb_send(const struct sr_dev_inst *sdi, struct pickit2_cmd *cmd)
|
||||
{
|
||||
struct sr_usb_dev_inst *usb;
|
||||
int ret, sent;
|
||||
GString *text;
|
||||
|
||||
if (!cmd)
|
||||
return SR_OK;
|
||||
usb = sdi->conn;
|
||||
if (!usb)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
text = sr_hexdump_new(&cmd->raw[0], cmd->length);
|
||||
sr_dbg("USB sent: %s", text->str);
|
||||
sr_hexdump_free(text);
|
||||
|
||||
ret = libusb_interrupt_transfer(usb->devhdl,
|
||||
LIBUSB_ENDPOINT_OUT | PICKIT2_USB_ENDPOINT,
|
||||
&cmd->raw[0], PICKIT2_PACKET_LENGTH,
|
||||
&sent, PICKIT2_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
sr_err("USB transmit error: %s.", libusb_error_name(ret));
|
||||
return SR_ERR_IO;
|
||||
}
|
||||
if (sent != PICKIT2_PACKET_LENGTH) {
|
||||
sr_err("USB short send: %d/%d bytes.",
|
||||
sent, PICKIT2_PACKET_LENGTH);
|
||||
return SR_ERR_IO;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int pickit2_usb_recv(const struct sr_dev_inst *sdi, struct pickit2_cmd *cmd)
|
||||
{
|
||||
struct sr_usb_dev_inst *usb;
|
||||
int ret, rcvd;
|
||||
GString *text;
|
||||
|
||||
if (!cmd)
|
||||
return SR_ERR_ARG;
|
||||
usb = sdi->conn;
|
||||
if (!usb)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
ret = libusb_interrupt_transfer(usb->devhdl,
|
||||
LIBUSB_ENDPOINT_IN | PICKIT2_USB_ENDPOINT,
|
||||
&cmd->raw[0], PICKIT2_PACKET_LENGTH,
|
||||
&rcvd, PICKIT2_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
if (ret == LIBUSB_ERROR_TIMEOUT)
|
||||
sr_dbg("USB receive error: %s.", libusb_error_name(ret));
|
||||
else
|
||||
sr_err("USB receive error: %s.", libusb_error_name(ret));
|
||||
return SR_ERR_IO;
|
||||
}
|
||||
|
||||
text = sr_hexdump_new(&cmd->raw[0], rcvd);
|
||||
sr_dbg("USB recv: %s", text->str);
|
||||
sr_hexdump_free(text);
|
||||
|
||||
cmd->length = rcvd;
|
||||
if (rcvd != PICKIT2_PACKET_LENGTH) {
|
||||
sr_err("USB short recv: %d/%d bytes.",
|
||||
rcvd, PICKIT2_PACKET_LENGTH);
|
||||
return SR_ERR_IO;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/* Send a request, (optionally) keep reading until response became available. */
|
||||
static int pickit2_usb_send_recv(const struct sr_dev_inst *sdi,
|
||||
struct pickit2_cmd *send_cmd, struct pickit2_cmd *recv_cmd, int do_wait)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Send the command when one got specified. Ignore errors. */
|
||||
if (send_cmd)
|
||||
(void)pickit2_usb_send(sdi, send_cmd);
|
||||
|
||||
/*
|
||||
* Try receiving data, always ignore errors. When requested by
|
||||
* the caller then keep receiving until response data became
|
||||
* available.
|
||||
*/
|
||||
if (!recv_cmd)
|
||||
return SR_OK;
|
||||
do {
|
||||
ret = pickit2_usb_recv(sdi, recv_cmd);
|
||||
if (ret == SR_OK)
|
||||
return SR_OK;
|
||||
if (!do_wait)
|
||||
return ret;
|
||||
} while (1);
|
||||
/* UNREACH */
|
||||
}
|
||||
|
||||
SR_PRIV int microchip_pickit2_setup_trigger(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
static const uint8_t trigger_channel_masks[PICKIT2_CHANNEL_COUNT] = {
|
||||
/* Bit positions for channels in trigger registers. */
|
||||
0x04, 0x08, 0x10,
|
||||
};
|
||||
static const uint16_t captureratio_magics[] = {
|
||||
/* TODO
|
||||
* How to exactly calculate these magic 16bit values?
|
||||
* They seem to neither match a percentage value nor a
|
||||
* sample count (assuming 1 window holds 1K samples).
|
||||
* As long as the formula is unknown, we are stuck with
|
||||
* looking up magic values from a table of few pre-sets.
|
||||
*/
|
||||
0x0000, /* unspecified ratio value */
|
||||
0x03cc, 0x000a, 0x0248, /* 10%/50%/90% in the first window */
|
||||
0x07b4, 0x0b9c, 0x0f84, /* 10% "plus 1/2/3 window widths" */
|
||||
};
|
||||
|
||||
struct dev_context *devc;
|
||||
uint8_t trig_en, trig_lvl, trig_edge, trig_rep, trig_div;
|
||||
uint16_t trig_pos;
|
||||
uint64_t rate;
|
||||
size_t trig_pos_idx, ch_idx;
|
||||
uint8_t ch_mask, ch_cond;
|
||||
struct pickit2_cmd cmd;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
/* Translate user specs to internal setup values. */
|
||||
trig_en = trig_lvl = trig_edge = 0;
|
||||
for (ch_idx = 0; ch_idx < PICKIT2_CHANNEL_COUNT; ch_idx++) {
|
||||
if (!devc->triggers[ch_idx])
|
||||
continue;
|
||||
ch_mask = trigger_channel_masks[ch_idx];
|
||||
ch_cond = devc->triggers[ch_idx];
|
||||
trig_en |= ch_mask;
|
||||
switch (ch_cond) {
|
||||
case SR_TRIGGER_ONE:
|
||||
case SR_TRIGGER_RISING:
|
||||
trig_lvl |= ch_mask;
|
||||
break;
|
||||
}
|
||||
switch (ch_cond) {
|
||||
case SR_TRIGGER_FALLING:
|
||||
case SR_TRIGGER_RISING:
|
||||
trig_edge |= ch_mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
trig_rep = 1;
|
||||
trig_rep = MIN(trig_rep, 255);
|
||||
trig_rep = MAX(trig_rep, 1);
|
||||
if (!trig_en)
|
||||
trig_rep = 0;
|
||||
rate = devc->samplerates[devc->curr_samplerate_idx];
|
||||
rate = SR_MHZ(1) / rate - 1;
|
||||
trig_div = rate & 0xff;
|
||||
trig_pos_idx = devc->trigpos;
|
||||
if (trig_pos_idx >= ARRAY_SIZE(captureratio_magics))
|
||||
trig_pos_idx = 0;
|
||||
trig_pos = captureratio_magics[trig_pos_idx];
|
||||
|
||||
/* Construct the SETUP packet. */
|
||||
pickit2_cmd_clear(&cmd);
|
||||
pickit2_cmd_append(&cmd, PICKIT2_CMD_SETUP);
|
||||
pickit2_cmd_append(&cmd, 0x01);
|
||||
pickit2_cmd_append(&cmd, trig_en);
|
||||
pickit2_cmd_append(&cmd, trig_lvl);
|
||||
pickit2_cmd_append(&cmd, trig_edge);
|
||||
pickit2_cmd_append(&cmd, trig_rep);
|
||||
pickit2_cmd_append(&cmd, trig_pos % 256);
|
||||
pickit2_cmd_append(&cmd, trig_pos / 256);
|
||||
pickit2_cmd_append(&cmd, trig_div);
|
||||
|
||||
/*
|
||||
* Transmit the SETUP packet. Only send it out, poll for the
|
||||
* response later. When a trigger is involved, the response may
|
||||
* take considerable amounts of time to arrive. We want apps
|
||||
* to remain responsive during that period of time.
|
||||
*/
|
||||
(void)pickit2_usb_send_recv(sdi, &cmd, NULL, FALSE);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/* Read specified bank data at given offset into caller provided buffer. */
|
||||
static int pickit2_retrieve_bank(struct sr_dev_inst *sdi,
|
||||
size_t bank_idx, size_t offset, uint8_t **buf, size_t *len)
|
||||
{
|
||||
struct pickit2_cmd send_cmd, recv_cmd;
|
||||
int ret;
|
||||
size_t copy_iter, copy_len;
|
||||
|
||||
/* Construct and send the SETPOS packet. No response expected. */
|
||||
pickit2_cmd_clear(&send_cmd);
|
||||
pickit2_cmd_append(&send_cmd, PICKIT2_CMD_SETPOS);
|
||||
pickit2_cmd_append(&send_cmd, offset & 0xff);
|
||||
pickit2_cmd_append(&send_cmd, PICKIT2_SEL_BANK0 + bank_idx);
|
||||
ret = pickit2_usb_send_recv(sdi, &send_cmd, NULL, FALSE);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
sr_dbg("read bank: pos set");
|
||||
|
||||
/* Run two READ cycles, get 2x 64 bytes => 128 bytes raw data. */
|
||||
pickit2_cmd_clear(&send_cmd);
|
||||
pickit2_cmd_append(&send_cmd, PICKIT2_CMD_READ);
|
||||
copy_iter = 2;
|
||||
while (copy_iter-- > 0) {
|
||||
ret = pickit2_usb_send_recv(sdi, &send_cmd, &recv_cmd, TRUE);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
copy_len = MIN(PICKIT2_PACKET_LENGTH, *len);
|
||||
memcpy(*buf, &recv_cmd.raw[0], copy_len);
|
||||
*buf += copy_len;
|
||||
*len -= copy_len;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/* Read all of the (banked, raw) sample data after acquisition completed. */
|
||||
static int pickit2_retrieve_sample_data(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
uint8_t *rdpos;
|
||||
size_t rdlen;
|
||||
int ret;
|
||||
|
||||
devc = sdi->priv;
|
||||
rdpos = &devc->samples_raw[0];
|
||||
rdlen = sizeof(devc->samples_raw);
|
||||
|
||||
ret = pickit2_retrieve_bank(sdi, 0, 0x00, &rdpos, &rdlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pickit2_retrieve_bank(sdi, 0, 0x80, &rdpos, &rdlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pickit2_retrieve_bank(sdi, 1, 0x00, &rdpos, &rdlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pickit2_retrieve_bank(sdi, 1, 0x80, &rdpos, &rdlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/* Send converted sample data to the sigrok session. */
|
||||
static int pickit2_submit_logic_data(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct {
|
||||
uint8_t raw_mask, conv_mask;
|
||||
} ch_map[PICKIT2_CHANNEL_COUNT] = {
|
||||
{ 0x04, 0x01, },
|
||||
{ 0x08, 0x02, },
|
||||
{ 0x01, 0x04, },
|
||||
};
|
||||
uint8_t *raw_buf, raw_byte, *conv_buf;
|
||||
size_t raw_len, conv_len;
|
||||
uint64_t limit;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_logic logic;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
/*
|
||||
* TODO Manipulate (or create) the above channel mapping table.
|
||||
* Remove disabled channels, create dense output format.
|
||||
* Could:
|
||||
* - Loop over the index, check the corresponding channel's
|
||||
* state, clear out the conv_mask part and shift down all
|
||||
* subsequent conv_mask parts.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convert raw dump (two samples per byte, at odd positions) to
|
||||
* internal sigrok format (one sample per byte, at increasing
|
||||
* offsets which start at 0).
|
||||
*/
|
||||
#define handle_nibble(n) do { \
|
||||
uint8_t conv_byte; \
|
||||
size_t ch_idx; \
|
||||
conv_byte = 0x00; \
|
||||
for (ch_idx = 0; ch_idx < PICKIT2_CHANNEL_COUNT; ch_idx++) { \
|
||||
if ((n) & ch_map[ch_idx].raw_mask) \
|
||||
conv_byte |= ch_map[ch_idx].conv_mask; \
|
||||
} \
|
||||
*conv_buf++ = conv_byte; \
|
||||
conv_len++; \
|
||||
} while (0)
|
||||
|
||||
raw_len = sizeof(devc->samples_raw);
|
||||
raw_buf = &devc->samples_raw[raw_len];
|
||||
conv_buf = &devc->samples_conv[0];
|
||||
conv_len = 0;
|
||||
while (raw_len-- > 0) {
|
||||
raw_byte = *(--raw_buf);
|
||||
handle_nibble((raw_byte >> 0) & 0x0f);
|
||||
handle_nibble((raw_byte >> 4) & 0x0f);
|
||||
}
|
||||
|
||||
/* Submit a logic packet to the sigrok session. */
|
||||
packet.type = SR_DF_LOGIC;
|
||||
packet.payload = &logic;
|
||||
logic.unitsize = sizeof(uint8_t);
|
||||
logic.data = &devc->samples_conv[0];
|
||||
logic.length = conv_len;
|
||||
limit = devc->sw_limits.limit_samples;
|
||||
if (limit && limit < logic.length)
|
||||
logic.length = limit;
|
||||
sr_session_send(sdi, &packet);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static gboolean pickit2_status_is_cancel(uint16_t status)
|
||||
{
|
||||
/* "Button press" and "transfer timeout" translate to "cancelled". */
|
||||
static const uint16_t status_cancel_mask = 0x4004;
|
||||
|
||||
sr_dbg("recv: status 0x%04x", status);
|
||||
if ((status & status_cancel_mask) == status_cancel_mask)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Periodically invoked poll routine, checking for incoming receive data. */
|
||||
SR_PRIV int microchip_pickit2_receive_data(int fd, int revents, void *cb_data)
|
||||
{
|
||||
struct sr_dev_inst *sdi;
|
||||
struct dev_context *devc;
|
||||
struct pickit2_cmd cmd;
|
||||
int ret;
|
||||
uint16_t status;
|
||||
|
||||
(void)fd;
|
||||
(void)revents;
|
||||
|
||||
sdi = cb_data;
|
||||
if (!sdi)
|
||||
return TRUE;
|
||||
devc = sdi->priv;
|
||||
if (!devc)
|
||||
return TRUE;
|
||||
|
||||
/* Waiting for the trigger condition? */
|
||||
if (devc->state == STATE_WAIT) {
|
||||
/* Keep waiting until status becomes available. */
|
||||
ret = pickit2_usb_send_recv(sdi, NULL, &cmd, FALSE);
|
||||
if (ret != SR_OK)
|
||||
return TRUE;
|
||||
/* Check status flags for cancel requests. */
|
||||
devc->state = STATE_DATA;
|
||||
status = RL16(&cmd.raw[0]);
|
||||
if (pickit2_status_is_cancel(status)) {
|
||||
sr_info("User cancelled acquisition.");
|
||||
sr_dev_acquisition_stop(sdi);
|
||||
return TRUE;
|
||||
}
|
||||
sr_dbg("recv: Data has become available.");
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve acquired sample data (blocking, acquisition has
|
||||
* completed and samples are few), and stop acquisition (have
|
||||
* the poll routine unregistered).
|
||||
*/
|
||||
ret = pickit2_retrieve_sample_data(sdi);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
ret = pickit2_submit_logic_data(sdi);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
sr_dev_acquisition_stop(sdi);
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBSIGROK_HARDWARE_MICROCHIP_PICKIT2_PROTOCOL_H
|
||||
#define LIBSIGROK_HARDWARE_MICROCHIP_PICKIT2_PROTOCOL_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "microchip-pickit2"
|
||||
|
||||
#define PICKIT2_CHANNEL_COUNT 3
|
||||
#define PICKIT2_SAMPLE_COUNT 1024
|
||||
#define PICKIT2_SAMPLE_RAWLEN (4 * 128)
|
||||
|
||||
enum pickit_state {
|
||||
STATE_IDLE,
|
||||
STATE_CONF,
|
||||
STATE_WAIT,
|
||||
STATE_DATA,
|
||||
};
|
||||
|
||||
struct dev_context {
|
||||
enum pickit_state state;
|
||||
const uint64_t *samplerates;
|
||||
size_t num_samplerates;
|
||||
size_t curr_samplerate_idx;
|
||||
const uint64_t *captureratios;
|
||||
size_t num_captureratios;
|
||||
size_t curr_captureratio_idx;
|
||||
struct sr_sw_limits sw_limits;
|
||||
gboolean detached_kernel_driver;
|
||||
int32_t triggers[PICKIT2_CHANNEL_COUNT]; /**@< see @ref SR_TRIGGER_ZERO et al */
|
||||
size_t trigpos;
|
||||
uint8_t samples_raw[PICKIT2_SAMPLE_RAWLEN];
|
||||
uint8_t samples_conv[PICKIT2_SAMPLE_COUNT];
|
||||
};
|
||||
|
||||
SR_PRIV int microchip_pickit2_setup_trigger(const struct sr_dev_inst *sdi);
|
||||
SR_PRIV int microchip_pickit2_receive_data(int fd, int revents, void *cb_data);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2019 Derek Hageman <hageman@inthat.cloud>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBSIGROK_HARDWARE_MOOSHIMETER_DMM_PROTOCOL_H
|
||||
#define LIBSIGROK_HARDWARE_MOOSHIMETER_DMM_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "mooshimeter-dmm"
|
||||
|
||||
struct packet_rx {
|
||||
int sequence_number;
|
||||
GSList *reorder_buffer;
|
||||
GByteArray *contents;
|
||||
};
|
||||
|
||||
struct packet_tx {
|
||||
int sequence_number;
|
||||
};
|
||||
|
||||
enum tree_node_datatype {
|
||||
TREE_NODE_DATATYPE_PLAIN = 0,
|
||||
TREE_NODE_DATATYPE_LINK,
|
||||
TREE_NODE_DATATYPE_CHOOSER,
|
||||
TREE_NODE_DATATYPE_U8,
|
||||
TREE_NODE_DATATYPE_U16,
|
||||
TREE_NODE_DATATYPE_U32,
|
||||
TREE_NODE_DATATYPE_S8,
|
||||
TREE_NODE_DATATYPE_S16,
|
||||
TREE_NODE_DATATYPE_S32,
|
||||
TREE_NODE_DATATYPE_STRING,
|
||||
TREE_NODE_DATATYPE_BINARY,
|
||||
TREE_NODE_DATATYPE_FLOAT,
|
||||
};
|
||||
|
||||
union tree_value {
|
||||
int32_t i;
|
||||
float f;
|
||||
GByteArray *b;
|
||||
};
|
||||
|
||||
struct config_tree_node {
|
||||
char *name;
|
||||
int id;
|
||||
size_t index_in_parent;
|
||||
|
||||
enum tree_node_datatype type;
|
||||
union tree_value value;
|
||||
|
||||
size_t count_children;
|
||||
struct config_tree_node *children;
|
||||
|
||||
uint32_t update_number;
|
||||
void (*on_update)(struct config_tree_node *node, void *param);
|
||||
void *on_update_param;
|
||||
};
|
||||
|
||||
struct dev_context {
|
||||
struct packet_rx rx;
|
||||
struct packet_tx tx;
|
||||
struct config_tree_node tree_root;
|
||||
struct config_tree_node *tree_id_lookup[0x7F];
|
||||
uint32_t buffer_bps[2];
|
||||
float buffer_lsb2native[2];
|
||||
|
||||
void (*channel_autorange[3])(const struct sr_dev_inst *sdi, float value);
|
||||
|
||||
struct sr_sw_limits limits;
|
||||
struct sr_analog_meaning channel_meaning[3];
|
||||
|
||||
gboolean enable_value_stream;
|
||||
};
|
||||
|
||||
SR_PRIV int mooshimeter_dmm_open(const struct sr_dev_inst *sdi);
|
||||
SR_PRIV int mooshimeter_dmm_close(const struct sr_dev_inst *sdi);
|
||||
SR_PRIV int mooshimeter_dmm_set_chooser(const struct sr_dev_inst *sdi, const char *path, const char *choice);
|
||||
SR_PRIV int mooshimeter_dmm_set_integer(const struct sr_dev_inst *sdi, const char *path, int value);
|
||||
SR_PRIV int mooshimeter_dmm_set_larger_number(const struct sr_dev_inst *sdi, const char *path, const char *parent, float number);
|
||||
SR_PRIV gboolean mooshimeter_dmm_set_autorange(const struct sr_dev_inst *sdi, const char *path, const char *parent, float latest);
|
||||
SR_PRIV int mooshimeter_dmm_get_chosen_number(const struct sr_dev_inst *sdi, const char *path, const char *parent, float *number);
|
||||
SR_PRIV int mooshimeter_dmm_get_available_number_choices(const struct sr_dev_inst *sdi, const char *path, float **numbers, size_t *count);
|
||||
SR_PRIV int mooshimeter_dmm_poll(int fd, int revents, void *cb_data);
|
||||
SR_PRIV int mooshimeter_dmm_heartbeat(int fd, int revents, void *cb_data);
|
||||
|
||||
#endif
|
|
@ -83,7 +83,7 @@ static const uint64_t samplerates[] = {
|
|||
SR_HZ(1),
|
||||
};
|
||||
|
||||
#define RESPONSE_DELAY_US (10 * 1000)
|
||||
#define RESPONSE_DELAY_US (20 * 1000)
|
||||
|
||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||
{
|
||||
|
@ -135,7 +135,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
|
||||
g_usleep(RESPONSE_DELAY_US);
|
||||
|
||||
if (sp_input_waiting(serial->data) == 0) {
|
||||
if (serial_has_receive_data(serial) == 0) {
|
||||
sr_dbg("Didn't get any reply.");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
|
||||
g_usleep(RESPONSE_DELAY_US);
|
||||
|
||||
if (sp_input_waiting(serial->data) != 0) {
|
||||
if (serial_has_receive_data(serial) != 0) {
|
||||
/* Got metadata. */
|
||||
sdi = get_metadata(serial);
|
||||
} else {
|
||||
|
@ -396,7 +396,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_serial_dev_inst *serial;
|
||||
uint16_t samplecount, readcount, delaycount;
|
||||
uint32_t samplecount, readcount, delaycount;
|
||||
uint8_t ols_changrp_mask, arg[4];
|
||||
int num_ols_changrp;
|
||||
int ret, i;
|
||||
|
@ -417,14 +417,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
|
||||
/*
|
||||
* Limit readcount to prevent reading past the end of the hardware
|
||||
* buffer.
|
||||
* buffer. Rather read too many samples than too few.
|
||||
*/
|
||||
samplecount = MIN(devc->max_samples / num_ols_changrp, devc->limit_samples);
|
||||
readcount = samplecount / 4;
|
||||
|
||||
/* Rather read too many samples than too few. */
|
||||
if (samplecount % 4 != 0)
|
||||
readcount++;
|
||||
readcount = (samplecount + 3) / 4;
|
||||
|
||||
/* Basic triggers. */
|
||||
if (ols_convert_trigger(sdi) != SR_OK) {
|
||||
|
@ -468,12 +464,28 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
/* Send sample limit and pre/post-trigger capture ratio. */
|
||||
sr_dbg("Setting sample limit %d, trigger point at %d",
|
||||
(readcount - 1) * 4, (delaycount - 1) * 4);
|
||||
arg[0] = ((readcount - 1) & 0xff);
|
||||
arg[1] = ((readcount - 1) & 0xff00) >> 8;
|
||||
arg[2] = ((delaycount - 1) & 0xff);
|
||||
arg[3] = ((delaycount - 1) & 0xff00) >> 8;
|
||||
if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK)
|
||||
return SR_ERR;
|
||||
|
||||
if (devc->max_samples > 256 * 1024) {
|
||||
arg[0] = ((readcount - 1) & 0xff);
|
||||
arg[1] = ((readcount - 1) & 0xff00) >> 8;
|
||||
arg[2] = ((readcount - 1) & 0xff0000) >> 16;
|
||||
arg[3] = ((readcount - 1) & 0xff000000) >> 24;
|
||||
if (send_longcommand(serial, CMD_CAPTURE_READCOUNT, arg) != SR_OK)
|
||||
return SR_ERR;
|
||||
arg[0] = ((delaycount - 1) & 0xff);
|
||||
arg[1] = ((delaycount - 1) & 0xff00) >> 8;
|
||||
arg[2] = ((delaycount - 1) & 0xff0000) >> 16;
|
||||
arg[3] = ((delaycount - 1) & 0xff000000) >> 24;
|
||||
if (send_longcommand(serial, CMD_CAPTURE_DELAYCOUNT, arg) != SR_OK)
|
||||
return SR_ERR;
|
||||
} else {
|
||||
arg[0] = ((readcount - 1) & 0xff);
|
||||
arg[1] = ((readcount - 1) & 0xff00) >> 8;
|
||||
arg[2] = ((delaycount - 1) & 0xff);
|
||||
arg[3] = ((delaycount - 1) & 0xff00) >> 8;
|
||||
if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK)
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
/* Flag register. */
|
||||
sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s",
|
||||
|
@ -523,7 +535,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
|
||||
static struct sr_dev_driver ols_driver_info = {
|
||||
.name = "ols",
|
||||
.longname = "Openbench Logic Sniffer",
|
||||
.longname = "Openbench Logic Sniffer & SUMP compatibles",
|
||||
.api_version = 1,
|
||||
.init = std_init,
|
||||
.cleanup = std_cleanup,
|
||||
|
|
|
@ -141,17 +141,50 @@ SR_PRIV struct dev_context *ols_dev_new(void)
|
|||
/* Acquisition settings */
|
||||
devc->limit_samples = devc->capture_ratio = 0;
|
||||
devc->trigger_at = -1;
|
||||
devc->channel_mask = 0xffffffff;
|
||||
devc->flag_reg = 0;
|
||||
|
||||
return devc;
|
||||
}
|
||||
|
||||
static void ols_channel_new(struct sr_dev_inst *sdi, int num_chan)
|
||||
{
|
||||
struct dev_context *devc = sdi->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_chan; i++)
|
||||
sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE,
|
||||
ols_channel_names[i]);
|
||||
|
||||
devc->max_channels = num_chan;
|
||||
}
|
||||
|
||||
static void metadata_quirks(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
gboolean is_shrimp;
|
||||
|
||||
if (!sdi)
|
||||
return;
|
||||
devc = sdi->priv;
|
||||
if (!devc)
|
||||
return;
|
||||
|
||||
is_shrimp = sdi->model && strcmp(sdi->model, "Shrimp1.0") == 0;
|
||||
if (is_shrimp) {
|
||||
if (!devc->max_channels)
|
||||
ols_channel_new(sdi, 4);
|
||||
if (!devc->max_samples)
|
||||
devc->max_samples = 256 * 1024;
|
||||
if (!devc->max_samplerate)
|
||||
devc->max_samplerate = SR_MHZ(20);
|
||||
}
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial)
|
||||
{
|
||||
struct sr_dev_inst *sdi;
|
||||
struct dev_context *devc;
|
||||
uint32_t tmp_int, ui;
|
||||
uint32_t tmp_int;
|
||||
uint8_t key, type, token;
|
||||
int delay_ms;
|
||||
GString *tmp_str, *devname, *version;
|
||||
|
@ -222,9 +255,7 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial)
|
|||
switch (token) {
|
||||
case 0x00:
|
||||
/* Number of usable channels */
|
||||
for (ui = 0; ui < tmp_int; ui++)
|
||||
sr_channel_new(sdi, ui, SR_CHANNEL_LOGIC, TRUE,
|
||||
ols_channel_names[ui]);
|
||||
ols_channel_new(sdi, tmp_int);
|
||||
break;
|
||||
case 0x01:
|
||||
/* Amount of sample memory available (bytes) */
|
||||
|
@ -258,9 +289,7 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial)
|
|||
switch (token) {
|
||||
case 0x00:
|
||||
/* Number of usable channels */
|
||||
for (ui = 0; ui < tmp_c; ui++)
|
||||
sr_channel_new(sdi, ui, SR_CHANNEL_LOGIC, TRUE,
|
||||
ols_channel_names[ui]);
|
||||
ols_channel_new(sdi, tmp_c);
|
||||
break;
|
||||
case 0x01:
|
||||
/* protocol version */
|
||||
|
@ -283,6 +312,9 @@ SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial)
|
|||
g_string_free(devname, FALSE);
|
||||
g_string_free(version, FALSE);
|
||||
|
||||
/* Optionally amend received metadata, model specific quirks. */
|
||||
metadata_quirks(sdi);
|
||||
|
||||
return sdi;
|
||||
}
|
||||
|
||||
|
@ -299,13 +331,11 @@ SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi,
|
|||
sr_info("Enabling demux mode.");
|
||||
devc->flag_reg |= FLAG_DEMUX;
|
||||
devc->flag_reg &= ~FLAG_FILTER;
|
||||
devc->max_channels = NUM_CHANNELS / 2;
|
||||
devc->cur_samplerate_divider = (CLOCK_RATE * 2 / samplerate) - 1;
|
||||
} else {
|
||||
sr_info("Disabling demux mode.");
|
||||
devc->flag_reg &= ~FLAG_DEMUX;
|
||||
devc->flag_reg |= FLAG_FILTER;
|
||||
devc->max_channels = NUM_CHANNELS;
|
||||
devc->cur_samplerate_divider = (CLOCK_RATE / samplerate) - 1;
|
||||
}
|
||||
|
||||
|
@ -366,7 +396,7 @@ SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data)
|
|||
}
|
||||
|
||||
num_ols_changrp = 0;
|
||||
for (i = NUM_CHANNELS; i > 0x02; i /= 2) {
|
||||
for (i = 0x20; i > 0x02; i >>= 1) {
|
||||
if ((devc->flag_reg & i) == 0) {
|
||||
num_ols_changrp++;
|
||||
}
|
||||
|
|
|
@ -28,9 +28,7 @@
|
|||
|
||||
#define LOG_PREFIX "openbench-logic-sniffer"
|
||||
|
||||
#define NUM_CHANNELS 32
|
||||
#define NUM_TRIGGER_STAGES 4
|
||||
#define SERIAL_SPEED B115200
|
||||
#define CLOCK_RATE SR_MHZ(100)
|
||||
#define MIN_NUM_SAMPLES 4
|
||||
#define DEFAULT_SAMPLERATE SR_KHZ(200)
|
||||
|
@ -38,12 +36,14 @@
|
|||
/* Command opcodes */
|
||||
#define CMD_RESET 0x00
|
||||
#define CMD_RUN 0x01
|
||||
#define CMD_TESTMODE 0x03
|
||||
#define CMD_ID 0x02
|
||||
#define CMD_TESTMODE 0x03
|
||||
#define CMD_METADATA 0x04
|
||||
#define CMD_SET_FLAGS 0x82
|
||||
#define CMD_SET_DIVIDER 0x80
|
||||
#define CMD_CAPTURE_SIZE 0x81
|
||||
#define CMD_SET_FLAGS 0x82
|
||||
#define CMD_CAPTURE_DELAYCOUNT 0x83 /* extension for Pepino */
|
||||
#define CMD_CAPTURE_READCOUNT 0x84 /* extension for Pepino */
|
||||
#define CMD_SET_TRIGGER_MASK 0xc0
|
||||
#define CMD_SET_TRIGGER_VALUE 0xc1
|
||||
#define CMD_SET_TRIGGER_CONFIG 0xc2
|
||||
|
|
|
@ -557,13 +557,13 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
arg[1] = ((readcount - 1) & 0xff00) >> 8;
|
||||
arg[2] = ((readcount - 1) & 0xff0000) >> 16;
|
||||
arg[3] = ((readcount - 1) & 0xff000000) >> 24;
|
||||
if (write_longcommand(devc, CMD_CAPTURE_DELAY, arg) != SR_OK)
|
||||
if (write_longcommand(devc, CMD_CAPTURE_READCOUNT, arg) != SR_OK)
|
||||
return SR_ERR;
|
||||
arg[0] = ((delaycount - 1) & 0xff);
|
||||
arg[1] = ((delaycount - 1) & 0xff00) >> 8;
|
||||
arg[2] = ((delaycount - 1) & 0xff0000) >> 16;
|
||||
arg[3] = ((delaycount - 1) & 0xff000000) >> 24;
|
||||
if (write_longcommand(devc, CMD_CAPTURE_COUNT, arg) != SR_OK)
|
||||
if (write_longcommand(devc, CMD_CAPTURE_DELAYCOUNT, arg) != SR_OK)
|
||||
return SR_ERR;
|
||||
|
||||
/* Flag register. */
|
||||
|
@ -636,7 +636,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_dev_driver p_ols_driver_info = {
|
||||
static struct sr_dev_driver p_ols_driver_info = {
|
||||
.name = "p-ols",
|
||||
.longname = "Pipistrello OLS",
|
||||
.api_version = 1,
|
||||
|
|
|
@ -49,8 +49,8 @@
|
|||
#define CMD_METADATA 0x04
|
||||
#define CMD_SET_DIVIDER 0x80
|
||||
#define CMD_SET_FLAGS 0x82
|
||||
#define CMD_CAPTURE_COUNT 0x83
|
||||
#define CMD_CAPTURE_DELAY 0x84
|
||||
#define CMD_CAPTURE_DELAYCOUNT 0x83
|
||||
#define CMD_CAPTURE_READCOUNT 0x84
|
||||
#define CMD_SET_TRIGGER_MASK 0xc0
|
||||
#define CMD_SET_TRIGGER_VALUE 0xc1
|
||||
#define CMD_SET_TRIGGER_CONFIG 0xc2
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 James Churchill <pelrun@gmail.com>
|
||||
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <math.h>
|
||||
#include "protocol.h"
|
||||
|
||||
static const uint32_t scanopts[] = {
|
||||
|
@ -48,12 +50,12 @@ static const uint32_t devopts[] = {
|
|||
|
||||
/* Model ID, model name, max current, max voltage, max power */
|
||||
static const struct rdtech_dps_model supported_models[] = {
|
||||
{ 3005, "DPS3005", 3, 50, 160 },
|
||||
{ 5005, "DPS5005", 5, 50, 250 },
|
||||
{ 5205, "DPH5005", 5, 50, 250 },
|
||||
{ 5015, "DPS5015", 15, 50, 750 },
|
||||
{ 5020, "DPS5020", 20, 50, 1000 },
|
||||
{ 8005, "DPS8005", 5, 80, 408 },
|
||||
{ 3005, "DPS3005", 5, 30, 160, 3, 2 },
|
||||
{ 5005, "DPS5005", 5, 50, 250, 3, 2 },
|
||||
{ 5205, "DPH5005", 5, 50, 250, 3, 2 },
|
||||
{ 5015, "DPS5015", 15, 50, 750, 2, 2 },
|
||||
{ 5020, "DPS5020", 20, 50, 1000, 2, 2 },
|
||||
{ 8005, "DPS8005", 5, 80, 408, 3, 2 },
|
||||
};
|
||||
|
||||
static struct sr_dev_driver rdtech_dps_driver_info;
|
||||
|
@ -95,7 +97,8 @@ static struct sr_dev_inst *probe_device(struct sr_modbus_dev_inst *modbus)
|
|||
devc = g_malloc0(sizeof(struct dev_context));
|
||||
sr_sw_limits_init(&devc->limits);
|
||||
devc->model = model;
|
||||
devc->expecting_registers = 0;
|
||||
devc->current_multiplier = pow(10.0, model->current_digits);
|
||||
devc->voltage_multiplier = pow(10.0, model->voltage_digits);
|
||||
|
||||
sdi->priv = devc;
|
||||
|
||||
|
@ -142,31 +145,20 @@ static int dev_open(struct sr_dev_inst *sdi)
|
|||
if (sr_modbus_open(modbus) < 0)
|
||||
return SR_ERR;
|
||||
|
||||
rdtech_dps_set_reg(modbus, REG_LOCK, 1);
|
||||
rdtech_dps_set_reg(sdi, REG_LOCK, 1);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_close(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
|
||||
modbus = sdi->conn;
|
||||
|
||||
if (!modbus)
|
||||
return SR_ERR_BUG;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
if (devc->expecting_registers) {
|
||||
/* Wait for the last data that was requested from the device. */
|
||||
uint16_t registers[devc->expecting_registers];
|
||||
sr_modbus_read_holding_registers(modbus, -1,
|
||||
devc->expecting_registers, registers);
|
||||
}
|
||||
|
||||
rdtech_dps_set_reg(modbus, REG_LOCK, 0);
|
||||
rdtech_dps_set_reg(sdi, REG_LOCK, 0);
|
||||
|
||||
return sr_modbus_close(modbus);
|
||||
}
|
||||
|
@ -175,13 +167,11 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
int ret;
|
||||
uint16_t ivalue;
|
||||
|
||||
(void)cg;
|
||||
|
||||
modbus = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
ret = SR_OK;
|
||||
|
@ -191,51 +181,51 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
ret = sr_sw_limits_config_get(&devc->limits, key, data);
|
||||
break;
|
||||
case SR_CONF_ENABLED:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_ENABLE, &ivalue)) == SR_OK)
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_ENABLE, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_boolean(ivalue);
|
||||
break;
|
||||
case SR_CONF_REGULATION:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_CV_CC, &ivalue)) != SR_OK)
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_CV_CC, &ivalue)) != SR_OK)
|
||||
break;
|
||||
*data = g_variant_new_string((ivalue == MODE_CC) ? "CC" : "CV");
|
||||
break;
|
||||
case SR_CONF_VOLTAGE:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_UOUT, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / 100.0f);
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_UOUT, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / devc->voltage_multiplier);
|
||||
break;
|
||||
case SR_CONF_VOLTAGE_TARGET:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_USET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / 100.0f);
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_USET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / devc->voltage_multiplier);
|
||||
break;
|
||||
case SR_CONF_CURRENT:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_IOUT, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / 100.0f);
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_IOUT, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / devc->current_multiplier);
|
||||
break;
|
||||
case SR_CONF_CURRENT_LIMIT:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_ISET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / 1000.0f);
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_ISET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / devc->current_multiplier);
|
||||
break;
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
|
||||
*data = g_variant_new_boolean(TRUE);
|
||||
break;
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_PROTECT, &ivalue)) == SR_OK)
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_PROTECT, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_boolean(ivalue == STATE_OVP);
|
||||
break;
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, PRE_OVPSET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / 100.0f);
|
||||
if ((ret = rdtech_dps_get_reg(sdi, PRE_OVPSET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / devc->voltage_multiplier);
|
||||
break;
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
|
||||
*data = g_variant_new_boolean(TRUE);
|
||||
break;
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, REG_PROTECT, &ivalue)) == SR_OK)
|
||||
if ((ret = rdtech_dps_get_reg(sdi, REG_PROTECT, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_boolean(ivalue == STATE_OCP);
|
||||
break;
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
|
||||
if ((ret = rdtech_dps_get_reg(modbus, PRE_OCPSET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / 1000.0f);
|
||||
if ((ret = rdtech_dps_get_reg(sdi, PRE_OCPSET, &ivalue)) == SR_OK)
|
||||
*data = g_variant_new_double((float)ivalue / devc->current_multiplier);
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
|
@ -248,11 +238,9 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
|
||||
(void)cg;
|
||||
|
||||
modbus = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
switch (key) {
|
||||
|
@ -260,15 +248,19 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
case SR_CONF_LIMIT_MSEC:
|
||||
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||
case SR_CONF_ENABLED:
|
||||
return rdtech_dps_set_reg(modbus, REG_ENABLE, g_variant_get_boolean(data));
|
||||
return rdtech_dps_set_reg(sdi, REG_ENABLE, g_variant_get_boolean(data));
|
||||
case SR_CONF_VOLTAGE_TARGET:
|
||||
return rdtech_dps_set_reg(modbus, REG_USET, g_variant_get_double(data) * 100);
|
||||
return rdtech_dps_set_reg(sdi, REG_USET,
|
||||
g_variant_get_double(data) * devc->voltage_multiplier);
|
||||
case SR_CONF_CURRENT_LIMIT:
|
||||
return rdtech_dps_set_reg(modbus, REG_ISET, g_variant_get_double(data) * 1000);
|
||||
return rdtech_dps_set_reg(sdi, REG_ISET,
|
||||
g_variant_get_double(data) * devc->current_multiplier);
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
|
||||
return rdtech_dps_set_reg(modbus, PRE_OVPSET, g_variant_get_double(data) * 100);
|
||||
return rdtech_dps_set_reg(sdi, PRE_OVPSET,
|
||||
g_variant_get_double(data) * devc->voltage_multiplier);
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
|
||||
return rdtech_dps_set_reg(modbus, PRE_OCPSET, g_variant_get_double(data) * 1000);
|
||||
return rdtech_dps_set_reg(sdi, PRE_OCPSET,
|
||||
g_variant_get_double(data) * devc->current_multiplier);
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -288,10 +280,12 @@ static int config_list(uint32_t key, GVariant **data,
|
|||
case SR_CONF_DEVICE_OPTIONS:
|
||||
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||
case SR_CONF_VOLTAGE_TARGET:
|
||||
*data = std_gvar_min_max_step(0.0, devc->model->max_voltage, 0.001);
|
||||
*data = std_gvar_min_max_step(0.0, devc->model->max_voltage,
|
||||
1 / devc->voltage_multiplier);
|
||||
break;
|
||||
case SR_CONF_CURRENT_LIMIT:
|
||||
*data = std_gvar_min_max_step(0.0, devc->model->max_current, 0.0001);
|
||||
*data = std_gvar_min_max_step(0.0, devc->model->max_current,
|
||||
1 / devc->current_multiplier);
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
|
@ -304,11 +298,21 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
uint16_t registers[3];
|
||||
int ret;
|
||||
|
||||
modbus = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
/* Prefill actual states */
|
||||
ret = rdtech_dps_read_holding_registers(modbus, REG_PROTECT, 3, registers);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
devc->actual_ovp_state = RB16(registers + 0) == STATE_OVP;
|
||||
devc->actual_ocp_state = RB16(registers + 0) == STATE_OCP;
|
||||
devc->actual_regulation_state = RB16(registers + 1);
|
||||
devc->actual_output_state = RB16(registers + 2);
|
||||
|
||||
if ((ret = sr_modbus_source_add(sdi->session, modbus, G_IO_IN, 10,
|
||||
rdtech_dps_receive_data, (void *)sdi)) != SR_OK)
|
||||
return ret;
|
||||
|
@ -316,7 +320,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
sr_sw_limits_acquisition_start(&devc->limits);
|
||||
std_session_send_df_header(sdi);
|
||||
|
||||
return rdtech_dps_capture_start(sdi);
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 James Churchill <pelrun@gmail.com>
|
||||
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,21 +21,55 @@
|
|||
#include <config.h>
|
||||
#include "protocol.h"
|
||||
|
||||
SR_PRIV int rdtech_dps_get_reg(struct sr_modbus_dev_inst *modbus,
|
||||
SR_PRIV int rdtech_dps_read_holding_registers(struct sr_modbus_dev_inst *modbus,
|
||||
int address, int nb_registers, uint16_t *registers)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
ret = sr_modbus_read_holding_registers(modbus,
|
||||
address, nb_registers, registers);
|
||||
++i;
|
||||
} while (ret != SR_OK && i < 3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SR_PRIV int rdtech_dps_get_reg(const struct sr_dev_inst *sdi,
|
||||
uint16_t address, uint16_t *value)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
uint16_t registers[1];
|
||||
int ret = sr_modbus_read_holding_registers(modbus, address, 1, registers);
|
||||
int ret;
|
||||
|
||||
devc = sdi->priv;
|
||||
modbus = sdi->conn;
|
||||
|
||||
g_mutex_lock(&devc->rw_mutex);
|
||||
ret = rdtech_dps_read_holding_registers(modbus, address, 1, registers);
|
||||
g_mutex_unlock(&devc->rw_mutex);
|
||||
*value = RB16(registers + 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SR_PRIV int rdtech_dps_set_reg(struct sr_modbus_dev_inst *modbus,
|
||||
SR_PRIV int rdtech_dps_set_reg(const struct sr_dev_inst *sdi,
|
||||
uint16_t address, uint16_t value)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
uint16_t registers[1];
|
||||
int ret;
|
||||
|
||||
devc = sdi->priv;
|
||||
modbus = sdi->conn;
|
||||
|
||||
WB16(registers, value);
|
||||
return sr_modbus_write_multiple_registers(modbus, address, 1, registers);
|
||||
g_mutex_lock(&devc->rw_mutex);
|
||||
ret = sr_modbus_write_multiple_registers(modbus, address, 1, registers);
|
||||
g_mutex_unlock(&devc->rw_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus,
|
||||
|
@ -42,7 +77,12 @@ SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus,
|
|||
{
|
||||
uint16_t registers[2];
|
||||
int ret;
|
||||
ret = sr_modbus_read_holding_registers(modbus, REG_MODEL, 2, registers);
|
||||
|
||||
/*
|
||||
* No mutex here, because there is no sr_dev_inst when this function
|
||||
* is called.
|
||||
*/
|
||||
ret = rdtech_dps_read_holding_registers(modbus, REG_MODEL, 2, registers);
|
||||
if (ret == SR_OK) {
|
||||
*model = RB16(registers + 0);
|
||||
*version = RB16(registers + 1);
|
||||
|
@ -52,7 +92,8 @@ SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus,
|
|||
}
|
||||
|
||||
static void send_value(const struct sr_dev_inst *sdi, struct sr_channel *ch,
|
||||
float value, enum sr_mq mq, enum sr_unit unit, int digits)
|
||||
float value, enum sr_mq mq, enum sr_mqflag mqflags,
|
||||
enum sr_unit unit, int digits)
|
||||
{
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog analog;
|
||||
|
@ -65,8 +106,8 @@ static void send_value(const struct sr_dev_inst *sdi, struct sr_channel *ch,
|
|||
analog.num_samples = 1;
|
||||
analog.data = &value;
|
||||
analog.meaning->mq = mq;
|
||||
analog.meaning->mqflags = mqflags;
|
||||
analog.meaning->unit = unit;
|
||||
analog.meaning->mqflags = SR_MQFLAG_DC;
|
||||
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &analog;
|
||||
|
@ -74,27 +115,14 @@ static void send_value(const struct sr_dev_inst *sdi, struct sr_channel *ch,
|
|||
g_slist_free(analog.meaning->channels);
|
||||
}
|
||||
|
||||
SR_PRIV int rdtech_dps_capture_start(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
int ret;
|
||||
|
||||
modbus = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
if ((ret = sr_modbus_read_holding_registers(modbus, REG_UOUT, 3, NULL)) == SR_OK)
|
||||
devc->expecting_registers = 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data)
|
||||
{
|
||||
struct sr_dev_inst *sdi;
|
||||
struct dev_context *devc;
|
||||
struct sr_modbus_dev_inst *modbus;
|
||||
struct sr_datafeed_packet packet;
|
||||
uint16_t registers[3];
|
||||
uint16_t registers[8];
|
||||
int ret;
|
||||
|
||||
(void)fd;
|
||||
(void)revents;
|
||||
|
@ -105,23 +133,57 @@ SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data)
|
|||
modbus = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
devc->expecting_registers = 0;
|
||||
if (sr_modbus_read_holding_registers(modbus, -1, 3, registers) == SR_OK) {
|
||||
g_mutex_lock(&devc->rw_mutex);
|
||||
/*
|
||||
* Using the libsigrok function here, because it doesn't matter if the
|
||||
* reading fails. It will be done again in the next acquision cycle anyways.
|
||||
*/
|
||||
ret = sr_modbus_read_holding_registers(modbus, REG_UOUT, 8, registers);
|
||||
g_mutex_unlock(&devc->rw_mutex);
|
||||
|
||||
if (ret == SR_OK) {
|
||||
/* Send channel values */
|
||||
packet.type = SR_DF_FRAME_BEGIN;
|
||||
sr_session_send(sdi, &packet);
|
||||
|
||||
send_value(sdi, sdi->channels->data,
|
||||
RB16(registers + 0) / 100.0f,
|
||||
SR_MQ_VOLTAGE, SR_UNIT_VOLT, 3);
|
||||
RB16(registers + 0) / devc->voltage_multiplier,
|
||||
SR_MQ_VOLTAGE, SR_MQFLAG_DC, SR_UNIT_VOLT,
|
||||
devc->model->voltage_digits);
|
||||
send_value(sdi, sdi->channels->next->data,
|
||||
RB16(registers + 1) / 1000.0f,
|
||||
SR_MQ_CURRENT, SR_UNIT_AMPERE, 4);
|
||||
RB16(registers + 1) / devc->current_multiplier,
|
||||
SR_MQ_CURRENT, SR_MQFLAG_DC, SR_UNIT_AMPERE,
|
||||
devc->model->current_digits);
|
||||
send_value(sdi, sdi->channels->next->next->data,
|
||||
RB16(registers + 2) / 100.0f,
|
||||
SR_MQ_POWER, SR_UNIT_WATT, 3);
|
||||
SR_MQ_POWER, 0, SR_UNIT_WATT, 2);
|
||||
|
||||
packet.type = SR_DF_FRAME_END;
|
||||
sr_session_send(sdi, &packet);
|
||||
|
||||
/* Check for state changes */
|
||||
if (devc->actual_ovp_state != (RB16(registers + 5) == STATE_OVP)) {
|
||||
devc->actual_ovp_state = RB16(registers + 5) == STATE_OVP;
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(devc->actual_ovp_state));
|
||||
}
|
||||
if (devc->actual_ocp_state != (RB16(registers + 5) == STATE_OCP)) {
|
||||
devc->actual_ocp_state = RB16(registers + 5) == STATE_OCP;
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(devc->actual_ocp_state));
|
||||
}
|
||||
if (devc->actual_regulation_state != RB16(registers + 6)) {
|
||||
devc->actual_regulation_state = RB16(registers + 6);
|
||||
sr_session_send_meta(sdi, SR_CONF_REGULATION,
|
||||
g_variant_new_string(
|
||||
devc->actual_regulation_state == MODE_CC ? "CC" : "CV"));
|
||||
}
|
||||
if (devc->actual_output_state != RB16(registers + 7)) {
|
||||
devc->actual_output_state = RB16(registers + 7);
|
||||
sr_session_send_meta(sdi, SR_CONF_ENABLED,
|
||||
g_variant_new_boolean(devc->actual_output_state));
|
||||
}
|
||||
|
||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||
}
|
||||
|
||||
|
@ -130,6 +192,5 @@ SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
rdtech_dps_capture_start(sdi);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 James Churchill <pelrun@gmail.com>
|
||||
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -33,12 +34,20 @@ struct rdtech_dps_model {
|
|||
unsigned int max_current;
|
||||
unsigned int max_voltage;
|
||||
unsigned int max_power;
|
||||
unsigned int current_digits;
|
||||
unsigned int voltage_digits;
|
||||
};
|
||||
|
||||
struct dev_context {
|
||||
const struct rdtech_dps_model *model;
|
||||
struct sr_sw_limits limits;
|
||||
int expecting_registers;
|
||||
GMutex rw_mutex;
|
||||
double current_multiplier;
|
||||
double voltage_multiplier;
|
||||
gboolean actual_ovp_state;
|
||||
gboolean actual_ocp_state;
|
||||
uint16_t actual_regulation_state;
|
||||
uint16_t actual_output_state;
|
||||
};
|
||||
|
||||
enum rdtech_dps_register {
|
||||
|
@ -84,13 +93,15 @@ enum rdtech_dps_mode {
|
|||
MODE_CC = 1,
|
||||
};
|
||||
|
||||
SR_PRIV int rdtech_dps_get_reg(struct sr_modbus_dev_inst *modbus, uint16_t address, uint16_t *value);
|
||||
SR_PRIV int rdtech_dps_set_reg(struct sr_modbus_dev_inst *modbus, uint16_t address, uint16_t value);
|
||||
SR_PRIV int rdtech_dps_read_holding_registers(struct sr_modbus_dev_inst *modbus,
|
||||
int address, int nb_registers, uint16_t *registers);
|
||||
|
||||
SR_PRIV int rdtech_dps_get_reg(const struct sr_dev_inst *sdi, uint16_t address, uint16_t *value);
|
||||
SR_PRIV int rdtech_dps_set_reg(const struct sr_dev_inst *sdi, uint16_t address, uint16_t value);
|
||||
|
||||
SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus,
|
||||
uint16_t *model, uint16_t *version);
|
||||
|
||||
SR_PRIV int rdtech_dps_capture_start(const struct sr_dev_inst *sdi);
|
||||
SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -180,8 +180,10 @@ enum series {
|
|||
DS2000,
|
||||
DS2000A,
|
||||
DSO1000,
|
||||
DSO1000B,
|
||||
DS1000Z,
|
||||
DS4000,
|
||||
MSO5000,
|
||||
MSO7000A,
|
||||
};
|
||||
|
||||
|
@ -205,10 +207,14 @@ static const struct rigol_ds_series supported_series[] = {
|
|||
{1000, 1}, {500, 1000000}, 14, 1400, 14000},
|
||||
[DSO1000] = {VENDOR(AGILENT), "DSO1000", PROTOCOL_V3, FORMAT_IEEE488_2,
|
||||
{50, 1}, {2, 1000}, 12, 600, 20480},
|
||||
[DSO1000B] = {VENDOR(AGILENT), "DSO1000", PROTOCOL_V3, FORMAT_IEEE488_2,
|
||||
{50, 1}, {2, 1000}, 12, 600, 20480},
|
||||
[DS1000Z] = {VENDOR(RIGOL), "DS1000Z", PROTOCOL_V4, FORMAT_IEEE488_2,
|
||||
{50, 1}, {1, 1000}, 12, 1200, 12000000},
|
||||
[DS4000] = {VENDOR(RIGOL), "DS4000", PROTOCOL_V4, FORMAT_IEEE488_2,
|
||||
{1000, 1}, {1, 1000}, 14, 1400, 14000},
|
||||
{1000, 1}, {1, 1000}, 14, 1400, 0},
|
||||
[MSO5000] = {VENDOR(RIGOL), "MSO5000", PROTOCOL_V5, FORMAT_IEEE488_2,
|
||||
{1000, 1}, {500, 1000000}, 10, 1000, 0},
|
||||
[MSO7000A] = {VENDOR(AGILENT), "MSO7000A", PROTOCOL_V4, FORMAT_IEEE488_2,
|
||||
{50, 1}, {2, 1000}, 10, 1000, 8000000},
|
||||
};
|
||||
|
@ -257,6 +263,10 @@ static const struct rigol_ds_model supported_models[] = {
|
|||
{SERIES(DSO1000), "DSO1014A", {2, 1000000000}, CH_INFO(4, false), std_cmd},
|
||||
{SERIES(DSO1000), "DSO1022A", {2, 1000000000}, CH_INFO(2, false), std_cmd},
|
||||
{SERIES(DSO1000), "DSO1024A", {2, 1000000000}, CH_INFO(4, false), std_cmd},
|
||||
{SERIES(DSO1000B), "DSO1052B", {2, 1000000000}, CH_INFO(2, false), std_cmd},
|
||||
{SERIES(DSO1000B), "DSO1072B", {2, 1000000000}, CH_INFO(2, false), std_cmd},
|
||||
{SERIES(DSO1000B), "DSO1102B", {2, 1000000000}, CH_INFO(2, false), std_cmd},
|
||||
{SERIES(DSO1000B), "DSO1152B", {2, 1000000000}, CH_INFO(2, false), std_cmd},
|
||||
{SERIES(DS1000Z), "DS1054Z", {5, 1000000000}, CH_INFO(4, false), std_cmd},
|
||||
{SERIES(DS1000Z), "DS1074Z", {5, 1000000000}, CH_INFO(4, false), std_cmd},
|
||||
{SERIES(DS1000Z), "DS1104Z", {5, 1000000000}, CH_INFO(4, false), std_cmd},
|
||||
|
@ -269,6 +279,12 @@ static const struct rigol_ds_model supported_models[] = {
|
|||
{SERIES(DS1000Z), "MSO1074Z-S", {5, 1000000000}, CH_INFO(4, true), std_cmd},
|
||||
{SERIES(DS1000Z), "MSO1104Z-S", {5, 1000000000}, CH_INFO(4, true), std_cmd},
|
||||
{SERIES(DS4000), "DS4024", {1, 1000000000}, CH_INFO(4, false), std_cmd},
|
||||
{SERIES(MSO5000), "MSO5072", {1, 1000000000}, CH_INFO(2, true), std_cmd},
|
||||
{SERIES(MSO5000), "MSO5074", {1, 1000000000}, CH_INFO(4, true), std_cmd},
|
||||
{SERIES(MSO5000), "MSO5102", {1, 1000000000}, CH_INFO(2, true), std_cmd},
|
||||
{SERIES(MSO5000), "MSO5104", {1, 1000000000}, CH_INFO(4, true), std_cmd},
|
||||
{SERIES(MSO5000), "MSO5204", {1, 1000000000}, CH_INFO(4, true), std_cmd},
|
||||
{SERIES(MSO5000), "MSO5354", {1, 1000000000}, CH_INFO(4, true), std_cmd},
|
||||
/* TODO: Digital channels are not yet supported on MSO7000A. */
|
||||
{SERIES(MSO7000A), "MSO7034A", {2, 1000000000}, CH_INFO(4, false), mso7000a_cmd},
|
||||
};
|
||||
|
@ -864,6 +880,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
struct sr_datafeed_packet packet;
|
||||
gboolean some_digital;
|
||||
GSList *l;
|
||||
char *cmd;
|
||||
|
||||
scpi = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
@ -906,9 +923,14 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
}
|
||||
if (ch->enabled != devc->digital_channels[ch->index]) {
|
||||
/* Enabled channel is currently disabled, or vice versa. */
|
||||
if (rigol_ds_config_set(sdi,
|
||||
devc->model->series->protocol >= PROTOCOL_V3 ?
|
||||
":LA:DIG%d:DISP %s" : ":DIG%d:TURN %s", ch->index,
|
||||
if (devc->model->series->protocol >= PROTOCOL_V5)
|
||||
cmd = ":LA:DISP D%d,%s";
|
||||
else if (devc->model->series->protocol >= PROTOCOL_V3)
|
||||
cmd = ":LA:DIG%d:DISP %s";
|
||||
else
|
||||
cmd = ":DIG%d:TURN %s";
|
||||
|
||||
if (rigol_ds_config_set(sdi, cmd, ch->index,
|
||||
ch->enabled ? "ON" : "OFF") != SR_OK)
|
||||
return SR_ERR;
|
||||
devc->digital_channels[ch->index] = ch->enabled;
|
||||
|
|
|
@ -333,6 +333,7 @@ SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi)
|
|||
struct dev_context *devc;
|
||||
gchar *trig_mode;
|
||||
unsigned int num_channels, i, j;
|
||||
int buffer_samples;
|
||||
|
||||
if (!(devc = sdi->priv))
|
||||
return SR_ERR;
|
||||
|
@ -369,6 +370,7 @@ SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi)
|
|||
break;
|
||||
case PROTOCOL_V3:
|
||||
case PROTOCOL_V4:
|
||||
case PROTOCOL_V5:
|
||||
if (rigol_ds_config_set(sdi, ":WAV:FORM BYTE") != SR_OK)
|
||||
return SR_ERR;
|
||||
if (devc->data_source == DATA_SOURCE_LIVE) {
|
||||
|
@ -381,7 +383,7 @@ SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi)
|
|||
if (devc->model->series->protocol == PROTOCOL_V3) {
|
||||
if (rigol_ds_config_set(sdi, ":WAV:MODE RAW") != SR_OK)
|
||||
return SR_ERR;
|
||||
} else if (devc->model->series->protocol == PROTOCOL_V4) {
|
||||
} else if (devc->model->series->protocol >= PROTOCOL_V4) {
|
||||
num_channels = 0;
|
||||
|
||||
/* Channels 3 and 4 are multiplexed with D0-7 and D8-15 */
|
||||
|
@ -398,12 +400,29 @@ SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi)
|
|||
}
|
||||
}
|
||||
|
||||
devc->analog_frame_size = devc->digital_frame_size =
|
||||
num_channels == 1 ?
|
||||
devc->model->series->buffer_samples :
|
||||
num_channels == 2 ?
|
||||
devc->model->series->buffer_samples / 2 :
|
||||
devc->model->series->buffer_samples / 4;
|
||||
buffer_samples = devc->model->series->buffer_samples;
|
||||
if (buffer_samples == 0)
|
||||
{
|
||||
/* The DS4000 series does not have a fixed memory depth, it
|
||||
* can be chosen from the menu and also varies with number
|
||||
* of active channels. Retrieve the actual number with the
|
||||
* ACQ:MDEP command. */
|
||||
sr_scpi_get_int(sdi->conn, "ACQ:MDEP?", &buffer_samples);
|
||||
devc->analog_frame_size = devc->digital_frame_size =
|
||||
buffer_samples;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The DS1000Z series has a fixed memory depth which we
|
||||
* need to divide correctly according to the number of
|
||||
* active channels. */
|
||||
devc->analog_frame_size = devc->digital_frame_size =
|
||||
num_channels == 1 ?
|
||||
buffer_samples :
|
||||
num_channels == 2 ?
|
||||
buffer_samples / 2 :
|
||||
buffer_samples / 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (rigol_ds_config_set(sdi, ":SING") != SR_OK)
|
||||
|
@ -459,6 +478,7 @@ SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi)
|
|||
}
|
||||
break;
|
||||
case PROTOCOL_V4:
|
||||
case PROTOCOL_V5:
|
||||
if (ch->type == SR_CHANNEL_ANALOG) {
|
||||
if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d",
|
||||
ch->index + 1) != SR_OK)
|
||||
|
@ -718,7 +738,7 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
|
|||
// TODO: For the MSO1000Z series, we need a way to express that
|
||||
// this data is in fact just for a single channel, with the valid
|
||||
// data for that channel in the LSB of each byte.
|
||||
logic.unitsize = devc->model->series->protocol == PROTOCOL_V4 ? 1 : 2;
|
||||
logic.unitsize = devc->model->series->protocol >= PROTOCOL_V4 ? 1 : 2;
|
||||
logic.data = devc->buffer;
|
||||
packet.type = SR_DF_LOGIC;
|
||||
packet.payload = &logic;
|
||||
|
@ -831,9 +851,12 @@ SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi)
|
|||
sr_dbg("Logic analyzer %s, current digital channel state:",
|
||||
devc->la_enabled ? "enabled" : "disabled");
|
||||
for (i = 0; i < ARRAY_SIZE(devc->digital_channels); i++) {
|
||||
cmd = g_strdup_printf(
|
||||
devc->model->series->protocol >= PROTOCOL_V3 ?
|
||||
":LA:DIG%d:DISP?" : ":DIG%d:TURN?", i);
|
||||
if (devc->model->series->protocol >= PROTOCOL_V5)
|
||||
cmd = g_strdup_printf(":LA:DISP? D%d", i);
|
||||
else if (devc->model->series->protocol >= PROTOCOL_V3)
|
||||
cmd = g_strdup_printf(":LA:DIG%d:DISP?", i);
|
||||
else
|
||||
cmd = g_strdup_printf(":DIG%d:TURN?", i);
|
||||
res = sr_scpi_get_bool(sdi->conn, cmd, &devc->digital_channels[i]);
|
||||
g_free(cmd);
|
||||
if (res != SR_OK)
|
||||
|
|
|
@ -42,6 +42,7 @@ enum protocol_version {
|
|||
PROTOCOL_V2, /* DS1000 */
|
||||
PROTOCOL_V3, /* DS2000, DSO1000 */
|
||||
PROTOCOL_V4, /* DS1000Z */
|
||||
PROTOCOL_V5, /* MSO5000 */
|
||||
};
|
||||
|
||||
enum data_format {
|
||||
|
|
|
@ -18,13 +18,12 @@
|
|||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <libserialport.h>
|
||||
#include <scpi.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "protocol.h"
|
||||
|
||||
SR_PRIV struct sr_dev_driver rohde_schwarz_sme_0x_driver_info;
|
||||
static struct sr_dev_driver rohde_schwarz_sme_0x_driver_info;
|
||||
|
||||
static const char *manufacturer = "Rohde&Schwarz";
|
||||
|
||||
|
@ -220,7 +219,7 @@ static int config_list(uint32_t key, GVariant **data,
|
|||
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_dev_driver rohde_schwarz_sme_0x_driver_info = {
|
||||
static struct sr_dev_driver rohde_schwarz_sme_0x_driver_info = {
|
||||
.name = "rohde-schwarz-sme-0x",
|
||||
.longname = "Rohde&Schwarz SME-0x",
|
||||
.api_version = 1,
|
||||
|
@ -238,5 +237,4 @@ SR_PRIV struct sr_dev_driver rohde_schwarz_sme_0x_driver_info = {
|
|||
.dev_acquisition_stop = std_serial_dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
|
||||
SR_REGISTER_DEV_DRIVER(rohde_schwarz_sme_0x_driver_info);
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
#define BUF_SIZE (16 * 1024)
|
||||
#define BUF_TIMEOUT 1000
|
||||
|
||||
SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info;
|
||||
|
||||
static const uint32_t scanopts[] = {
|
||||
SR_CONF_CONN,
|
||||
};
|
||||
|
@ -459,7 +457,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info = {
|
||||
static struct sr_dev_driver saleae_logic_pro_driver_info = {
|
||||
.name = "saleae-logic-pro",
|
||||
.longname = "Saleae Logic Pro",
|
||||
.api_version = 1,
|
||||
|
@ -477,5 +475,4 @@ SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info = {
|
|||
.dev_acquisition_stop = dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
|
||||
SR_REGISTER_DEV_DRIVER(saleae_logic_pro_driver_info);
|
||||
|
|
|
@ -428,8 +428,7 @@ static int prime_fpga(const struct sr_dev_inst *sdi)
|
|||
return ret;
|
||||
|
||||
if (version != 0x10 && version != 0x13 && version != 0x40 && version != 0x41) {
|
||||
sr_err("Unsupported FPGA version: 0x%02x.", version);
|
||||
return SR_ERR;
|
||||
sr_warn("Unsupported FPGA version: 0x%02x.", version);
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
|
|
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "protocol.h"
|
||||
|
||||
static struct sr_dev_driver scpi_dmm_driver_info;
|
||||
|
||||
static const uint32_t scanopts[] = {
|
||||
SR_CONF_CONN,
|
||||
SR_CONF_SERIALCOMM,
|
||||
};
|
||||
|
||||
static const uint32_t drvopts[] = {
|
||||
SR_CONF_MULTIMETER,
|
||||
};
|
||||
|
||||
static const uint32_t devopts_generic[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_MEASURED_QUANTITY | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
};
|
||||
|
||||
static const struct scpi_command cmdset_agilent[] = {
|
||||
{ DMM_CMD_SETUP_REMOTE, "\n", },
|
||||
{ DMM_CMD_SETUP_FUNC, "CONF:%s", },
|
||||
{ DMM_CMD_QUERY_FUNC, "CONF?", },
|
||||
{ DMM_CMD_START_ACQ, "MEAS", },
|
||||
{ DMM_CMD_STOP_ACQ, "ABORT", },
|
||||
{ DMM_CMD_QUERY_VALUE, "READ?", },
|
||||
{ DMM_CMD_QUERY_PREC, "CONF?", },
|
||||
ALL_ZERO,
|
||||
};
|
||||
|
||||
/*
|
||||
* cmdset_hp is used for the 34401A, which was added to this code after the
|
||||
* 34405A and 34465A. It differs in starting the measurement with INIT: using
|
||||
* MEAS without a trailing '?' (as used for the 34405A) is not valid for the
|
||||
* 34401A and gives an error.
|
||||
* I'm surprised the same instruction sequence doesn't work and INIT may
|
||||
* work for both, but I don't have the others to re-test.
|
||||
*
|
||||
* On the 34401A,
|
||||
* MEAS <optional parameters> ? configures, arms, triggers and waits
|
||||
* for a reading
|
||||
* CONF <parameters> configures
|
||||
* INIT prepares for triggering (trigger mode is not set, assumed
|
||||
* internal - external might time out)
|
||||
* *OPC waits for completion, and
|
||||
* READ? retrieves the result
|
||||
*/
|
||||
static const struct scpi_command cmdset_hp[] = {
|
||||
{ DMM_CMD_SETUP_REMOTE, "\n", },
|
||||
{ DMM_CMD_SETUP_FUNC, "CONF:%s", },
|
||||
{ DMM_CMD_QUERY_FUNC, "CONF?", },
|
||||
{ DMM_CMD_START_ACQ, "INIT", },
|
||||
{ DMM_CMD_STOP_ACQ, "ABORT", },
|
||||
{ DMM_CMD_QUERY_VALUE, "READ?", },
|
||||
{ DMM_CMD_QUERY_PREC, "CONF?", },
|
||||
ALL_ZERO,
|
||||
};
|
||||
|
||||
static const struct mqopt_item mqopts_agilent_34405a[] = {
|
||||
{ SR_MQ_VOLTAGE, SR_MQFLAG_DC, "VOLT:DC", "VOLT ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_VOLTAGE, SR_MQFLAG_AC, "VOLT:AC", "VOLT:AC ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_CURRENT, SR_MQFLAG_DC, "CURR:DC", "CURR ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_CURRENT, SR_MQFLAG_AC, "CURR:AC", "CURR:AC ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_RESISTANCE, 0, "RES", "RES ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_CONTINUITY, 0, "CONT", "CONT", -1, },
|
||||
{ SR_MQ_CAPACITANCE, 0, "CAP", "CAP ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_VOLTAGE, SR_MQFLAG_DC | SR_MQFLAG_DIODE, "DIOD", "DIOD", -4, },
|
||||
{ SR_MQ_TEMPERATURE, 0, "TEMP", "TEMP ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_FREQUENCY, 0, "FREQ", "FREQ ", NO_DFLT_PREC, },
|
||||
};
|
||||
|
||||
static const struct mqopt_item mqopts_agilent_34401a[] = {
|
||||
{ SR_MQ_VOLTAGE, SR_MQFLAG_DC, "VOLT:DC", "VOLT ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_VOLTAGE, SR_MQFLAG_AC, "VOLT:AC", "VOLT:AC ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_CURRENT, SR_MQFLAG_DC, "CURR:DC", "CURR ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_CURRENT, SR_MQFLAG_AC, "CURR:AC", "CURR:AC ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_RESISTANCE, 0, "RES", "RES ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE, "FRES", "FRES ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_CONTINUITY, 0, "CONT", "CONT", -1, },
|
||||
{ SR_MQ_VOLTAGE, SR_MQFLAG_DC | SR_MQFLAG_DIODE, "DIOD", "DIOD", -4, },
|
||||
{ SR_MQ_FREQUENCY, 0, "FREQ", "FREQ ", NO_DFLT_PREC, },
|
||||
{ SR_MQ_TIME, 0, "PER", "PER ", NO_DFLT_PREC, },
|
||||
};
|
||||
|
||||
SR_PRIV const struct scpi_dmm_model models[] = {
|
||||
{
|
||||
"Agilent", "34405A",
|
||||
1, 5, cmdset_agilent, ARRAY_AND_SIZE(mqopts_agilent_34405a),
|
||||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
0,
|
||||
},
|
||||
{
|
||||
"Keysight", "34465A",
|
||||
1, 5, cmdset_agilent, ARRAY_AND_SIZE(mqopts_agilent_34405a),
|
||||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
0,
|
||||
},
|
||||
{
|
||||
"HP", "34401A",
|
||||
1, 6, cmdset_hp, ARRAY_AND_SIZE(mqopts_agilent_34401a),
|
||||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
/* 34401A: typ. 1020ms for AC readings (default is 1000ms). */
|
||||
1000 * 1500,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct scpi_dmm_model *is_compatible(const char *vendor, const char *model)
|
||||
{
|
||||
size_t i;
|
||||
const struct scpi_dmm_model *entry;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(models); i++) {
|
||||
entry = &models[i];
|
||||
if (!entry->vendor || !entry->model)
|
||||
continue;
|
||||
if (strcmp(vendor, entry->vendor) != 0)
|
||||
continue;
|
||||
if (strcmp(model, entry->model) != 0)
|
||||
continue;
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
||||
{
|
||||
struct sr_scpi_hw_info *hw_info;
|
||||
int ret;
|
||||
const char *vendor;
|
||||
const struct scpi_dmm_model *model;
|
||||
struct sr_dev_inst *sdi;
|
||||
struct dev_context *devc;
|
||||
size_t i;
|
||||
gchar *channel_name;
|
||||
|
||||
scpi_dmm_cmd_delay(scpi);
|
||||
ret = sr_scpi_get_hw_id(scpi, &hw_info);
|
||||
if (ret != SR_OK) {
|
||||
sr_info("Could not get IDN response.");
|
||||
return NULL;
|
||||
}
|
||||
vendor = sr_vendor_alias(hw_info->manufacturer);
|
||||
model = is_compatible(vendor, hw_info->model);
|
||||
if (!model) {
|
||||
sr_scpi_hw_info_free(hw_info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sdi = g_malloc0(sizeof(*sdi));
|
||||
sdi->vendor = g_strdup(hw_info->manufacturer);
|
||||
sdi->model = g_strdup(hw_info->model);
|
||||
sdi->version = g_strdup(hw_info->firmware_version);
|
||||
sdi->serial_num = g_strdup(hw_info->serial_number);
|
||||
sdi->conn = scpi;
|
||||
sdi->driver = &scpi_dmm_driver_info;
|
||||
sdi->inst_type = SR_INST_SCPI;
|
||||
sr_scpi_hw_info_free(hw_info);
|
||||
if (model->read_timeout_us) /* non-default read timeout */
|
||||
scpi->read_timeout_us = model->read_timeout_us;
|
||||
devc = g_malloc0(sizeof(*devc));
|
||||
sdi->priv = devc;
|
||||
devc->num_channels = model->num_channels;
|
||||
devc->cmdset = model->cmdset;
|
||||
devc->model = model;
|
||||
|
||||
for (i = 0; i < devc->num_channels; i++) {
|
||||
channel_name = g_strdup_printf("P%zu", i + 1);
|
||||
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, channel_name);
|
||||
}
|
||||
|
||||
return sdi;
|
||||
}
|
||||
|
||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||
{
|
||||
return sr_scpi_scan(di->context, options, probe_device);
|
||||
}
|
||||
|
||||
static int dev_open(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
int ret;
|
||||
|
||||
scpi = sdi->conn;
|
||||
ret = sr_scpi_open(scpi);
|
||||
if (ret < 0) {
|
||||
sr_err("Failed to open SCPI device: %s.", sr_strerror(ret));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_close(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
|
||||
scpi = sdi->conn;
|
||||
if (!scpi)
|
||||
return SR_ERR_BUG;
|
||||
|
||||
sr_dbg("DIAG: sdi->status %d.", sdi->status - SR_ST_NOT_FOUND);
|
||||
if (sdi->status <= SR_ST_INACTIVE)
|
||||
return SR_OK;
|
||||
|
||||
return sr_scpi_close(scpi);
|
||||
}
|
||||
|
||||
static int config_get(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
enum sr_mq mq;
|
||||
enum sr_mqflag mqflag;
|
||||
GVariant *arr[2];
|
||||
int ret;
|
||||
|
||||
(void)cg;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
case SR_CONF_LIMIT_MSEC:
|
||||
return sr_sw_limits_config_get(&devc->limits, key, data);
|
||||
case SR_CONF_MEASURED_QUANTITY:
|
||||
ret = scpi_dmm_get_mq(sdi, &mq, &mqflag, NULL, NULL);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
arr[0] = g_variant_new_uint32(mq);
|
||||
arr[1] = g_variant_new_uint64(mqflag);
|
||||
*data = g_variant_new_tuple(arr, ARRAY_SIZE(arr));
|
||||
return SR_OK;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
}
|
||||
|
||||
static int config_set(uint32_t key, GVariant *data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
enum sr_mq mq;
|
||||
enum sr_mqflag mqflag;
|
||||
GVariant *tuple_child;
|
||||
|
||||
(void)cg;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_LIMIT_SAMPLES:
|
||||
case SR_CONF_LIMIT_MSEC:
|
||||
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||
case SR_CONF_MEASURED_QUANTITY:
|
||||
tuple_child = g_variant_get_child_value(data, 0);
|
||||
mq = g_variant_get_uint32(tuple_child);
|
||||
tuple_child = g_variant_get_child_value(data, 1);
|
||||
mqflag = g_variant_get_uint64(tuple_child);
|
||||
g_variant_unref(tuple_child);
|
||||
return scpi_dmm_set_mq(sdi, mq, mqflag);
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
}
|
||||
|
||||
static int config_list(uint32_t key, GVariant **data,
|
||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
GVariant *gvar, *arr[2];
|
||||
GVariantBuilder gvb;
|
||||
size_t i;
|
||||
|
||||
(void)cg;
|
||||
|
||||
devc = sdi ? sdi->priv : NULL;
|
||||
|
||||
switch (key) {
|
||||
case SR_CONF_SCAN_OPTIONS:
|
||||
case SR_CONF_DEVICE_OPTIONS:
|
||||
if (!devc)
|
||||
return STD_CONFIG_LIST(key, data, sdi, cg,
|
||||
scanopts, drvopts, devopts_generic);
|
||||
return std_opts_config_list(key, data, sdi, cg,
|
||||
ARRAY_AND_SIZE(scanopts), ARRAY_AND_SIZE(drvopts),
|
||||
devc->model->devopts, devc->model->devopts_size);
|
||||
case SR_CONF_MEASURED_QUANTITY:
|
||||
/* TODO Use std_gvar_measured_quantities() when available. */
|
||||
if (!devc)
|
||||
return SR_ERR_ARG;
|
||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
||||
for (i = 0; i < devc->model->mqopt_size; i++) {
|
||||
arr[0] = g_variant_new_uint32(devc->model->mqopts[i].mq);
|
||||
arr[1] = g_variant_new_uint64(devc->model->mqopts[i].mqflag);
|
||||
gvar = g_variant_new_tuple(arr, ARRAY_SIZE(arr));
|
||||
g_variant_builder_add_value(&gvb, gvar);
|
||||
}
|
||||
*data = g_variant_builder_end(&gvb);
|
||||
return SR_OK;
|
||||
default:
|
||||
(void)devc;
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
}
|
||||
|
||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
struct dev_context *devc;
|
||||
int ret;
|
||||
const struct mqopt_item *item;
|
||||
const char *command;
|
||||
|
||||
scpi = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
ret = scpi_dmm_get_mq(sdi, &devc->start_acq_mq.curr_mq,
|
||||
&devc->start_acq_mq.curr_mqflag, NULL, &item);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_START_ACQ);
|
||||
if (command && *command) {
|
||||
scpi_dmm_cmd_delay(scpi);
|
||||
ret = sr_scpi_send(scpi, command);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sr_sw_limits_acquisition_start(&devc->limits);
|
||||
ret = std_session_send_df_header(sdi);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 10,
|
||||
scpi_dmm_receive_data, (void *)sdi);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
struct dev_context *devc;
|
||||
const char *command;
|
||||
|
||||
scpi = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
|
||||
command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_STOP_ACQ);
|
||||
if (command && *command) {
|
||||
scpi_dmm_cmd_delay(scpi);
|
||||
(void)sr_scpi_send(scpi, command);
|
||||
}
|
||||
sr_scpi_source_remove(sdi->session, scpi);
|
||||
|
||||
std_session_send_df_end(sdi);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static struct sr_dev_driver scpi_dmm_driver_info = {
|
||||
.name = "scpi-dmm",
|
||||
.longname = "SCPI DMM",
|
||||
.api_version = 1,
|
||||
.init = std_init,
|
||||
.cleanup = std_cleanup,
|
||||
.scan = scan,
|
||||
.dev_list = std_dev_list,
|
||||
.dev_clear = std_dev_clear,
|
||||
.config_get = config_get,
|
||||
.config_set = config_set,
|
||||
.config_list = config_list,
|
||||
.dev_open = dev_open,
|
||||
.dev_close = dev_close,
|
||||
.dev_acquisition_start = dev_acquisition_start,
|
||||
.dev_acquisition_stop = dev_acquisition_stop,
|
||||
.context = NULL,
|
||||
};
|
||||
SR_REGISTER_DEV_DRIVER(scpi_dmm_driver_info);
|
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "protocol.h"
|
||||
|
||||
#define WITH_CMD_DELAY 0 /* TODO See which devices need delays. */
|
||||
|
||||
SR_PRIV void scpi_dmm_cmd_delay(struct sr_scpi_dev_inst *scpi)
|
||||
{
|
||||
if (WITH_CMD_DELAY)
|
||||
g_usleep(WITH_CMD_DELAY * 1000);
|
||||
sr_scpi_get_opc(scpi);
|
||||
}
|
||||
|
||||
SR_PRIV const struct mqopt_item *scpi_dmm_lookup_mq_number(
|
||||
const struct sr_dev_inst *sdi, enum sr_mq mq, enum sr_mqflag flag)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
size_t i;
|
||||
const struct mqopt_item *item;
|
||||
|
||||
devc = sdi->priv;
|
||||
for (i = 0; i < devc->model->mqopt_size; i++) {
|
||||
item = &devc->model->mqopts[i];
|
||||
if (item->mq != mq || item->mqflag != flag)
|
||||
continue;
|
||||
return item;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SR_PRIV const struct mqopt_item *scpi_dmm_lookup_mq_text(
|
||||
const struct sr_dev_inst *sdi, const char *text)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
size_t i;
|
||||
const struct mqopt_item *item;
|
||||
|
||||
devc = sdi->priv;
|
||||
for (i = 0; i < devc->model->mqopt_size; i++) {
|
||||
item = &devc->model->mqopts[i];
|
||||
if (!item->scpi_func_query || !item->scpi_func_query[0])
|
||||
continue;
|
||||
if (!g_str_has_prefix(text, item->scpi_func_query))
|
||||
continue;
|
||||
return item;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SR_PRIV int scpi_dmm_get_mq(const struct sr_dev_inst *sdi,
|
||||
enum sr_mq *mq, enum sr_mqflag *flag, char **rsp,
|
||||
const struct mqopt_item **mqitem)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
const char *command;
|
||||
char *response;
|
||||
const char *have;
|
||||
int ret;
|
||||
const struct mqopt_item *item;
|
||||
|
||||
devc = sdi->priv;
|
||||
if (mq)
|
||||
*mq = 0;
|
||||
if (flag)
|
||||
*flag = 0;
|
||||
if (rsp)
|
||||
*rsp = NULL;
|
||||
if (mqitem)
|
||||
*mqitem = NULL;
|
||||
|
||||
scpi_dmm_cmd_delay(sdi->conn);
|
||||
command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_QUERY_FUNC);
|
||||
if (!command || !*command)
|
||||
return SR_ERR_NA;
|
||||
response = NULL;
|
||||
ret = sr_scpi_get_string(sdi->conn, command, &response);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
if (!response || !*response)
|
||||
return SR_ERR_NA;
|
||||
have = response;
|
||||
if (*have == '"')
|
||||
have++;
|
||||
|
||||
ret = SR_ERR_NA;
|
||||
item = scpi_dmm_lookup_mq_text(sdi, have);
|
||||
if (item) {
|
||||
if (mq)
|
||||
*mq = item->mq;
|
||||
if (flag)
|
||||
*flag = item->mqflag;
|
||||
if (mqitem)
|
||||
*mqitem = item;
|
||||
ret = SR_OK;
|
||||
}
|
||||
|
||||
if (rsp) {
|
||||
*rsp = response;
|
||||
response = NULL;
|
||||
}
|
||||
g_free(response);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SR_PRIV int scpi_dmm_set_mq(const struct sr_dev_inst *sdi,
|
||||
enum sr_mq mq, enum sr_mqflag flag)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
const struct mqopt_item *item;
|
||||
const char *mode, *command;
|
||||
int ret;
|
||||
|
||||
devc = sdi->priv;
|
||||
item = scpi_dmm_lookup_mq_number(sdi, mq, flag);
|
||||
if (!item)
|
||||
return SR_ERR_NA;
|
||||
|
||||
mode = item->scpi_func_setup;
|
||||
command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_SETUP_FUNC);
|
||||
scpi_dmm_cmd_delay(sdi->conn);
|
||||
ret = sr_scpi_send(sdi->conn, command, mode);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV int scpi_dmm_get_meas_agilent(const struct sr_dev_inst *sdi, size_t ch)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
struct dev_context *devc;
|
||||
struct scpi_dmm_acq_info *info;
|
||||
struct sr_datafeed_analog *analog;
|
||||
int ret;
|
||||
enum sr_mq mq;
|
||||
enum sr_mqflag mqflag;
|
||||
char *mode_response;
|
||||
const char *p;
|
||||
char **fields;
|
||||
size_t count;
|
||||
char prec_text[20];
|
||||
const struct mqopt_item *item;
|
||||
int prec_exp;
|
||||
const char *command;
|
||||
char *response;
|
||||
gboolean use_double;
|
||||
int sig_digits, val_exp;
|
||||
int digits;
|
||||
enum sr_unit unit;
|
||||
|
||||
scpi = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
info = &devc->run_acq_info;
|
||||
analog = &info->analog[ch];
|
||||
|
||||
/*
|
||||
* Get the meter's current mode, keep the response around.
|
||||
* Skip the measurement if the mode is uncertain.
|
||||
*/
|
||||
ret = scpi_dmm_get_mq(sdi, &mq, &mqflag, &mode_response, &item);
|
||||
if (ret != SR_OK) {
|
||||
g_free(mode_response);
|
||||
return ret;
|
||||
}
|
||||
if (!mode_response)
|
||||
return SR_ERR;
|
||||
if (!mq) {
|
||||
g_free(mode_response);
|
||||
return +1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the last comma separated field of the function query
|
||||
* response, or fallback to the model's default precision for
|
||||
* the current function. This copes with either of these cases:
|
||||
* VOLT +1.00000E-01,+1.00000E-06
|
||||
* DIOD
|
||||
* TEMP THER,5000,+1.00000E+00,+1.00000E-01
|
||||
*/
|
||||
p = sr_scpi_unquote_string(mode_response);
|
||||
fields = g_strsplit(p, ",", 0);
|
||||
count = g_strv_length(fields);
|
||||
if (count >= 2) {
|
||||
snprintf(prec_text, sizeof(prec_text),
|
||||
"%s", fields[count - 1]);
|
||||
p = prec_text;
|
||||
} else if (!item) {
|
||||
p = NULL;
|
||||
} else if (item->default_precision == NO_DFLT_PREC) {
|
||||
p = NULL;
|
||||
} else {
|
||||
snprintf(prec_text, sizeof(prec_text),
|
||||
"1e%d", item->default_precision);
|
||||
p = prec_text;
|
||||
}
|
||||
g_strfreev(fields);
|
||||
|
||||
/*
|
||||
* Need to extract the exponent value ourselves, since a strtod()
|
||||
* call will "eat" the exponent, too. Strip space, strip sign,
|
||||
* strip float number (without! exponent), check for exponent
|
||||
* and get exponent value. Accept absence of Esnn suffixes.
|
||||
*/
|
||||
while (p && *p && g_ascii_isspace(*p))
|
||||
p++;
|
||||
if (p && *p && (*p == '+' || *p == '-'))
|
||||
p++;
|
||||
while (p && *p && g_ascii_isdigit(*p))
|
||||
p++;
|
||||
if (p && *p && *p == '.')
|
||||
p++;
|
||||
while (p && *p && g_ascii_isdigit(*p))
|
||||
p++;
|
||||
ret = SR_OK;
|
||||
if (!p || !*p)
|
||||
prec_exp = 0;
|
||||
else if (*p != 'e' && *p != 'E')
|
||||
ret = SR_ERR_DATA;
|
||||
else
|
||||
ret = sr_atoi(++p, &prec_exp);
|
||||
g_free(mode_response);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Get the measurement value. Make sure to strip trailing space
|
||||
* or else number conversion may fail in fatal ways. Detect OL
|
||||
* conditions. Determine the measurement's precision: Count the
|
||||
* number of significant digits before the period, and get the
|
||||
* exponent's value.
|
||||
*
|
||||
* The text presentation of values is like this:
|
||||
* +1.09450000E-01
|
||||
* Skip space/sign, count digits before the period, skip to the
|
||||
* exponent, get exponent value.
|
||||
*
|
||||
* TODO Can sr_parse_rational() return the exponent for us? In
|
||||
* addition to providing a precise rational value instead of a
|
||||
* float that's an approximation of the received value? Can the
|
||||
* 'analog' struct that we fill in carry rationals?
|
||||
*
|
||||
* Use double precision FP here during conversion. Optionally
|
||||
* downgrade to single precision later to reduce the amount of
|
||||
* logged information.
|
||||
*/
|
||||
command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_QUERY_VALUE);
|
||||
if (!command || !*command)
|
||||
return SR_ERR_NA;
|
||||
scpi_dmm_cmd_delay(scpi);
|
||||
ret = sr_scpi_get_string(scpi, command, &response);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
g_strstrip(response);
|
||||
use_double = devc->model->digits > 6;
|
||||
ret = sr_atod_ascii(response, &info->d_value);
|
||||
if (ret != SR_OK) {
|
||||
g_free(response);
|
||||
return ret;
|
||||
}
|
||||
if (!response)
|
||||
return SR_ERR;
|
||||
if (info->d_value > +9e37) {
|
||||
info->d_value = +INFINITY;
|
||||
} else if (info->d_value < -9e37) {
|
||||
info->d_value = -INFINITY;
|
||||
} else {
|
||||
p = response;
|
||||
while (p && *p && g_ascii_isspace(*p))
|
||||
p++;
|
||||
if (p && *p && (*p == '-' || *p == '+'))
|
||||
p++;
|
||||
sig_digits = 0;
|
||||
while (p && *p && g_ascii_isdigit(*p)) {
|
||||
sig_digits++;
|
||||
p++;
|
||||
}
|
||||
if (p && *p && *p == '.')
|
||||
p++;
|
||||
while (p && *p && g_ascii_isdigit(*p))
|
||||
p++;
|
||||
ret = SR_OK;
|
||||
if (!p || !*p)
|
||||
val_exp = 0;
|
||||
else if (*p != 'e' && *p != 'E')
|
||||
ret = SR_ERR_DATA;
|
||||
else
|
||||
ret = sr_atoi(++p, &val_exp);
|
||||
}
|
||||
g_free(response);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
/*
|
||||
* TODO Come up with the most appropriate 'digits' calculation.
|
||||
* This implementation assumes that either the device provides
|
||||
* the resolution with the query for the meter's function, or
|
||||
* the driver uses a fallback text pretending the device had
|
||||
* provided it. This works with supported Agilent devices.
|
||||
*
|
||||
* An alternative may be to assume a given digits count which
|
||||
* depends on the device, and adjust that count based on the
|
||||
* value's significant digits and exponent. But this approach
|
||||
* fails if devices change their digits count depending on
|
||||
* modes or user requests, and also fails when e.g. devices
|
||||
* with "100000 counts" can provide values between 100000 and
|
||||
* 120000 in either 4 or 5 digits modes, depending on the most
|
||||
* recent trend of the values. This less robust approach should
|
||||
* only be taken if the mode inquiry won't yield the resolution
|
||||
* (as e.g. DIOD does on 34405A, though we happen to know the
|
||||
* fixed resolution for this very mode on this very model).
|
||||
*
|
||||
* For now, let's keep the prepared code path for the second
|
||||
* approach in place, should some Agilent devices need it yet
|
||||
* benefit from re-using most of the remaining acquisition
|
||||
* routine.
|
||||
*/
|
||||
#if 1
|
||||
digits = -prec_exp;
|
||||
#else
|
||||
digits = devc->model->digits;
|
||||
digits -= sig_digits;
|
||||
digits -= val_exp;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fill in the 'analog' description: value, encoding, meaning.
|
||||
* Callers will fill in the sample count, and channel name,
|
||||
* and will send out the packet.
|
||||
*/
|
||||
if (use_double) {
|
||||
analog->data = &info->d_value;
|
||||
analog->encoding->unitsize = sizeof(info->d_value);
|
||||
} else {
|
||||
info->f_value = info->d_value;
|
||||
analog->data = &info->f_value;
|
||||
analog->encoding->unitsize = sizeof(info->f_value);
|
||||
}
|
||||
analog->encoding->is_float = TRUE;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
analog->encoding->is_bigendian = TRUE;
|
||||
#else
|
||||
analog->encoding->is_bigendian = FALSE;
|
||||
#endif
|
||||
analog->encoding->digits = digits;
|
||||
analog->meaning->mq = mq;
|
||||
analog->meaning->mqflags = mqflag;
|
||||
switch (mq) {
|
||||
case SR_MQ_VOLTAGE:
|
||||
unit = SR_UNIT_VOLT;
|
||||
break;
|
||||
case SR_MQ_CURRENT:
|
||||
unit = SR_UNIT_AMPERE;
|
||||
break;
|
||||
case SR_MQ_RESISTANCE:
|
||||
case SR_MQ_CONTINUITY:
|
||||
unit = SR_UNIT_OHM;
|
||||
break;
|
||||
case SR_MQ_CAPACITANCE:
|
||||
unit = SR_UNIT_FARAD;
|
||||
break;
|
||||
case SR_MQ_TEMPERATURE:
|
||||
unit = SR_UNIT_CELSIUS;
|
||||
break;
|
||||
case SR_MQ_FREQUENCY:
|
||||
unit = SR_UNIT_HERTZ;
|
||||
break;
|
||||
case SR_MQ_TIME:
|
||||
unit = SR_UNIT_SECOND;
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
analog->meaning->unit = unit;
|
||||
analog->spec->spec_digits = digits;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/* Strictly speaking this is a timer controlled poll routine. */
|
||||
SR_PRIV int scpi_dmm_receive_data(int fd, int revents, void *cb_data)
|
||||
{
|
||||
struct sr_dev_inst *sdi;
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
struct dev_context *devc;
|
||||
struct scpi_dmm_acq_info *info;
|
||||
gboolean sent_sample;
|
||||
size_t ch;
|
||||
struct sr_channel *channel;
|
||||
int ret;
|
||||
|
||||
(void)fd;
|
||||
(void)revents;
|
||||
|
||||
sdi = cb_data;
|
||||
if (!sdi)
|
||||
return TRUE;
|
||||
scpi = sdi->conn;
|
||||
devc = sdi->priv;
|
||||
if (!scpi || !devc)
|
||||
return TRUE;
|
||||
info = &devc->run_acq_info;
|
||||
|
||||
sent_sample = FALSE;
|
||||
ret = SR_OK;
|
||||
for (ch = 0; ch < devc->num_channels; ch++) {
|
||||
/* Check the channel's enabled status. */
|
||||
channel = g_slist_nth_data(sdi->channels, ch);
|
||||
if (!channel->enabled)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Prepare an analog measurement value. Note that digits
|
||||
* will get updated later.
|
||||
*/
|
||||
info->packet.type = SR_DF_ANALOG;
|
||||
info->packet.payload = &info->analog[ch];
|
||||
sr_analog_init(&info->analog[ch], &info->encoding[ch],
|
||||
&info->meaning[ch], &info->spec[ch], 0);
|
||||
|
||||
/* Just check OPC before sending another request. */
|
||||
scpi_dmm_cmd_delay(sdi->conn);
|
||||
|
||||
/*
|
||||
* Have the model take and interpret a measurement. Lack
|
||||
* of support is pointless, failed retrieval/conversion
|
||||
* is considered fatal. The routine will fill in the
|
||||
* 'analog' details, except for channel name and sample
|
||||
* count (assume one value per channel).
|
||||
*
|
||||
* Note that non-zero non-negative return codes signal
|
||||
* that the channel's data shell get skipped in this
|
||||
* iteration over the channels. This copes with devices
|
||||
* or modes where channels may provide data at different
|
||||
* rates.
|
||||
*/
|
||||
if (!devc->model->get_measurement) {
|
||||
ret = SR_ERR_NA;
|
||||
break;
|
||||
}
|
||||
ret = devc->model->get_measurement(sdi, ch);
|
||||
if (ret > 0)
|
||||
continue;
|
||||
if (ret != SR_OK)
|
||||
break;
|
||||
|
||||
/* Send the packet that was filled in by the model's routine. */
|
||||
info->analog[ch].num_samples = 1;
|
||||
info->analog[ch].meaning->channels = g_slist_append(NULL, channel);
|
||||
sr_session_send(sdi, &info->packet);
|
||||
g_slist_free(info->analog[ch].meaning->channels);
|
||||
sent_sample = TRUE;
|
||||
}
|
||||
if (sent_sample)
|
||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||
if (ret != SR_OK) {
|
||||
/* Stop acquisition upon communication or data errors. */
|
||||
sr_dev_acquisition_stop(sdi);
|
||||
return TRUE;
|
||||
}
|
||||
if (sr_sw_limits_check(&devc->limits))
|
||||
sr_dev_acquisition_stop(sdi);
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBSIGROK_HARDWARE_SCPI_DMM_PROTOCOL_H
|
||||
#define LIBSIGROK_HARDWARE_SCPI_DMM_PROTOCOL_H
|
||||
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
#include "scpi.h"
|
||||
|
||||
#define LOG_PREFIX "scpi-dmm"
|
||||
|
||||
#define SCPI_DMM_MAX_CHANNELS 1
|
||||
|
||||
enum scpi_dmm_cmdcode {
|
||||
DMM_CMD_SETUP_REMOTE,
|
||||
DMM_CMD_SETUP_FUNC,
|
||||
DMM_CMD_QUERY_FUNC,
|
||||
DMM_CMD_START_ACQ,
|
||||
DMM_CMD_STOP_ACQ,
|
||||
DMM_CMD_QUERY_VALUE,
|
||||
DMM_CMD_QUERY_PREC,
|
||||
};
|
||||
|
||||
struct mqopt_item {
|
||||
enum sr_mq mq;
|
||||
enum sr_mqflag mqflag;
|
||||
const char *scpi_func_setup;
|
||||
const char *scpi_func_query;
|
||||
int default_precision;
|
||||
};
|
||||
#define NO_DFLT_PREC -99
|
||||
|
||||
struct scpi_dmm_model {
|
||||
const char *vendor;
|
||||
const char *model;
|
||||
size_t num_channels;
|
||||
ssize_t digits;
|
||||
const struct scpi_command *cmdset;
|
||||
const struct mqopt_item *mqopts;
|
||||
size_t mqopt_size;
|
||||
int (*get_measurement)(const struct sr_dev_inst *sdi, size_t ch);
|
||||
const uint32_t *devopts;
|
||||
size_t devopts_size;
|
||||
unsigned int read_timeout_us; /* If zero, use default from src/scpi/scpi.c. */
|
||||
};
|
||||
|
||||
struct dev_context {
|
||||
size_t num_channels;
|
||||
const struct scpi_command *cmdset;
|
||||
const struct scpi_dmm_model *model;
|
||||
struct sr_sw_limits limits;
|
||||
struct {
|
||||
enum sr_mq curr_mq;
|
||||
enum sr_mqflag curr_mqflag;
|
||||
} start_acq_mq;
|
||||
struct scpi_dmm_acq_info {
|
||||
float f_value;
|
||||
double d_value;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog analog[SCPI_DMM_MAX_CHANNELS];
|
||||
struct sr_analog_encoding encoding[SCPI_DMM_MAX_CHANNELS];
|
||||
struct sr_analog_meaning meaning[SCPI_DMM_MAX_CHANNELS];
|
||||
struct sr_analog_spec spec[SCPI_DMM_MAX_CHANNELS];
|
||||
} run_acq_info;
|
||||
};
|
||||
|
||||
SR_PRIV void scpi_dmm_cmd_delay(struct sr_scpi_dev_inst *scpi);
|
||||
SR_PRIV const struct mqopt_item *scpi_dmm_lookup_mq_number(
|
||||
const struct sr_dev_inst *sdi, enum sr_mq mq, enum sr_mqflag flag);
|
||||
SR_PRIV const struct mqopt_item *scpi_dmm_lookup_mq_text(
|
||||
const struct sr_dev_inst *sdi, const char *text);
|
||||
SR_PRIV int scpi_dmm_get_mq(const struct sr_dev_inst *sdi,
|
||||
enum sr_mq *mq, enum sr_mqflag *flag, char **rsp,
|
||||
const struct mqopt_item **mqitem);
|
||||
SR_PRIV int scpi_dmm_set_mq(const struct sr_dev_inst *sdi,
|
||||
enum sr_mq mq, enum sr_mqflag flag);
|
||||
SR_PRIV int scpi_dmm_get_meas_agilent(const struct sr_dev_inst *sdi, size_t ch);
|
||||
SR_PRIV int scpi_dmm_receive_data(int fd, int revents, void *cb_data);
|
||||
|
||||
#endif
|
|
@ -2,7 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2017 Frank Stettner <frank-stettner@gmx.net>
|
||||
* Copyright (C) 2017,2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -152,6 +152,13 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi,
|
|||
for (l = sdi->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
pch = ch->priv;
|
||||
/* Add mqflags from channel_group_spec only to voltage
|
||||
* and current channels.
|
||||
*/
|
||||
if (pch->mq == SR_MQ_VOLTAGE || pch->mq == SR_MQ_CURRENT)
|
||||
pch->mqflags = cgs->mqflags;
|
||||
else
|
||||
pch->mqflags = 0;
|
||||
if (pch->hw_output_idx == j)
|
||||
cg->channels = g_slist_append(cg->channels, ch);
|
||||
}
|
||||
|
@ -166,7 +173,10 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi,
|
|||
sr_scpi_hw_info_free(hw_info);
|
||||
hw_info = NULL;
|
||||
|
||||
sr_scpi_cmd(sdi, devc->device->commands, 0, NULL, SCPI_CMD_LOCAL);
|
||||
/* Don't send SCPI_CMD_LOCAL for HP 66xxB using SCPI over GPIB. */
|
||||
if (!(devc->device->dialect == SCPI_DIALECT_HP_66XXB &&
|
||||
scpi->transport == SCPI_TRANSPORT_LIBGPIB))
|
||||
sr_scpi_cmd(sdi, devc->device->commands, 0, NULL, SCPI_CMD_LOCAL);
|
||||
|
||||
return sdi;
|
||||
}
|
||||
|
@ -258,7 +268,12 @@ static int dev_open(struct sr_dev_inst *sdi)
|
|||
return SR_ERR;
|
||||
|
||||
devc = sdi->priv;
|
||||
sr_scpi_cmd(sdi, devc->device->commands, 0, NULL, SCPI_CMD_REMOTE);
|
||||
|
||||
/* Don't send SCPI_CMD_REMOTE for HP 66xxB using SCPI over GPIB. */
|
||||
if (!(devc->device->dialect == SCPI_DIALECT_HP_66XXB &&
|
||||
scpi->transport == SCPI_TRANSPORT_LIBGPIB))
|
||||
sr_scpi_cmd(sdi, devc->device->commands, 0, NULL, SCPI_CMD_REMOTE);
|
||||
|
||||
devc->beeper_was_set = FALSE;
|
||||
if (sr_scpi_cmd_resp(sdi, devc->device->commands, 0, NULL,
|
||||
&beeper, G_VARIANT_TYPE_BOOLEAN, SCPI_CMD_BEEPER) == SR_OK) {
|
||||
|
@ -287,7 +302,11 @@ static int dev_close(struct sr_dev_inst *sdi)
|
|||
if (devc->beeper_was_set)
|
||||
sr_scpi_cmd(sdi, devc->device->commands,
|
||||
0, NULL, SCPI_CMD_BEEPER_ENABLE);
|
||||
sr_scpi_cmd(sdi, devc->device->commands, 0, NULL, SCPI_CMD_LOCAL);
|
||||
|
||||
/* Don't send SCPI_CMD_LOCAL for HP 66xxB using SCPI over GPIB. */
|
||||
if (!(devc->device->dialect == SCPI_DIALECT_HP_66XXB &&
|
||||
scpi->transport == SCPI_TRANSPORT_LIBGPIB))
|
||||
sr_scpi_cmd(sdi, devc->device->commands, 0, NULL, SCPI_CMD_LOCAL);
|
||||
|
||||
return sr_scpi_close(scpi);
|
||||
}
|
||||
|
@ -313,6 +332,7 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
char *channel_group_name;
|
||||
int cmd, ret;
|
||||
const char *s;
|
||||
int reg;
|
||||
|
||||
if (!sdi)
|
||||
return SR_ERR_ARG;
|
||||
|
@ -375,7 +395,11 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
cmd = SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ENABLED;
|
||||
break;
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE:
|
||||
gvtype = G_VARIANT_TYPE_BOOLEAN;
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB ||
|
||||
devc->device->dialect == SCPI_DIALECT_HP_COMP)
|
||||
gvtype = G_VARIANT_TYPE_STRING;
|
||||
else
|
||||
gvtype = G_VARIANT_TYPE_BOOLEAN;
|
||||
cmd = SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE;
|
||||
break;
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
|
||||
|
@ -387,7 +411,11 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
cmd = SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ENABLED;
|
||||
break;
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE:
|
||||
gvtype = G_VARIANT_TYPE_BOOLEAN;
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB ||
|
||||
devc->device->dialect == SCPI_DIALECT_HP_COMP)
|
||||
gvtype = G_VARIANT_TYPE_STRING;
|
||||
else
|
||||
gvtype = G_VARIANT_TYPE_BOOLEAN;
|
||||
cmd = SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE;
|
||||
break;
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
|
||||
|
@ -398,6 +426,14 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
gvtype = G_VARIANT_TYPE_BOOLEAN;
|
||||
cmd = SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION;
|
||||
break;
|
||||
case SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE:
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB ||
|
||||
devc->device->dialect == SCPI_DIALECT_HP_COMP)
|
||||
gvtype = G_VARIANT_TYPE_STRING;
|
||||
else
|
||||
gvtype = G_VARIANT_TYPE_BOOLEAN;
|
||||
cmd = SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE;
|
||||
break;
|
||||
case SR_CONF_REGULATION:
|
||||
gvtype = G_VARIANT_TYPE_STRING;
|
||||
cmd = SCPI_CMD_GET_OUTPUT_REGULATION;
|
||||
|
@ -419,28 +455,116 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
channel_group_cmd, channel_group_name, data, gvtype, cmd);
|
||||
g_free(channel_group_name);
|
||||
|
||||
/*
|
||||
* Handle special cases
|
||||
*/
|
||||
|
||||
if (cmd == SCPI_CMD_GET_OUTPUT_REGULATION) {
|
||||
/*
|
||||
* The Rigol DP800 series return CV/CC/UR, Philips PM2800
|
||||
* return VOLT/CURR. We always return a GVariant string in
|
||||
* the Rigol notation.
|
||||
*/
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
if (!strcmp(s, "VOLT")) {
|
||||
if (devc->device->dialect == SCPI_DIALECT_PHILIPS) {
|
||||
/*
|
||||
* The Philips PM2800 series returns VOLT/CURR. We always return
|
||||
* a GVariant string in the Rigol notation (CV/CC/UR).
|
||||
*/
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
if (!g_strcmp0(s, "VOLT")) {
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_string("CV");
|
||||
} else if (!g_strcmp0(s, "CURR")) {
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_string("CC");
|
||||
}
|
||||
}
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_COMP) {
|
||||
/* Evaluate Status Register from a HP 66xx in COMP mode. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_string("CV");
|
||||
} else if (!strcmp(s, "CURR")) {
|
||||
if (reg & (1 << 0))
|
||||
*data = g_variant_new_string("CV");
|
||||
else if (reg & (1 << 1))
|
||||
*data = g_variant_new_string("CC");
|
||||
else if (reg & (1 << 2))
|
||||
*data = g_variant_new_string("UR");
|
||||
else if (reg & (1 << 9))
|
||||
*data = g_variant_new_string("CC-");
|
||||
else
|
||||
*data = g_variant_new_string("");
|
||||
}
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB) {
|
||||
/* Evaluate Operational Status Register from a HP 66xxB. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_string("CC");
|
||||
if (reg & (1 << 8))
|
||||
*data = g_variant_new_string("CV");
|
||||
else if (reg & (1 << 10))
|
||||
*data = g_variant_new_string("CC");
|
||||
else if (reg & (1 << 11))
|
||||
*data = g_variant_new_string("CC-");
|
||||
else
|
||||
*data = g_variant_new_string("UR");
|
||||
}
|
||||
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
if (strcmp(s, "CV") && strcmp(s, "CC") && strcmp(s, "UR")) {
|
||||
sr_dbg("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s);
|
||||
if (g_strcmp0(s, "CV") && g_strcmp0(s, "CC") && g_strcmp0(s, "CC-") &&
|
||||
g_strcmp0(s, "UR") && g_strcmp0(s, "")) {
|
||||
|
||||
sr_err("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s);
|
||||
ret = SR_ERR_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE) {
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_COMP) {
|
||||
/* Evaluate Status Register from a HP 66xx in COMP mode. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_boolean(reg & (1 << 3));
|
||||
}
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB) {
|
||||
/* Evaluate Questionable Status Register bit 0 from a HP 66xxB. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_boolean(reg & (1 << 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE) {
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_COMP) {
|
||||
/* Evaluate Status Register from a HP 66xx in COMP mode. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_boolean(reg & (1 << 6));
|
||||
}
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB) {
|
||||
/* Evaluate Questionable Status Register bit 1 from a HP 66xxB. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_boolean(reg & (1 << 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE) {
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_COMP) {
|
||||
/* Evaluate Status Register from a HP 66xx in COMP mode. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_boolean(reg & (1 << 4));
|
||||
}
|
||||
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB) {
|
||||
/* Evaluate Questionable Status Register bit 4 from a HP 66xxB. */
|
||||
s = g_variant_get_string(*data, NULL);
|
||||
sr_atoi(s, ®);
|
||||
g_variant_unref(*data);
|
||||
*data = g_variant_new_boolean(reg & (1 << 4));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -640,6 +764,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|||
/* Prime the pipe with the first channel. */
|
||||
devc->cur_acquisition_channel = sr_next_enabled_channel(sdi, NULL);
|
||||
|
||||
/* Device specific initialization before acquisition starts. */
|
||||
if (devc->device->init_acquisition)
|
||||
devc->device->init_acquisition(sdi);
|
||||
|
||||
if ((ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 10,
|
||||
scpi_pps_receive_data, (void *)sdi)) != SR_OK)
|
||||
return ret;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
* (Written by Alexandru Gagniuc <mrnuke@google.com> for Google, Inc.)
|
||||
* Copyright (C) 2017 Frank Stettner <frank-stettner@gmx.net>
|
||||
* Copyright (C) 2017,2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -48,7 +48,7 @@ static const uint32_t agilent_n5700a_devopts_cg[] = {
|
|||
};
|
||||
|
||||
static const struct channel_group_spec agilent_n5700a_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP },
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct channel_spec agilent_n5767a_ch[] = {
|
||||
|
@ -86,6 +86,53 @@ static const struct scpi_command agilent_n5700a_cmd[] = {
|
|||
ALL_ZERO
|
||||
};
|
||||
|
||||
/* BK Precision 9130 series */
|
||||
static const uint32_t bk_9130_devopts[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||
};
|
||||
|
||||
static const uint32_t bk_9130_devopts_cg[] = {
|
||||
SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_VOLTAGE | SR_CONF_GET,
|
||||
SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_CURRENT | SR_CONF_GET,
|
||||
SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
|
||||
};
|
||||
|
||||
static const struct channel_spec bk_9130_ch[] = {
|
||||
{ "1", { 0, 30, 0.001, 3, 3 }, { 0, 3, 0.001, 3, 3 }, { 0, 90, 0, 3, 3 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
|
||||
{ "2", { 0, 30, 0.001, 3, 3 }, { 0, 3, 0.001, 3, 3 }, { 0, 90, 0, 3, 3 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
|
||||
{ "3", { 0, 5, 0.001, 3, 3 }, { 0, 3, 0.001, 3, 3 }, { 0, 15, 0, 3, 3 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_group_spec bk_9130_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP, SR_MQFLAG_DC },
|
||||
{ "2", CH_IDX(1), PPS_OVP, SR_MQFLAG_DC },
|
||||
{ "3", CH_IDX(2), PPS_OVP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct scpi_command bk_9130_cmd[] = {
|
||||
{ SCPI_CMD_REMOTE, "SYST:REMOTE" },
|
||||
{ SCPI_CMD_LOCAL, "SYST:LOCAL" },
|
||||
{ SCPI_CMD_SELECT_CHANNEL, ":INST:NSEL %s" },
|
||||
{ SCPI_CMD_GET_MEAS_VOLTAGE, ":MEAS:VOLT?" },
|
||||
{ SCPI_CMD_GET_MEAS_CURRENT, ":MEAS:CURR?" },
|
||||
{ SCPI_CMD_GET_MEAS_POWER, ":MEAS:POWER?" },
|
||||
{ SCPI_CMD_GET_VOLTAGE_TARGET, ":SOUR:VOLT?" },
|
||||
{ SCPI_CMD_SET_VOLTAGE_TARGET, ":SOUR:VOLT %.6f" },
|
||||
{ SCPI_CMD_GET_CURRENT_LIMIT, ":SOUR:CURR?" },
|
||||
{ SCPI_CMD_SET_CURRENT_LIMIT, ":SOUR:CURR %.6f" },
|
||||
{ SCPI_CMD_GET_OUTPUT_ENABLED, ":OUTP?" },
|
||||
{ SCPI_CMD_SET_OUTPUT_ENABLE, ":OUTP 1" },
|
||||
{ SCPI_CMD_SET_OUTPUT_DISABLE, ":OUTP 0" },
|
||||
{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":SOUR:VOLT:PROT?" },
|
||||
{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":SOUR:VOLT:PROT %.6f" },
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
/* Chroma 61600 series AC source */
|
||||
static const uint32_t chroma_61604_devopts[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
|
@ -109,7 +156,7 @@ static const struct channel_spec chroma_61604_ch[] = {
|
|||
};
|
||||
|
||||
static const struct channel_group_spec chroma_61604_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP },
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_AC },
|
||||
};
|
||||
|
||||
static const struct scpi_command chroma_61604_cmd[] = {
|
||||
|
@ -152,7 +199,7 @@ static const uint32_t chroma_62000_devopts_cg[] = {
|
|||
};
|
||||
|
||||
static const struct channel_group_spec chroma_62000_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP },
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct scpi_command chroma_62000_cmd[] = {
|
||||
|
@ -258,7 +305,7 @@ static const struct channel_spec rigol_dp712_ch[] = {
|
|||
};
|
||||
|
||||
static const struct channel_group_spec rigol_dp700_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP },
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
/* Same as the DP800 series, except for the missing :SYST:OTP* commands. */
|
||||
|
@ -336,14 +383,14 @@ static const struct channel_spec rigol_dp832_ch[] = {
|
|||
};
|
||||
|
||||
static const struct channel_group_spec rigol_dp820_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP },
|
||||
{ "2", CH_IDX(1), PPS_OVP | PPS_OCP },
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
{ "2", CH_IDX(1), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct channel_group_spec rigol_dp830_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP },
|
||||
{ "2", CH_IDX(1), PPS_OVP | PPS_OCP },
|
||||
{ "3", CH_IDX(2), PPS_OVP | PPS_OCP },
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
{ "2", CH_IDX(1), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
{ "3", CH_IDX(2), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct scpi_command rigol_dp800_cmd[] = {
|
||||
|
@ -382,7 +429,7 @@ static const struct scpi_command rigol_dp800_cmd[] = {
|
|||
ALL_ZERO
|
||||
};
|
||||
|
||||
/* HP 663xx series */
|
||||
/* HP 663xA series */
|
||||
static const uint32_t hp_6630a_devopts[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
|
@ -395,10 +442,136 @@ static const uint32_t hp_6630a_devopts_cg[] = {
|
|||
SR_CONF_CURRENT | SR_CONF_GET,
|
||||
SR_CONF_VOLTAGE_TARGET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_CURRENT_LIMIT | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE | SR_CONF_GET,
|
||||
SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_SET,
|
||||
SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE | SR_CONF_GET,
|
||||
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
|
||||
SR_CONF_REGULATION | SR_CONF_GET,
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6632a_ch[] = {
|
||||
{ "1", { 0, 20.475, 0.005, 3, 4 }, { 0, 5.1188, 0.00125, 4, 5 }, { 0, 104.80743 }, FREQ_DC_ONLY, { 0, 22, 0.1 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6633a_ch[] = {
|
||||
{ "1", { 0, 51.188, 0.0125, 3, 4 }, { 0, 2.0475, 0.0005, 4, 5 }, { 0, 104.80743 }, FREQ_DC_ONLY, { 0, 55, 0.25 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6634a_ch[] = {
|
||||
{ "1", { 0, 102.38, 0.025, 3, 4 }, { 0, 1.0238, 0.00025, 4, 5 }, { 0, 104.81664 }, FREQ_DC_ONLY, { 0, 110, 0.5 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_group_spec hp_6630a_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct scpi_command hp_6630a_cmd[] = {
|
||||
{ SCPI_CMD_SET_OUTPUT_ENABLE, "OUT 1" },
|
||||
{ SCPI_CMD_SET_OUTPUT_DISABLE, "OUT 0" },
|
||||
{ SCPI_CMD_GET_MEAS_VOLTAGE, "VOUT?" },
|
||||
{ SCPI_CMD_GET_MEAS_CURRENT, "IOUT?" },
|
||||
{ SCPI_CMD_SET_VOLTAGE_TARGET, "VSET %.4f" },
|
||||
{ SCPI_CMD_SET_CURRENT_LIMIT, "ISET %.4f" },
|
||||
{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE, "STS?" },
|
||||
{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, "OVSET %.4f" },
|
||||
{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE, "OCP 1" },
|
||||
{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE, "OCP 0" },
|
||||
{ SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE, "STS?" },
|
||||
{ SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE, "STS?" },
|
||||
{ SCPI_CMD_GET_OUTPUT_REGULATION, "STS?" },
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
static int hp_6630a_init_acquisition(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
|
||||
scpi = sdi->conn;
|
||||
|
||||
/*
|
||||
* Monitor CV (1), CC+ (2), UR (4), OVP (8), OTP (16), OCP (64) and
|
||||
* CC- (256) bits of the Status Register for the FAULT? query.
|
||||
*/
|
||||
return sr_scpi_send(scpi, "UNMASK 607");
|
||||
}
|
||||
|
||||
static int hp_6630a_update_status(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
int ret;
|
||||
int fault;
|
||||
gboolean cv, cc_pos, unreg, cc_neg;
|
||||
gboolean regulation_changed;
|
||||
char *regulation;
|
||||
|
||||
scpi = sdi->conn;
|
||||
|
||||
/*
|
||||
* Use the FAULT register (only 0->1 transitions), this way multiple set
|
||||
* regulation bits in the STS/ASTS registers are ignored. In rare cases
|
||||
* we will miss some changes (1->0 transitions, e.g. no regulation at all),
|
||||
* but SPS/ASPS doesn't work either, unless all states are stored and
|
||||
* compared to the states in STS/ASTS.
|
||||
* TODO: Use SPoll or SRQ when SCPI over GPIB is used.
|
||||
*/
|
||||
ret = sr_scpi_get_int(scpi, "FAULT?", &fault);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
/* OVP */
|
||||
if (fault & (1 << 3))
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(fault & (1 << 3)));
|
||||
|
||||
/* OCP */
|
||||
if (fault & (1 << 6))
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(fault & (1 << 6)));
|
||||
|
||||
/* OTP */
|
||||
if (fault & (1 << 4))
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(fault & (1 << 4)));
|
||||
|
||||
/* CV */
|
||||
cv = (fault & (1 << 0));
|
||||
regulation_changed = (fault & (1 << 0));
|
||||
/* CC+ */
|
||||
cc_pos = (fault & (1 << 1));
|
||||
regulation_changed = (fault & (1 << 1)) | regulation_changed;
|
||||
/* UNREG */
|
||||
unreg = (fault & (1 << 2));
|
||||
regulation_changed = (fault & (1 << 2)) | regulation_changed;
|
||||
/* CC- */
|
||||
cc_neg = (fault & (1 << 9));
|
||||
regulation_changed = (fault & (1 << 9)) | regulation_changed;
|
||||
|
||||
if (regulation_changed) {
|
||||
if (cv && !cc_pos && !cc_neg && !unreg)
|
||||
regulation = "CV";
|
||||
else if (cc_pos && !cv && !cc_neg && !unreg)
|
||||
regulation = "CC";
|
||||
else if (cc_neg && !cv && !cc_pos && !unreg)
|
||||
regulation = "CC-";
|
||||
else if (unreg && !cv && !cc_pos && !cc_neg)
|
||||
regulation = "UR";
|
||||
else if (!cv && !cc_pos && !cc_neg && !unreg)
|
||||
regulation = "";
|
||||
else {
|
||||
sr_dbg("Undefined regulation for HP 66xxA "
|
||||
"(CV=%i, CC+=%i, CC-=%i, UR=%i).",
|
||||
cv, cc_pos, cc_neg, unreg);
|
||||
return FALSE;
|
||||
}
|
||||
sr_session_send_meta(sdi, SR_CONF_REGULATION,
|
||||
g_variant_new_string(regulation));
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/* HP 663xB series */
|
||||
static const uint32_t hp_6630b_devopts[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
|
@ -411,12 +584,28 @@ static const uint32_t hp_6630b_devopts_cg[] = {
|
|||
SR_CONF_CURRENT | SR_CONF_GET,
|
||||
SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE | SR_CONF_GET,
|
||||
SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE | SR_CONF_GET,
|
||||
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
|
||||
SR_CONF_REGULATION | SR_CONF_GET,
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6633a_ch[] = {
|
||||
{ "1", { 0, 51.188, 0.0125, 3, 4 }, { 0, 2.0475, 0.0005, 4, 5 }, { 0, 104.80743 }, FREQ_DC_ONLY, { 0, 55, 0.25 }, NO_OCP_LIMITS },
|
||||
static const struct channel_spec hp_6611c_ch[] = {
|
||||
{ "1", { 0, 8.19, 0.002, 3, 4 }, { 0, 5.1188, 0.00125, 4, 5 }, { 0, 41.92297 }, FREQ_DC_ONLY, { 0, 12, 0.06 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6612c_ch[] = {
|
||||
{ "1", { 0, 20.475, 0.005, 3, 4 }, { 0, 2.0475, 0.0005, 4, 5 }, { 0, 41.92256 }, FREQ_DC_ONLY, { 0, 22, 0.1 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6613c_ch[] = {
|
||||
{ "1", { 0, 51.188, 0.0125, 3, 4 }, { 0, 1.0238, 0.00025, 4, 5 }, { 0, 52.40627 }, FREQ_DC_ONLY, { 0, 55, 0.25 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6614c_ch[] = {
|
||||
{ "1", { 0, 102.38, 0.025, 3, 4 }, { 0, 0.5118, 0.000125, 4, 5 }, { 0, 52.39808 }, FREQ_DC_ONLY, { 0, 110, 0.5 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_6631b_ch[] = {
|
||||
|
@ -427,6 +616,10 @@ static const struct channel_spec hp_6632b_ch[] = {
|
|||
{ "1", { 0, 20.475, 0.005, 3, 4 }, { 0, 5.1188, 0.00132, 4, 5 }, { 0, 104.80743 }, FREQ_DC_ONLY, { 0, 22, 0.1 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_66312a_ch[] = {
|
||||
{ "1", { 0, 20.475, 0.0001, 4, 5 }, { 0, 2.0475, 0.0001, 4, 5 }, { 0, 41.92256 }, FREQ_DC_ONLY, { 0, 22, 0.01 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_spec hp_66332a_ch[] = {
|
||||
{ "1", { 0, 20.475, 0.005, 3, 4 }, { 0, 5.1188, 0.00132, 4, 5 }, { 0, 104.80743 }, FREQ_DC_ONLY, { 0, 22, 0.1 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
@ -439,24 +632,15 @@ static const struct channel_spec hp_6634b_ch[] = {
|
|||
{ "1", { 0, 102.38, 0.025, 3, 4 }, { 0, 1.0238, 0.000263, 4, 5 }, { 0, 104.81664 }, FREQ_DC_ONLY, { 0, 110, 0.5 }, NO_OCP_LIMITS },
|
||||
};
|
||||
|
||||
static const struct channel_group_spec hp_663xx_cg[] = {
|
||||
{ "1", CH_IDX(0), 0 },
|
||||
};
|
||||
|
||||
static const struct scpi_command hp_6630a_cmd[] = {
|
||||
{ SCPI_CMD_SET_OUTPUT_ENABLE, "OUT 1" },
|
||||
{ SCPI_CMD_SET_OUTPUT_DISABLE, "OUT 0" },
|
||||
{ SCPI_CMD_GET_MEAS_VOLTAGE, "VOUT?" },
|
||||
{ SCPI_CMD_GET_MEAS_CURRENT, "IOUT?" },
|
||||
{ SCPI_CMD_SET_VOLTAGE_TARGET, "VSET %.4f" },
|
||||
{ SCPI_CMD_SET_CURRENT_LIMIT, "ISET %.4f" },
|
||||
{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE, "OCP 1" },
|
||||
{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE, "OCP 0" },
|
||||
{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, "OVSET %.4f" },
|
||||
ALL_ZERO
|
||||
static const struct channel_group_spec hp_6630b_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct scpi_command hp_6630b_cmd[] = {
|
||||
/*
|
||||
* SCPI_CMD_REMOTE and SCPI_CMD_LOCAL are not used when GPIB is used,
|
||||
* otherwise the device will report (non critical) error 602.
|
||||
*/
|
||||
{ SCPI_CMD_REMOTE, "SYST:REM" },
|
||||
{ SCPI_CMD_LOCAL, "SYST:LOC" },
|
||||
{ SCPI_CMD_GET_OUTPUT_ENABLED, "OUTP:STAT?" },
|
||||
|
@ -471,11 +655,187 @@ static const struct scpi_command hp_6630b_cmd[] = {
|
|||
{ SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ENABLED, ":CURR:PROT:STAT?" },
|
||||
{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE, ":CURR:PROT:STAT 1" },
|
||||
{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE, ":CURR:PROT:STAT 0" },
|
||||
{ SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE, "STAT:QUES:COND?" },
|
||||
{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE, "STAT:QUES:COND?" },
|
||||
{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":VOLT:PROT?" },
|
||||
{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":VOLT:PROT %.6f" },
|
||||
{ SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE, "STAT:QUES:COND?" },
|
||||
{ SCPI_CMD_GET_OUTPUT_REGULATION, "STAT:OPER:COND?" },
|
||||
ALL_ZERO
|
||||
};
|
||||
|
||||
static int hp_6630b_init_acquisition(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
int ret;
|
||||
|
||||
scpi = sdi->conn;
|
||||
|
||||
/*
|
||||
* Monitor CV (256), CC+ (1024) and CC- (2048) bits of the
|
||||
* Operational Status Register.
|
||||
* Use both positive and negative transitions of the status bits.
|
||||
*/
|
||||
ret = sr_scpi_send(scpi, "STAT:OPER:PTR 3328;NTR 3328;ENAB 3328");
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Monitor OVP (1), OCP (2), OTP (16) and Unreg (1024) bits of the
|
||||
* Questionable Status Register.
|
||||
* Use both positive and negative transitions of the status bits.
|
||||
*/
|
||||
ret = sr_scpi_send(scpi, "STAT:QUES:PTR 1043;NTR 1043;ENAB 1043");
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Service Request Enable Register set for Operational Status Register
|
||||
* bits (128) and Questionable Status Register bits (8).
|
||||
* This masks the Status Register generating a SRQ/RQS. Not implemented yet!
|
||||
*/
|
||||
/*
|
||||
ret = sr_scpi_send(scpi, "*SRE 136");
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
*/
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int hp_6630b_update_status(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
int ret;
|
||||
int stb;
|
||||
int ques_even, ques_cond;
|
||||
int oper_even, oper_cond;
|
||||
gboolean output_enabled;
|
||||
gboolean unreg, cv, cc_pos, cc_neg;
|
||||
gboolean regulation_changed;
|
||||
char *regulation;
|
||||
|
||||
scpi = sdi->conn;
|
||||
|
||||
unreg = FALSE;
|
||||
cv = FALSE;
|
||||
cc_pos = FALSE;
|
||||
cc_neg = FALSE;
|
||||
regulation_changed = FALSE;
|
||||
|
||||
/*
|
||||
* Use SPoll when SCPI uses GPIB as transport layer.
|
||||
* SPoll is approx. twice as fast as a normal GPIB write + read would be!
|
||||
*/
|
||||
#ifdef HAVE_LIBGPIB
|
||||
char spoll_buf;
|
||||
|
||||
if (scpi->transport == SCPI_TRANSPORT_LIBGPIB) {
|
||||
ret = sr_scpi_gpib_spoll(scpi, &spoll_buf);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
stb = (uint8_t)spoll_buf;
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
ret = sr_scpi_get_int(scpi, "*STB?", &stb);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
#ifdef HAVE_LIBGPIB
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Questionable status summary bit */
|
||||
if (stb & (1 << 3)) {
|
||||
/* Read the event register to clear it! */
|
||||
ret = sr_scpi_get_int(scpi, "STAT:QUES:EVEN?", &ques_even);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
/* Now get the values. */
|
||||
ret = sr_scpi_get_int(scpi, "STAT:QUES:COND?", &ques_cond);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
/* OVP */
|
||||
if (ques_even & (1 << 0))
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(ques_cond & (1 << 0)));
|
||||
|
||||
/* OCP */
|
||||
if (ques_even & (1 << 1))
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(ques_cond & (1 << 1)));
|
||||
|
||||
/* OTP */
|
||||
if (ques_even & (1 << 4))
|
||||
sr_session_send_meta(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
|
||||
g_variant_new_boolean(ques_cond & (1 << 4)));
|
||||
|
||||
/* UNREG */
|
||||
unreg = (ques_cond & (1 << 10));
|
||||
regulation_changed = (ques_even & (1 << 10)) | regulation_changed;
|
||||
|
||||
/*
|
||||
* Check if output state has changed, due to one of the
|
||||
* questionable states changed.
|
||||
* NOTE: The output state is sent even if it hasn't changed,
|
||||
* but that only happens rarely.
|
||||
*/
|
||||
ret = sr_scpi_get_bool(scpi, "OUTP:STAT?", &output_enabled);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
sr_session_send_meta(sdi, SR_CONF_ENABLED,
|
||||
g_variant_new_boolean(output_enabled));
|
||||
}
|
||||
|
||||
/* Operation status summary bit */
|
||||
if (stb & (1 << 7)) {
|
||||
/* Read the event register to clear it! */
|
||||
ret = sr_scpi_get_int(scpi, "STAT:OPER:EVEN?", &oper_even);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
/* Now get the values. */
|
||||
ret = sr_scpi_get_int(scpi, "STAT:OPER:COND?", &oper_cond);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
/* CV */
|
||||
cv = (oper_cond & (1 << 8));
|
||||
regulation_changed = (oper_even & (1 << 8)) | regulation_changed;
|
||||
/* CC+ */
|
||||
cc_pos = (oper_cond & (1 << 10));
|
||||
regulation_changed = (oper_even & (1 << 10)) | regulation_changed;
|
||||
/* CC- */
|
||||
cc_neg = (oper_cond & (1 << 11));
|
||||
regulation_changed = (oper_even & (1 << 11)) | regulation_changed;
|
||||
}
|
||||
|
||||
if (regulation_changed) {
|
||||
if (cv && !cc_pos && !cc_neg && !unreg)
|
||||
regulation = "CV";
|
||||
else if (cc_pos && !cv && !cc_neg && !unreg)
|
||||
regulation = "CC";
|
||||
else if (cc_neg && !cv && !cc_pos && !unreg)
|
||||
regulation = "CC-";
|
||||
else if (unreg && !cv && !cc_pos && !cc_neg)
|
||||
regulation = "UR";
|
||||
else if (!cv && !cc_pos && !cc_neg && !unreg)
|
||||
/* This happens in case of OCP active. */
|
||||
regulation = "";
|
||||
else {
|
||||
/* This happens from time to time (CV and CC+ active). */
|
||||
sr_dbg("Undefined regulation for HP 66xxB "
|
||||
"(CV=%i, CC+=%i, CC-=%i, UR=%i).",
|
||||
cv, cc_pos, cc_neg, unreg);
|
||||
return FALSE;
|
||||
}
|
||||
sr_session_send_meta(sdi, SR_CONF_REGULATION,
|
||||
g_variant_new_string(regulation));
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/* Philips/Fluke PM2800 series */
|
||||
static const uint32_t philips_pm2800_devopts[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
|
@ -599,6 +959,7 @@ static int philips_pm2800_probe_channels(struct sr_dev_inst *sdi,
|
|||
(*channel_groups)[i].name = (char *)philips_pm2800_names[i];
|
||||
(*channel_groups)[i].channel_index_mask = 1 << i;
|
||||
(*channel_groups)[i].features = PPS_OTP | PPS_OVP | PPS_OCP;
|
||||
(*channel_groups)[i].mqflags = SR_MQFLAG_DC;
|
||||
}
|
||||
*num_channels = *num_channel_groups = num_modules;
|
||||
|
||||
|
@ -651,9 +1012,9 @@ static const struct channel_spec rs_hmc8043_ch[] = {
|
|||
};
|
||||
|
||||
static const struct channel_group_spec rs_hmc8043_cg[] = {
|
||||
{ "1", CH_IDX(0), PPS_OVP },
|
||||
{ "2", CH_IDX(1), PPS_OVP },
|
||||
{ "3", CH_IDX(2), PPS_OVP },
|
||||
{ "1", CH_IDX(0), PPS_OVP, SR_MQFLAG_DC },
|
||||
{ "2", CH_IDX(1), PPS_OVP, SR_MQFLAG_DC },
|
||||
{ "3", CH_IDX(2), PPS_OVP, SR_MQFLAG_DC },
|
||||
};
|
||||
|
||||
static const struct scpi_command rs_hmc8043_cmd[] = {
|
||||
|
@ -678,167 +1039,315 @@ static const struct scpi_command rs_hmc8043_cmd[] = {
|
|||
|
||||
SR_PRIV const struct scpi_pps pps_profiles[] = {
|
||||
/* Agilent N5763A */
|
||||
{ "Agilent", "N5763A", 0,
|
||||
{ "Agilent", "N5763A", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(agilent_n5700a_devopts),
|
||||
ARRAY_AND_SIZE(agilent_n5700a_devopts_cg),
|
||||
ARRAY_AND_SIZE(agilent_n5763a_ch),
|
||||
ARRAY_AND_SIZE(agilent_n5700a_cg),
|
||||
agilent_n5700a_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/* Agilent N5767A */
|
||||
{ "Agilent", "N5767A", 0,
|
||||
{ "Agilent", "N5767A", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(agilent_n5700a_devopts),
|
||||
ARRAY_AND_SIZE(agilent_n5700a_devopts_cg),
|
||||
ARRAY_AND_SIZE(agilent_n5767a_ch),
|
||||
ARRAY_AND_SIZE(agilent_n5700a_cg),
|
||||
agilent_n5700a_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/* BK Precision 9310 */
|
||||
{ "BK", "^9130$", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(bk_9130_devopts),
|
||||
ARRAY_AND_SIZE(bk_9130_devopts_cg),
|
||||
ARRAY_AND_SIZE(bk_9130_ch),
|
||||
ARRAY_AND_SIZE(bk_9130_cg),
|
||||
bk_9130_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/* Chroma 61604 */
|
||||
{ "Chroma", "61604", 0,
|
||||
{ "Chroma", "61604", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(chroma_61604_devopts),
|
||||
ARRAY_AND_SIZE(chroma_61604_devopts_cg),
|
||||
ARRAY_AND_SIZE(chroma_61604_ch),
|
||||
ARRAY_AND_SIZE(chroma_61604_cg),
|
||||
chroma_61604_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/* Chroma 62000 series */
|
||||
{ "Chroma", "620[0-9]{2}P-[0-9]{2,3}-[0-9]{1,3}", 0,
|
||||
{ "Chroma", "620[0-9]{2}P-[0-9]{2,3}-[0-9]{1,3}", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(chroma_62000_devopts),
|
||||
ARRAY_AND_SIZE(chroma_62000_devopts_cg),
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
chroma_62000_cmd,
|
||||
.probe_channels = chroma_62000p_probe_channels,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/*
|
||||
* This entry is for testing the HP COMP language with a HP 6632B power
|
||||
* supply switched to the COMP language ("SYST:LANG COMP"). When used,
|
||||
* disable the entry for the HP 6632B below!
|
||||
*/
|
||||
/*
|
||||
{ "HP", "6632B", SCPI_DIALECT_HP_COMP, 0,
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6632a_ch),
|
||||
ARRAY_AND_SIZE(hp_6630a_cg),
|
||||
hp_6630a_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630a_init_acquisition,
|
||||
hp_6630a_update_status,
|
||||
},
|
||||
*/
|
||||
|
||||
/* HP 6632A */
|
||||
{ "HP", "6632A", SCPI_DIALECT_HP_COMP, 0,
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6632a_ch),
|
||||
ARRAY_AND_SIZE(hp_6630a_cg),
|
||||
hp_6630a_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630a_init_acquisition,
|
||||
hp_6630a_update_status,
|
||||
},
|
||||
|
||||
/* HP 6633A */
|
||||
{ "HP", "6633A", 0,
|
||||
{ "HP", "6633A", SCPI_DIALECT_HP_COMP, 0,
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6633a_ch),
|
||||
ARRAY_AND_SIZE(hp_663xx_cg),
|
||||
ARRAY_AND_SIZE(hp_6630a_cg),
|
||||
hp_6630a_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630a_init_acquisition,
|
||||
hp_6630a_update_status,
|
||||
},
|
||||
|
||||
/* HP 6634A */
|
||||
{ "HP", "6634A", SCPI_DIALECT_HP_COMP, 0,
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630a_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6634a_ch),
|
||||
ARRAY_AND_SIZE(hp_6630a_cg),
|
||||
hp_6630a_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630a_init_acquisition,
|
||||
hp_6630a_update_status,
|
||||
},
|
||||
|
||||
/* HP 6611C */
|
||||
{ "HP", "6611C", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6611c_ch),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 6612C */
|
||||
{ "HP", "6612C", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6612c_ch),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 6613C */
|
||||
{ "HP", "6613C", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6613c_ch),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 6614C */
|
||||
{ "HP", "6614C", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6614c_ch),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 6631B */
|
||||
{ "HP", "6631B", PPS_OVP | PPS_OCP | PPS_OTP,
|
||||
{ "HP", "6631B", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6631b_ch),
|
||||
ARRAY_AND_SIZE(hp_663xx_cg),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 6632B */
|
||||
{ "HP", "6632B", PPS_OVP | PPS_OCP | PPS_OTP,
|
||||
{ "HP", "6632B", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6632b_ch),
|
||||
ARRAY_AND_SIZE(hp_663xx_cg),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 66312A */
|
||||
{ "HP", "66312A", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_66312a_ch),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 66332A */
|
||||
{ "HP", "66332A", PPS_OVP | PPS_OCP | PPS_OTP,
|
||||
{ "HP", "66332A", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_66332a_ch),
|
||||
ARRAY_AND_SIZE(hp_663xx_cg),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 6633B */
|
||||
{ "HP", "6633B", PPS_OVP | PPS_OCP | PPS_OTP,
|
||||
{ "HP", "6633B", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6633b_ch),
|
||||
ARRAY_AND_SIZE(hp_663xx_cg),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* HP 6634B */
|
||||
{ "HP", "6634B", PPS_OVP | PPS_OCP | PPS_OTP,
|
||||
{ "HP", "6634B", SCPI_DIALECT_HP_66XXB, PPS_OTP,
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts),
|
||||
ARRAY_AND_SIZE(hp_6630b_devopts_cg),
|
||||
ARRAY_AND_SIZE(hp_6634b_ch),
|
||||
ARRAY_AND_SIZE(hp_663xx_cg),
|
||||
ARRAY_AND_SIZE(hp_6630b_cg),
|
||||
hp_6630b_cmd,
|
||||
.probe_channels = NULL,
|
||||
hp_6630b_init_acquisition,
|
||||
hp_6630b_update_status,
|
||||
},
|
||||
|
||||
/* Rigol DP700 series */
|
||||
{ "Rigol", "^DP711$", 0,
|
||||
{ "Rigol", "^DP711$", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(rigol_dp700_devopts),
|
||||
ARRAY_AND_SIZE(rigol_dp700_devopts_cg),
|
||||
ARRAY_AND_SIZE(rigol_dp711_ch),
|
||||
ARRAY_AND_SIZE(rigol_dp700_cg),
|
||||
rigol_dp700_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
{ "Rigol", "^DP712$", 0,
|
||||
{ "Rigol", "^DP712$", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(rigol_dp700_devopts),
|
||||
ARRAY_AND_SIZE(rigol_dp700_devopts_cg),
|
||||
ARRAY_AND_SIZE(rigol_dp712_ch),
|
||||
ARRAY_AND_SIZE(rigol_dp700_cg),
|
||||
rigol_dp700_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/* Rigol DP800 series */
|
||||
{ "Rigol", "^DP821A$", PPS_OTP,
|
||||
{ "Rigol", "^DP821A$", SCPI_DIALECT_UNKNOWN, PPS_OTP,
|
||||
ARRAY_AND_SIZE(rigol_dp800_devopts),
|
||||
ARRAY_AND_SIZE(rigol_dp800_devopts_cg),
|
||||
ARRAY_AND_SIZE(rigol_dp821a_ch),
|
||||
ARRAY_AND_SIZE(rigol_dp820_cg),
|
||||
rigol_dp800_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
{ "Rigol", "^DP831A$", PPS_OTP,
|
||||
{ "Rigol", "^DP831A$", SCPI_DIALECT_UNKNOWN, PPS_OTP,
|
||||
ARRAY_AND_SIZE(rigol_dp800_devopts),
|
||||
ARRAY_AND_SIZE(rigol_dp800_devopts_cg),
|
||||
ARRAY_AND_SIZE(rigol_dp831_ch),
|
||||
ARRAY_AND_SIZE(rigol_dp830_cg),
|
||||
rigol_dp800_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
{ "Rigol", "^(DP832|DP832A)$", PPS_OTP,
|
||||
{ "Rigol", "^(DP832|DP832A)$", SCPI_DIALECT_UNKNOWN, PPS_OTP,
|
||||
ARRAY_AND_SIZE(rigol_dp800_devopts),
|
||||
ARRAY_AND_SIZE(rigol_dp800_devopts_cg),
|
||||
ARRAY_AND_SIZE(rigol_dp832_ch),
|
||||
ARRAY_AND_SIZE(rigol_dp830_cg),
|
||||
rigol_dp800_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/* Philips/Fluke PM2800 series */
|
||||
{ "Philips", "^PM28[13][123]/[01234]{1,2}$", 0,
|
||||
{ "Philips", "^PM28[13][123]/[01234]{1,2}$", SCPI_DIALECT_PHILIPS, 0,
|
||||
ARRAY_AND_SIZE(philips_pm2800_devopts),
|
||||
ARRAY_AND_SIZE(philips_pm2800_devopts_cg),
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
philips_pm2800_cmd,
|
||||
philips_pm2800_probe_channels,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
|
||||
/* Rohde & Schwarz HMC8043 */
|
||||
{ "Rohde&Schwarz", "HMC8043", 0,
|
||||
{ "Rohde&Schwarz", "HMC8043", SCPI_DIALECT_UNKNOWN, 0,
|
||||
ARRAY_AND_SIZE(rs_hmc8043_devopts),
|
||||
ARRAY_AND_SIZE(rs_hmc8043_devopts_cg),
|
||||
ARRAY_AND_SIZE(rs_hmc8043_ch),
|
||||
ARRAY_AND_SIZE(rs_hmc8043_cg),
|
||||
rs_hmc8043_cmd,
|
||||
.probe_channels = NULL,
|
||||
.init_acquisition = NULL,
|
||||
.update_status = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -27,6 +28,7 @@
|
|||
SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
const struct scpi_pps *device;
|
||||
struct sr_datafeed_packet packet;
|
||||
struct sr_datafeed_analog analog;
|
||||
struct sr_analog_encoding encoding;
|
||||
|
@ -52,6 +54,9 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
|
|||
if (!(devc = sdi->priv))
|
||||
return TRUE;
|
||||
|
||||
if (!(device = devc->device))
|
||||
return TRUE;
|
||||
|
||||
pch = devc->cur_acquisition_channel->priv;
|
||||
|
||||
channel_group_cmd = 0;
|
||||
|
@ -61,6 +66,15 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
|
|||
channel_group_name = pch->hwname;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the current channel is the first in the array, perform the device
|
||||
* specific status update first.
|
||||
*/
|
||||
if (devc->cur_acquisition_channel == sr_next_enabled_channel(sdi, NULL) &&
|
||||
device->update_status) {
|
||||
device->update_status(sdi);
|
||||
}
|
||||
|
||||
if (pch->mq == SR_MQ_VOLTAGE) {
|
||||
gvtype = G_VARIANT_TYPE_DOUBLE;
|
||||
cmd = SCPI_CMD_GET_MEAS_VOLTAGE;
|
||||
|
@ -91,6 +105,7 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
|
|||
analog.meaning->channels = g_slist_append(NULL, devc->cur_acquisition_channel);
|
||||
analog.num_samples = 1;
|
||||
analog.meaning->mq = pch->mq;
|
||||
analog.meaning->mqflags = pch->mqflags;
|
||||
if (pch->mq == SR_MQ_VOLTAGE) {
|
||||
analog.meaning->unit = SR_UNIT_VOLT;
|
||||
analog.encoding->digits = ch_spec->voltage[4];
|
||||
|
@ -103,8 +118,11 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
|
|||
analog.meaning->unit = SR_UNIT_WATT;
|
||||
analog.encoding->digits = ch_spec->power[4];
|
||||
analog.spec->spec_digits = ch_spec->power[3];
|
||||
} else if (pch->mq == SR_MQ_FREQUENCY) {
|
||||
analog.meaning->unit = SR_UNIT_HERTZ;
|
||||
analog.encoding->digits = ch_spec->frequency[4];
|
||||
analog.spec->spec_digits = ch_spec->frequency[3];
|
||||
}
|
||||
analog.meaning->mqflags = SR_MQFLAG_DC;
|
||||
f = (float)g_variant_get_double(gvdata);
|
||||
g_variant_unref(gvdata);
|
||||
analog.data = &f;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2017 Frank Stettner <frank-stettner@gmx.net>
|
||||
* Copyright (C) 2017,2019 Frank Stettner <frank-stettner@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -53,6 +53,7 @@ enum pps_scpi_cmds {
|
|||
SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION,
|
||||
SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_ENABLE,
|
||||
SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_DISABLE,
|
||||
SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE,
|
||||
SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ENABLED,
|
||||
SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLE,
|
||||
SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_DISABLE,
|
||||
|
@ -67,6 +68,14 @@ enum pps_scpi_cmds {
|
|||
SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD,
|
||||
};
|
||||
|
||||
/* Defines the SCPI dialect */
|
||||
enum pps_scpi_dialect {
|
||||
SCPI_DIALECT_UNKNOWN = 1,
|
||||
SCPI_DIALECT_HP_COMP,
|
||||
SCPI_DIALECT_HP_66XXB,
|
||||
SCPI_DIALECT_PHILIPS,
|
||||
};
|
||||
|
||||
/*
|
||||
* These are bit values denoting features a device can have either globally,
|
||||
* in scpi_pps.features, or on a per-channel-group basis in
|
||||
|
@ -84,6 +93,7 @@ enum pps_features {
|
|||
struct scpi_pps {
|
||||
const char *vendor;
|
||||
const char *model;
|
||||
const enum pps_scpi_dialect dialect;
|
||||
uint64_t features;
|
||||
const uint32_t *devopts;
|
||||
unsigned int num_devopts;
|
||||
|
@ -97,6 +107,8 @@ struct scpi_pps {
|
|||
int (*probe_channels) (struct sr_dev_inst *sdi, struct sr_scpi_hw_info *hwinfo,
|
||||
struct channel_spec **channels, unsigned int *num_channels,
|
||||
struct channel_group_spec **channel_groups, unsigned int *num_channel_groups);
|
||||
int (*init_acquisition) (const struct sr_dev_inst *sdi);
|
||||
int (*update_status) (const struct sr_dev_inst *sdi);
|
||||
};
|
||||
|
||||
struct channel_spec {
|
||||
|
@ -114,10 +126,13 @@ struct channel_group_spec {
|
|||
const char *name;
|
||||
uint64_t channel_index_mask;
|
||||
uint64_t features;
|
||||
/* The mqflags will only be applied to voltage and current channels! */
|
||||
enum sr_mqflag mqflags;
|
||||
};
|
||||
|
||||
struct pps_channel {
|
||||
enum sr_mq mq;
|
||||
enum sr_mqflag mqflags;
|
||||
unsigned int hw_output_idx;
|
||||
const char *hwname;
|
||||
int digits;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue